From 176d5335fe66f379a339b0ab99cc7566e90ff1a9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:44 +0200 Subject: [PATCH 001/367] ALSA: hda - Add infrastructure for dynamic stream allocation Added the infrastructure for dynamic stream allocation on HD-audio. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 74 ++++++++++++++++++++--- sound/pci/hda/hda_codec.h | 5 +- sound/pci/hda/hda_intel.c | 121 +++++++++++--------------------------- 3 files changed, 105 insertions(+), 95 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6447754ae56e..19b4530e3baf 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2262,6 +2262,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, return 0; } +/* + * attach a new PCM stream + */ +static int __devinit +snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) +{ + struct hda_pcm_stream *info; + int stream, err; + + if (!pcm->name) + return -EINVAL; + for (stream = 0; stream < 2; stream++) { + info = &pcm->stream[stream]; + if (info->substreams) { + err = set_pcm_default_values(codec, info); + if (err < 0) + return err; + } + } + return codec->bus->ops.attach_pcm(codec, pcm); +} + /** * snd_hda_build_pcms - build PCM information * @bus: the BUS @@ -2290,10 +2312,24 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec, */ int __devinit snd_hda_build_pcms(struct hda_bus *bus) { + static const char *dev_name[HDA_PCM_NTYPES] = { + "Audio", "SPDIF", "HDMI", "Modem" + }; + /* starting device index for each PCM type */ + static int dev_idx[HDA_PCM_NTYPES] = { + [HDA_PCM_TYPE_AUDIO] = 0, + [HDA_PCM_TYPE_SPDIF] = 1, + [HDA_PCM_TYPE_HDMI] = 3, + [HDA_PCM_TYPE_MODEM] = 6 + }; + /* normal audio device indices; not linear to keep compatibility */ + static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; + int num_devs[HDA_PCM_NTYPES]; + memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &bus->codec_list, list) { - unsigned int pcm, s; + unsigned int pcm; int err; if (!codec->patch_ops.build_pcms) continue; @@ -2301,15 +2337,37 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) if (err < 0) return err; for (pcm = 0; pcm < codec->num_pcms; pcm++) { - for (s = 0; s < 2; s++) { - struct hda_pcm_stream *info; - info = &codec->pcm_info[pcm].stream[s]; - if (!info->substreams) + struct hda_pcm *cpcm = &codec->pcm_info[pcm]; + int type = cpcm->pcm_type; + switch (type) { + case HDA_PCM_TYPE_AUDIO: + if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { + snd_printk(KERN_WARNING + "Too many audio devices\n"); continue; - err = set_pcm_default_values(codec, info); - if (err < 0) - return err; + } + cpcm->device = audio_idx[num_devs[type]]; + break; + case HDA_PCM_TYPE_SPDIF: + case HDA_PCM_TYPE_HDMI: + case HDA_PCM_TYPE_MODEM: + if (num_devs[type]) { + snd_printk(KERN_WARNING + "%s already defined\n", + dev_name[type]); + continue; + } + cpcm->device = dev_idx[type]; + break; + default: + snd_printk(KERN_WARNING + "Invalid PCM type %d\n", type); + continue; } + num_devs[type]++; + err = snd_hda_attach_pcm(codec, cpcm); + if (err < 0) + return err; } } return 0; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 60468f562400..70e8fa09273d 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -542,6 +542,8 @@ struct hda_bus_ops { unsigned int (*get_response)(struct hda_codec *codec); /* free the private data */ void (*private_free)(struct hda_bus *); + /* attach a PCM stream */ + int (*attach_pcm)(struct hda_codec *codec, struct hda_pcm *pcm); #ifdef CONFIG_SND_HDA_POWER_SAVE /* notify power-up/down from codec to controller */ void (*pm_notify)(struct hda_codec *codec); @@ -680,7 +682,8 @@ struct hda_pcm { char *name; struct hda_pcm_stream stream[2]; unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */ - int device; /* assigned device number */ + int device; /* device number to assign */ + struct snd_pcm *pcm; /* assigned PCM instance */ }; /* codec information */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 9f316c1b2790..7b0abf08a583 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) return 0; } +static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm); /* * Codec initialization @@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; + bus_temp.ops.attach_pcm = azx_attach_pcm_stream; #ifdef CONFIG_SND_HDA_POWER_SAVE bus_temp.ops.pm_notify = azx_power_notify; #endif @@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = { static void azx_pcm_free(struct snd_pcm *pcm) { - kfree(pcm->private_data); + struct azx_pcm *apcm = pcm->private_data; + if (apcm) { + apcm->chip->pcm[pcm->device] = NULL; + kfree(apcm); + } } -static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, - struct hda_pcm *cpcm) +static int +azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm) { - int err; + struct azx *chip = codec->bus->private_data; struct snd_pcm *pcm; struct azx_pcm *apcm; + int pcm_dev = cpcm->device; + int s, err; - /* if no substreams are defined for both playback and capture, - * it's just a placeholder. ignore it. - */ - if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) - return 0; - - if (snd_BUG_ON(!cpcm->name)) + if (pcm_dev >= AZX_MAX_PCMS) { + snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n", + pcm_dev); return -EINVAL; - - err = snd_pcm_new(chip->card, cpcm->name, cpcm->device, - cpcm->stream[0].substreams, - cpcm->stream[1].substreams, + } + if (chip->pcm[pcm_dev]) { + snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev); + return -EBUSY; + } + err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, + cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, + cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams, &pcm); if (err < 0) return err; strcpy(pcm->name, cpcm->name); - apcm = kmalloc(sizeof(*apcm), GFP_KERNEL); + apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); if (apcm == NULL) return -ENOMEM; apcm->chip = chip; apcm->codec = codec; - apcm->hinfo[0] = &cpcm->stream[0]; - apcm->hinfo[1] = &cpcm->stream[1]; pcm->private_data = apcm; pcm->private_free = azx_pcm_free; - if (cpcm->stream[0].substreams) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); - if (cpcm->stream[1].substreams) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); + if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) + pcm->dev_class = SNDRV_PCM_CLASS_MODEM; + chip->pcm[pcm_dev] = pcm; + cpcm->pcm = pcm; + for (s = 0; s < 2; s++) { + apcm->hinfo[s] = &cpcm->stream[s]; + if (cpcm->stream[s].substreams) + snd_pcm_set_ops(pcm, s, &azx_pcm_ops); + } + /* buffer pre-allocation */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 1024 * 64, 32 * 1024 * 1024); - chip->pcm[cpcm->device] = pcm; - return 0; -} - -static int __devinit azx_pcm_create(struct azx *chip) -{ - static const char *dev_name[HDA_PCM_NTYPES] = { - "Audio", "SPDIF", "HDMI", "Modem" - }; - /* starting device index for each PCM type */ - static int dev_idx[HDA_PCM_NTYPES] = { - [HDA_PCM_TYPE_AUDIO] = 0, - [HDA_PCM_TYPE_SPDIF] = 1, - [HDA_PCM_TYPE_HDMI] = 3, - [HDA_PCM_TYPE_MODEM] = 6 - }; - /* normal audio device indices; not linear to keep compatibility */ - static int audio_idx[4] = { 0, 2, 4, 5 }; - struct hda_codec *codec; - int c, err; - int num_devs[HDA_PCM_NTYPES]; - - err = snd_hda_build_pcms(chip->bus); - if (err < 0) - return err; - - /* create audio PCMs */ - memset(num_devs, 0, sizeof(num_devs)); - list_for_each_entry(codec, &chip->bus->codec_list, list) { - for (c = 0; c < codec->num_pcms; c++) { - struct hda_pcm *cpcm = &codec->pcm_info[c]; - int type = cpcm->pcm_type; - switch (type) { - case HDA_PCM_TYPE_AUDIO: - if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { - snd_printk(KERN_WARNING - "Too many audio devices\n"); - continue; - } - cpcm->device = audio_idx[num_devs[type]]; - break; - case HDA_PCM_TYPE_SPDIF: - case HDA_PCM_TYPE_HDMI: - case HDA_PCM_TYPE_MODEM: - if (num_devs[type]) { - snd_printk(KERN_WARNING - "%s already defined\n", - dev_name[type]); - continue; - } - cpcm->device = dev_idx[type]; - break; - default: - snd_printk(KERN_WARNING - "Invalid PCM type %d\n", type); - continue; - } - num_devs[type]++; - err = create_codec_pcm(chip, codec, cpcm); - if (err < 0) - return err; - } - } return 0; } @@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci, } /* create PCM streams */ - err = azx_pcm_create(chip); + err = snd_hda_build_pcms(chip->bus); if (err < 0) { snd_card_free(card); return err; From b2e1859745b783922533d29e3b03af29378a23f0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:44 +0200 Subject: [PATCH 002/367] ALSA: hda - Add generic arrays Added helper functions to handle generic arrays. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 34 ++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_codec.h | 20 ++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 19b4530e3baf..e70303183c3c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3196,3 +3196,37 @@ int snd_hda_codecs_inuse(struct hda_bus *bus) } #endif #endif + +/* + * generic arrays + */ + +/* get a new element from the given array + * if it exceeds the pre-allocated array size, re-allocate the array + */ +void *snd_array_new(struct snd_array *array) +{ + if (array->used >= array->alloced) { + int num = array->alloced + array->alloc_align; + void *nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); + if (!nlist) + return NULL; + if (array->list) { + memcpy(nlist, array->list, + array->elem_size * array->alloced); + kfree(array->list); + } + array->list = nlist; + array->alloced = num; + } + return array->list + (array->used++ * array->elem_size); +} + +/* free the given array elements */ +void snd_array_free(struct snd_array *array) +{ + kfree(array->list); + array->used = 0; + array->alloced = 0; + array->list = NULL; +} diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 70e8fa09273d..b9b21766b730 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -519,6 +519,26 @@ enum { /* max. codec address */ #define HDA_MAX_CODEC_ADDRESS 0x0f +/* + * generic arrays + */ +struct snd_array { + unsigned int used; + unsigned int alloced; + unsigned int elem_size; + unsigned int alloc_align; + void *list; +}; + +void *snd_array_new(struct snd_array *array); +void snd_array_free(struct snd_array *array); +static inline void snd_array_init(struct snd_array *array, unsigned int size, + unsigned int align) +{ + array->elem_size = size; + array->alloc_align = align; +} + /* * Structures */ From 603c40199252f0c3b91fca02fd3283c4f8e55179 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:44 +0200 Subject: [PATCH 003/367] ALSA: hda - Use generic array helpers Use generic array helpers to simplify array handling in snd-hda-intel. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 38 ++++----------- sound/pci/hda/hda_codec.h | 5 +- sound/pci/hda/patch_analog.c | 56 +++++++++++----------- sound/pci/hda/patch_conexant.c | 11 ----- sound/pci/hda/patch_realtek.c | 86 ++++++++++++++++------------------ sound/pci/hda/patch_sigmatel.c | 55 ++++++++++------------ sound/pci/hda/patch_via.c | 71 ++++++++++++---------------- 7 files changed, 132 insertions(+), 190 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e70303183c3c..39a49d4a864a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -756,12 +756,12 @@ static void __devinit init_hda_cache(struct hda_cache_rec *cache, { memset(cache, 0, sizeof(*cache)); memset(cache->hash, 0xff, sizeof(cache->hash)); - cache->record_size = record_size; + snd_array_init(&cache->buf, record_size, 64); } static void free_hda_cache(struct hda_cache_rec *cache) { - kfree(cache->buffer); + snd_array_free(&cache->buf); } /* query the hash. allocate an entry if not found. */ @@ -770,38 +770,18 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, { u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 cur = cache->hash[idx]; + struct hda_cache_head *info_head = cache->buf.list; struct hda_cache_head *info; while (cur != 0xffff) { - info = (struct hda_cache_head *)(cache->buffer + - cur * cache->record_size); + info = &info_head[cur]; if (info->key == key) return info; cur = info->next; } /* add a new hash entry */ - if (cache->num_entries >= cache->size) { - /* reallocate the array */ - unsigned int new_size = cache->size + 64; - void *new_buffer; - new_buffer = kcalloc(new_size, cache->record_size, GFP_KERNEL); - if (!new_buffer) { - snd_printk(KERN_ERR "hda_codec: " - "can't malloc amp_info\n"); - return NULL; - } - if (cache->buffer) { - memcpy(new_buffer, cache->buffer, - cache->size * cache->record_size); - kfree(cache->buffer); - } - cache->size = new_size; - cache->buffer = new_buffer; - } - cur = cache->num_entries++; - info = (struct hda_cache_head *)(cache->buffer + - cur * cache->record_size); + info = snd_array_new(&cache->buf); info->key = key; info->val = 0; info->next = cache->hash[idx]; @@ -942,10 +922,10 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, /* resume the all amp commands from the cache */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { - struct hda_amp_info *buffer = codec->amp_cache.buffer; + struct hda_amp_info *buffer = codec->amp_cache.buf.list; int i; - for (i = 0; i < codec->amp_cache.size; i++, buffer++) { + for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) { u32 key = buffer->head.key; hda_nid_t nid; unsigned int idx, dir, ch; @@ -1779,10 +1759,10 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) { - struct hda_cache_head *buffer = codec->cmd_cache.buffer; + struct hda_cache_head *buffer = codec->cmd_cache.buf.list; int i; - for (i = 0; i < codec->cmd_cache.size; i++, buffer++) { + for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) { u32 key = buffer->key; if (!key) continue; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index b9b21766b730..77064b0cb821 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -657,10 +657,7 @@ struct hda_amp_info { struct hda_cache_rec { u16 hash[64]; /* hash table for index */ - unsigned int num_entries; /* number of assigned entries */ - unsigned int size; /* allocated size */ - unsigned int record_size; /* record size (including header) */ - void *buffer; /* hash table entries */ + struct snd_array buf; /* record entries */ }; /* PCM callbacks */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2b00c4afdf97..02643bce5634 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -67,8 +67,7 @@ struct ad198x_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; + struct snd_array kctls; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -154,6 +153,8 @@ static const char *ad_slave_sws[] = { NULL }; +static void ad198x_free_kctls(struct hda_codec *codec); + static int ad198x_build_controls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; @@ -202,6 +203,7 @@ static int ad198x_build_controls(struct hda_codec *codec) return err; } + ad198x_free_kctls(codec); /* no longer needed */ return 0; } @@ -375,16 +377,27 @@ static int ad198x_build_pcms(struct hda_codec *codec) 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); +} + static void ad198x_free(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; - unsigned int i; - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } + if (!spec) + return; + + ad198x_free_kctls(codec); kfree(codec->spec); } @@ -2452,9 +2465,6 @@ static struct hda_amp_list ad1988_loopbacks[] = { * Automatic parse of I/O pins from the BIOS configuration */ -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - enum { AD_CTL_WIDGET_VOL, AD_CTL_WIDGET_MUTE, @@ -2472,27 +2482,15 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ - if (! knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; + 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; knew->private_value = val; - spec->num_kctl_used++; return 0; } @@ -2846,8 +2844,8 @@ static int ad1988_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = AD1988_SPDIF_IN; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 7c1eb23f0cec..076010708152 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -86,8 +86,6 @@ struct conexant_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -344,15 +342,6 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { - struct conexant_spec *spec = codec->spec; - unsigned int i; - - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - kfree(codec->spec); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0b6e682c46d0..3e21a7198656 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -284,8 +284,7 @@ struct alc_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; + struct snd_array kctls; struct hda_input_mux private_imux; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -1590,6 +1589,9 @@ static const char *alc_slave_sws[] = { /* * build control elements */ + +static void alc_free_kctls(struct hda_codec *codec); + static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -1636,6 +1638,7 @@ static int alc_build_controls(struct hda_codec *codec) return err; } + alc_free_kctls(codec); /* no longer needed */ return 0; } @@ -2726,19 +2729,27 @@ static int alc_build_pcms(struct hda_codec *codec) return 0; } +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(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int i; if (!spec) return; - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } + alc_free_kctls(codec); kfree(spec); codec->spec = NULL; /* to be sure */ } @@ -3423,9 +3434,6 @@ static struct alc_config_preset alc880_presets[] = { * Automatic parse of I/O pins from the BIOS configuration */ -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - enum { ALC_CTL_WIDGET_VOL, ALC_CTL_WIDGET_MUTE, @@ -3443,29 +3451,15 @@ static int add_control(struct alc_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - /* array + terminator */ - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); - if (!knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, - sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return -ENOMEM; *knew = alc880_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); if (!knew->name) return -ENOMEM; knew->private_value = val; - spec->num_kctl_used++; return 0; } @@ -3789,8 +3783,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = ALC880_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; @@ -5177,7 +5171,7 @@ static int alc260_parse_auto_config(struct hda_codec *codec) err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg); if (err < 0) return err; - if (!spec->kctl_alloc) + if (!spec->kctls.list) return 0; /* can't find valid BIOS pin config */ err = alc260_auto_create_analog_input_ctls(spec, &spec->autocfg); if (err < 0) @@ -5187,8 +5181,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; @@ -10256,8 +10250,8 @@ static int alc262_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = ALC262_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; spec->num_mux_defs = 1; @@ -11387,8 +11381,8 @@ static int alc268_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; if (spec->autocfg.speaker_pins[0] != 0x1d) spec->mixers[spec->num_mixers++] = alc268_beep_mixer; @@ -12159,8 +12153,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; /* create a beep mixer control if the pin 0x1d isn't assigned */ for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++) @@ -13257,8 +13251,8 @@ static int alc861_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; @@ -14368,8 +14362,8 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_init_verbs++] = alc861vd_volume_init_verbs; @@ -16194,8 +16188,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c59065513118..3db39adad79a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -35,7 +35,6 @@ #include "hda_patch.h" #include "hda_beep.h" -#define NUM_CONTROL_ALLOC 32 #define STAC_PWR_EVENT 0x20 #define STAC_HP_EVENT 0x30 #define STAC_VREF_EVENT 0x40 @@ -218,8 +217,7 @@ struct sigmatel_spec { /* dynamic controls and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; + struct snd_array kctls; struct hda_input_mux private_dimux; struct hda_input_mux private_imux; struct hda_input_mux private_smux; @@ -1233,6 +1231,8 @@ static const char *slave_sws[] = { NULL }; +static void stac92xx_free_kctls(struct hda_codec *codec); + static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -1305,6 +1305,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) return err; } + stac92xx_free_kctls(codec); /* no longer needed */ return 0; } @@ -2592,28 +2593,16 @@ static int stac92xx_add_control_idx(struct sigmatel_spec *spec, int type, { struct snd_kcontrol_new *knew; - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ - if (! knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return -ENOMEM; *knew = stac92xx_control_templates[type]; knew->index = idx; knew->name = kstrdup(name, GFP_KERNEL); if (! knew->name) return -ENOMEM; knew->private_value = val; - spec->num_kctl_used++; return 0; } @@ -3434,8 +3423,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if (dig_in && spec->autocfg.dig_in_pin) spec->dig_in_nid = dig_in; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux; spec->dinput_mux = &spec->private_dimux; @@ -3536,8 +3525,8 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = 0x04; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux; spec->dinput_mux = &spec->private_dimux; @@ -3698,20 +3687,26 @@ static int stac92xx_init(struct hda_codec *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); + } + snd_array_free(&spec->kctls); +} + static void stac92xx_free(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int i; if (! spec) return; - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - if (spec->bios_pin_configs) kfree(spec->bios_pin_configs); diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 63e4871e5d8f..760e14ae3bff 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -53,9 +53,6 @@ #define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_MASK (0x0f<<19) -#define NUM_CONTROL_ALLOC 32 -#define NUM_VERB_ALLOC 32 - /* Pin Widget NID */ #define VT1708_HP_NID 0x13 #define VT1708_DIGOUT_NID 0x14 @@ -227,8 +224,7 @@ struct via_spec { /* dynamic controls, init_verbs and input_mux */ struct auto_pin_cfg autocfg; - unsigned int num_kctl_alloc, num_kctl_used; - struct snd_kcontrol_new *kctl_alloc; + struct snd_array kctls; struct hda_input_mux private_imux[2]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; @@ -272,33 +268,31 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, { struct snd_kcontrol_new *knew; - if (spec->num_kctl_used >= spec->num_kctl_alloc) { - int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; - - /* array + terminator */ - knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); - if (!knew) - return -ENOMEM; - if (spec->kctl_alloc) { - memcpy(knew, spec->kctl_alloc, - sizeof(*knew) * spec->num_kctl_alloc); - kfree(spec->kctl_alloc); - } - spec->kctl_alloc = knew; - spec->num_kctl_alloc = num; - } - - knew = &spec->kctl_alloc[spec->num_kctl_used]; + snd_array_init(&spec->kctls, sizeof(*knew), 32); + knew = snd_array_new(&spec->kctls); + if (!knew) + return -ENOMEM; *knew = vt1708_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) return -ENOMEM; knew->private_value = val; - spec->num_kctl_used++; return 0; } +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, hda_nid_t pin, const char *ctlname, int idx, int mix_nid) @@ -896,6 +890,7 @@ static int via_build_controls(struct hda_codec *codec) if (err < 0) return err; } + via_free_kctls(codec); /* no longer needed */ return 0; } @@ -941,17 +936,11 @@ static int via_build_pcms(struct hda_codec *codec) static void via_free(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - unsigned int i; if (!spec) return; - if (spec->kctl_alloc) { - for (i = 0; i < spec->num_kctl_used; i++) - kfree(spec->kctl_alloc[i].name); - kfree(spec->kctl_alloc); - } - + via_free_kctls(codec); kfree(codec->spec); } @@ -1373,8 +1362,8 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1708_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->init_verbs[spec->num_iverbs++] = vt1708_volume_init_verbs; @@ -1846,8 +1835,8 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1709_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux[0]; @@ -2390,8 +2379,8 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_in_pin) spec->dig_in_nid = VT1708B_DIGIN_NID; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux[0]; @@ -2855,8 +2844,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) spec->extra_dig_out_nid = 0x15; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux[0]; @@ -3174,8 +3163,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) spec->extra_dig_out_nid = 0x1B; - if (spec->kctl_alloc) - spec->mixers[spec->num_mixers++] = spec->kctl_alloc; + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux[0]; From f44ac8378d3d84b912b34f08afaff64182ee1b41 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:45 +0200 Subject: [PATCH 004/367] ALSA: hda - Allocate name string of each codec Allocate dynamically the name string of each codec instead of pointing to a static string. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 37 +++++++++++++++++++++++++------------ sound/pci/hda/hda_codec.h | 2 ++ sound/pci/hda/hda_proc.c | 5 ++--- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 39a49d4a864a..53e36495fae5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -446,7 +446,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ - (codec->bus->modelname && !strcmp(codec->bus->modelname, "generic")) + (codec->modelname && !strcmp(codec->modelname, "generic")) #else #define is_generic_config(codec) 0 #endif @@ -481,15 +481,14 @@ find_codec_preset(struct hda_codec *codec) } /* - * snd_hda_get_codec_name - store the codec name + * get_codec_name - store the codec name */ -void snd_hda_get_codec_name(struct hda_codec *codec, - char *name, int namelen) +static int get_codec_name(struct hda_codec *codec) { const struct hda_vendor_id *c; const char *vendor = NULL; u16 vendor_id = codec->vendor_id >> 16; - char tmp[16]; + char tmp[16], name[32]; for (c = hda_vendor_ids; c->id; c++) { if (c->id == vendor_id) { @@ -502,10 +501,15 @@ void snd_hda_get_codec_name(struct hda_codec *codec, vendor = tmp; } if (codec->preset && codec->preset->name) - snprintf(name, namelen, "%s %s", vendor, codec->preset->name); + snprintf(name, sizeof(name), "%s %s", vendor, + codec->preset->name); else - snprintf(name, namelen, "%s ID %x", vendor, + snprintf(name, sizeof(name), "%s ID %x", vendor, codec->vendor_id & 0xffff); + codec->name = kstrdup(name, GFP_KERNEL); + if (!codec->name) + return -ENOMEM; + return 0; } /* @@ -575,6 +579,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) codec->patch_ops.free(codec); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); + kfree(codec->name); + kfree(codec->modelname); kfree(codec->wcaps); kfree(codec); } @@ -661,12 +667,19 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_SUBSYSTEM_ID, 0); } + if (bus->modelname) + codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); codec->preset = find_codec_preset(codec); + if (!codec->name) { + err = get_codec_name(codec); + if (err < 0) + return err; + } /* audio codec should override the mixer name */ - if (codec->afg || !*bus->card->mixername) - snd_hda_get_codec_name(codec, bus->card->mixername, - sizeof(bus->card->mixername)); + if (codec->afg || !*codec->bus->card->mixername) + strlcpy(codec->bus->card->mixername, codec->name, + sizeof(codec->bus->card->mixername)); if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); @@ -2370,11 +2383,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, const char **models, const struct snd_pci_quirk *tbl) { - if (codec->bus->modelname && models) { + if (codec->modelname && models) { int i; for (i = 0; i < num_configs; i++) { if (models[i] && - !strcmp(codec->bus->modelname, models[i])) { + !strcmp(codec->modelname, models[i])) { snd_printd(KERN_INFO "hda_codec: model '%s' is " "selected\n", models[i]); return i; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 77064b0cb821..53f3b08b24cd 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -719,6 +719,8 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; + const char *name; /* codec name */ + const char *modelname; /* model name for preset */ /* set by patch */ struct hda_codec_ops patch_ops; diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 743d77922bce..64ab19f14f79 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -511,12 +511,11 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct hda_codec *codec = entry->private_data; - char buf[32]; hda_nid_t nid; int i, nodes; - snd_hda_get_codec_name(codec, buf, sizeof(buf)); - snd_iprintf(buffer, "Codec: %s\n", buf); + snd_iprintf(buffer, "Codec: %s\n", + codec->name ? codec->name : "Not Set"); snd_iprintf(buffer, "Address: %d\n", codec->addr); snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); From d13bd412dce23eed8bc35a2499d7d88cb39a1581 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:45 +0200 Subject: [PATCH 005/367] ALSA: hda - Manage kcontrol lists Manage all kcontrol elements created in the hda-intel driver. This makes it possible to remove and reconfigure the controls of each codec. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 40 +++++++++++++++++++++++++++++----- sound/pci/hda/hda_codec.h | 2 ++ sound/pci/hda/hda_generic.c | 20 ++++++++++------- sound/pci/hda/hda_local.h | 3 +++ sound/pci/hda/patch_sigmatel.c | 2 +- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 53e36495fae5..bc3ed249b0fc 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -574,6 +574,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) flush_scheduled_work(); #endif list_del(&codec->list); + snd_array_free(&codec->mixers); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -622,6 +623,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, mutex_init(&codec->spdif_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); + snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); #ifdef CONFIG_SND_HDA_POWER_SAVE INIT_DELAYED_WORK(&codec->power_work, hda_power_work); @@ -1090,6 +1092,32 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, return _snd_hda_find_mixer_ctl(codec, name, 0); } +/* Add a control element and assign to the codec */ +int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) +{ + int err; + struct snd_kcontrol **knewp; + + err = snd_ctl_add(codec->bus->card, kctl); + if (err < 0) + return err; + knewp = snd_array_new(&codec->mixers); + if (!knewp) + return -ENOMEM; + *knewp = kctl; + return 0; +} + +/* Clear all controls assigned to the given codec */ +void snd_hda_ctls_clear(struct hda_codec *codec) +{ + int i; + struct snd_kcontrol **kctls = codec->mixers.list; + for (i = 0; i < codec->mixers.used; i++) + snd_ctl_remove(codec->bus->card, kctls[i]); + snd_array_free(&codec->mixers); +} + /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves) @@ -1107,7 +1135,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) return -ENOMEM; - err = snd_ctl_add(codec->bus->card, kctl); + err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; @@ -1571,7 +1599,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) kctl = snd_ctl_new1(dig_mix, codec); kctl->id.index = idx; kctl->private_value = nid; - err = snd_ctl_add(codec->bus->card, kctl); + err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } @@ -1615,7 +1643,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, if (!mout->dig_out_nid) return 0; /* ATTENTION: here mout is passed as private_data, instead of codec */ - return snd_ctl_add(codec->bus->card, + return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); } @@ -1717,7 +1745,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); kctl->private_value = nid; - err = snd_ctl_add(codec->bus->card, kctl); + err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } @@ -2440,7 +2468,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) kctl = snd_ctl_new1(knew, codec); if (!kctl) return -ENOMEM; - err = snd_ctl_add(codec->bus->card, kctl); + err = snd_hda_ctl_add(codec, kctl); if (err < 0) { if (!codec->addr) return err; @@ -2448,7 +2476,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) if (!kctl) return -ENOMEM; kctl->id.device = codec->addr; - err = snd_ctl_add(codec->bus->card, kctl); + err = snd_hda_ctl_add(codec, kctl); if (err < 0) return err; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 53f3b08b24cd..8813ec10ca13 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -740,6 +740,8 @@ struct hda_codec { hda_nid_t start_nid; u32 *wcaps; + struct snd_array mixers; /* list of assigned mixer elements */ + struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 0ca30894f7c6..98ff010d5b95 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -723,7 +723,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, 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); - if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) + err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); + if (err < 0) return err; created = 1; } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && @@ -732,7 +733,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, if (is_loopback) add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) + err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); + if (err < 0) return err; created = 1; } @@ -745,14 +747,16 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, (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); - if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) + err = snd_hda_ctl_add(codec, 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_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); - if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&knew, codec))) < 0) + err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); + if (err < 0) return err; created = 1; } @@ -849,8 +853,8 @@ static int build_input_controls(struct hda_codec *codec) } /* create input MUX if multiple sources are available */ - if ((err = snd_ctl_add(codec->bus->card, - snd_ctl_new1(&cap_sel, codec))) < 0) + err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec)); + if (err < 0) return err; /* no volume control? */ @@ -867,8 +871,8 @@ static int build_input_controls(struct hda_codec *codec) HDA_CODEC_VOLUME(name, adc_node->nid, spec->input_mux.items[i].index, HDA_INPUT); - if ((err = snd_ctl_add(codec->bus->card, - snd_ctl_new1(&knew, codec))) < 0) + err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); + if (err < 0) return err; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7957fefda730..48faaf8cd21b 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -393,6 +393,9 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); +int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl); +void snd_hda_ctls_clear(struct hda_codec *codec); + /* * hwdep interface */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3db39adad79a..9c67af8e2089 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1250,7 +1250,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) } if (spec->num_dmuxes > 0) { stac_dmux_mixer.count = spec->num_dmuxes; - err = snd_ctl_add(codec->bus->card, + err = snd_hda_ctl_add(codec, snd_ctl_new1(&stac_dmux_mixer, codec)); if (err < 0) return err; From 6c1f45ea89b59ad2cdbfa6779e23d77b274da0a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:45 +0200 Subject: [PATCH 006/367] ALSA: hda - Add codec reconfiguration feature Added the reconfiguration feature of any individual codec. Via the reconfiguration, the old resources are released and the patch is called again to recreate the PCM and mixers in addition to the re-initialization. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 147 ++++++++++++++++++++++++++------------ sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_local.h | 2 + 3 files changed, 103 insertions(+), 47 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index bc3ed249b0fc..5b54ac07fcbd 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -344,7 +344,7 @@ static void process_unsol_events(struct work_struct *work) /* * initialize unsolicited queue */ -static int __devinit init_unsol_queue(struct hda_bus *bus) +static int init_unsol_queue(struct hda_bus *bus) { struct hda_bus_unsolicited *unsol; @@ -454,7 +454,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, /* * find a matching codec preset */ -static const struct hda_codec_preset __devinit * +static const struct hda_codec_preset * find_codec_preset(struct hda_codec *codec) { const struct hda_codec_preset **tbl, *preset; @@ -624,6 +624,13 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); + if (codec->bus->modelname) { + codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); + if (!codec->modelname) { + snd_hda_codec_free(codec); + return -ENODEV; + } + } #ifdef CONFIG_SND_HDA_POWER_SAVE INIT_DELAYED_WORK(&codec->power_work, hda_power_work); @@ -672,6 +679,30 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, if (bus->modelname) codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); + err = snd_hda_codec_configure(codec); + if (err < 0) { + snd_hda_codec_free(codec); + return err; + } + snd_hda_codec_proc_new(codec); + +#ifdef CONFIG_SND_HDA_HWDEP + snd_hda_create_hwdep(codec); +#endif + + sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, + codec->subsystem_id, codec->revision_id); + snd_component_add(codec->bus->card, component); + + if (codecp) + *codecp = codec; + return 0; +} + +int snd_hda_codec_configure(struct hda_codec *codec) +{ + int err; + codec->preset = find_codec_preset(codec); if (!codec->name) { err = get_codec_name(codec); @@ -698,25 +729,9 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, printk(KERN_ERR "hda-codec: No codec parser is available\n"); patched: - if (err < 0) { - snd_hda_codec_free(codec); - return err; - } - - if (codec->patch_ops.unsol_event) - init_unsol_queue(bus); - - snd_hda_codec_proc_new(codec); -#ifdef CONFIG_SND_HDA_HWDEP - snd_hda_create_hwdep(codec); -#endif - - sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); - snd_component_add(codec->bus->card, component); - - if (codecp) - *codecp = codec; - return 0; + if (!err && codec->patch_ops.unsol_event) + err = init_unsol_queue(codec->bus); + return err; } /** @@ -1118,6 +1133,31 @@ void snd_hda_ctls_clear(struct hda_codec *codec) snd_array_free(&codec->mixers); } +void snd_hda_codec_reset(struct hda_codec *codec) +{ + int i; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + cancel_delayed_work(&codec->power_work); + flush_scheduled_work(); +#endif + snd_hda_ctls_clear(codec); + /* relase PCMs */ + for (i = 0; i < codec->num_pcms; i++) { + if (codec->pcm_info[i].pcm) + snd_device_free(codec->bus->card, + codec->pcm_info[i].pcm); + } + if (codec->patch_ops.free) + codec->patch_ops.free(codec); + codec->spec = NULL; + free_hda_cache(&codec->amp_cache); + free_hda_cache(&codec->cmd_cache); + codec->num_pcms = 0; + codec->pcm_info = NULL; + codec->preset = NULL; +} + /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves) @@ -1939,23 +1979,30 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - int err = 0; - /* fake as if already powered-on */ - hda_keep_power_on(codec); - /* then fire up */ - hda_set_power_state(codec, - codec->afg ? codec->afg : codec->mfg, - AC_PWRST_D0); - /* continue to initialize... */ - if (codec->patch_ops.init) - err = codec->patch_ops.init(codec); - if (!err && codec->patch_ops.build_controls) - err = codec->patch_ops.build_controls(codec); - snd_hda_power_down(codec); + int err = snd_hda_codec_build_controls(codec); if (err < 0) return err; } + return 0; +} +int snd_hda_codec_build_controls(struct hda_codec *codec) +{ + int err = 0; + /* fake as if already powered-on */ + hda_keep_power_on(codec); + /* then fire up */ + hda_set_power_state(codec, + codec->afg ? codec->afg : codec->mfg, + AC_PWRST_D0); + /* continue to initialize... */ + if (codec->patch_ops.init) + err = codec->patch_ops.init(codec); + if (!err && codec->patch_ops.build_controls) + err = codec->patch_ops.build_controls(codec); + snd_hda_power_down(codec); + if (err < 0) + return err; return 0; } @@ -2256,8 +2303,8 @@ static int hda_pcm_default_cleanup(struct hda_pcm_stream *hinfo, return 0; } -static int __devinit set_pcm_default_values(struct hda_codec *codec, - struct hda_pcm_stream *info) +static int set_pcm_default_values(struct hda_codec *codec, + struct hda_pcm_stream *info) { /* query support PCM information from the given NID */ if (info->nid && (!info->rates || !info->formats)) { @@ -2331,7 +2378,7 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) * * This function returns 0 if successfull, or a negative error code. */ -int __devinit snd_hda_build_pcms(struct hda_bus *bus) +int snd_hda_build_pcms(struct hda_bus *bus) { static const char *dev_name[HDA_PCM_NTYPES] = { "Audio", "SPDIF", "HDMI", "Modem" @@ -2352,14 +2399,17 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { unsigned int pcm; int err; - if (!codec->patch_ops.build_pcms) - continue; - err = codec->patch_ops.build_pcms(codec); - if (err < 0) - return err; + if (!codec->num_pcms) { + if (!codec->patch_ops.build_pcms) + continue; + err = codec->patch_ops.build_pcms(codec); + if (err < 0) + return err; + } for (pcm = 0; pcm < codec->num_pcms; pcm++) { struct hda_pcm *cpcm = &codec->pcm_info[pcm]; int type = cpcm->pcm_type; + int dev; switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { @@ -2367,7 +2417,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) "Too many audio devices\n"); continue; } - cpcm->device = audio_idx[num_devs[type]]; + dev = audio_idx[num_devs[type]]; break; case HDA_PCM_TYPE_SPDIF: case HDA_PCM_TYPE_HDMI: @@ -2378,7 +2428,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) dev_name[type]); continue; } - cpcm->device = dev_idx[type]; + dev = dev_idx[type]; break; default: snd_printk(KERN_WARNING @@ -2386,9 +2436,12 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) continue; } num_devs[type]++; - err = snd_hda_attach_pcm(codec, cpcm); - if (err < 0) - return err; + if (!cpcm->pcm) { + cpcm->device = dev; + err = snd_hda_attach_pcm(codec, cpcm); + if (err < 0) + return err; + } } } return 0; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 8813ec10ca13..ce9f69bde328 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -823,6 +823,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec); * Mixer */ int snd_hda_build_controls(struct hda_bus *bus); +int snd_hda_codec_build_controls(struct hda_codec *codec); /* * PCM diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 48faaf8cd21b..d8283f1ab21a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -96,6 +96,8 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name); int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves); +void snd_hda_codec_reset(struct hda_codec *codec); +int snd_hda_codec_configure(struct hda_codec *codec); /* amp value bits */ #define HDA_AMP_MUTE 0x80 From d7ffba19ce4c1b153d502a89d829400bf76d6c11 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:46 +0200 Subject: [PATCH 007/367] ALSA: hda - Add sysfs entries to hwdep devices Added the sysfs entries to hwdep devices so that the new features like reconfiguration can be done via sysfs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 17 ++++- sound/pci/hda/hda_hwdep.c | 157 ++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_local.h | 5 ++ 3 files changed, 177 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5b54ac07fcbd..0741eda78a5e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -393,6 +393,20 @@ static int snd_hda_bus_dev_free(struct snd_device *device) return snd_hda_bus_free(bus); } +#ifdef CONFIG_SND_HDA_HWDEP +static int snd_hda_bus_dev_register(struct snd_device *device) +{ + struct hda_bus *bus = device->device_data; + struct hda_codec *codec; + list_for_each_entry(codec, &bus->codec_list, list) { + snd_hda_hwdep_add_sysfs(codec); + } + return 0; +} +#else +#define snd_hda_bus_dev_register NULL +#endif + /** * snd_hda_bus_new - create a HDA bus * @card: the card entry @@ -408,6 +422,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, struct hda_bus *bus; int err; static struct snd_device_ops dev_ops = { + .dev_register = snd_hda_bus_dev_register, .dev_free = snd_hda_bus_dev_free, }; @@ -686,9 +701,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, } snd_hda_codec_proc_new(codec); -#ifdef CONFIG_SND_HDA_HWDEP snd_hda_create_hwdep(codec); -#endif sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 6e18a422d993..214772c8b556 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -27,6 +27,7 @@ #include "hda_codec.h" #include "hda_local.h" #include +#include /* * write/read an out-of-bound verb @@ -119,3 +120,159 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) return 0; } + +/* + * sysfs interface + */ + +static int clear_codec(struct hda_codec *codec) +{ + snd_hda_codec_reset(codec); + return 0; +} + +static int reconfig_codec(struct hda_codec *codec) +{ + int err; + + snd_printk(KERN_INFO "hda-codec: reconfiguring\n"); + snd_hda_codec_reset(codec); + err = snd_hda_codec_configure(codec); + if (err < 0) + return err; + /* rebuild PCMs */ + err = snd_hda_build_pcms(codec->bus); + if (err < 0) + return err; + /* rebuild mixers */ + err = snd_hda_codec_build_controls(codec); + if (err < 0) + return err; + return 0; +} + +/* + * allocate a string at most len chars, and remove the trailing EOL + */ +static char *kstrndup_noeol(const char *src, size_t len) +{ + char *s = kstrndup(src, len, GFP_KERNEL); + char *p; + if (!s) + return NULL; + p = strchr(s, '\n'); + if (p) + *p = 0; + return s; +} + +#define CODEC_INFO_SHOW(type) \ +static ssize_t type##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + return sprintf(buf, "0x%x\n", codec->type); \ +} + +#define CODEC_INFO_STR_SHOW(type) \ +static ssize_t type##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + return sprintf(buf, "%s\n", \ + codec->type ? codec->type : ""); \ +} + +CODEC_INFO_SHOW(vendor_id); +CODEC_INFO_SHOW(subsystem_id); +CODEC_INFO_SHOW(revision_id); +CODEC_INFO_SHOW(afg); +CODEC_INFO_SHOW(mfg); +CODEC_INFO_STR_SHOW(name); +CODEC_INFO_STR_SHOW(modelname); + +#define CODEC_INFO_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + char *after; \ + codec->type = simple_strtoul(buf, &after, 0); \ + return count; \ +} + +#define CODEC_INFO_STR_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + char *s = kstrndup_noeol(buf, 64); \ + if (!s) \ + return -ENOMEM; \ + kfree(codec->type); \ + codec->type = s; \ + return count; \ +} + +CODEC_INFO_STORE(vendor_id); +CODEC_INFO_STORE(subsystem_id); +CODEC_INFO_STORE(revision_id); +CODEC_INFO_STR_STORE(name); +CODEC_INFO_STR_STORE(modelname); + +#define CODEC_ACTION_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ + struct hda_codec *codec = hwdep->private_data; \ + int err = 0; \ + if (*buf) \ + err = type##_codec(codec); \ + return err < 0 ? err : count; \ +} + +CODEC_ACTION_STORE(reconfig); +CODEC_ACTION_STORE(clear); + +#define CODEC_ATTR_RW(type) \ + __ATTR(type, 0644, type##_show, type##_store) +#define CODEC_ATTR_RO(type) \ + __ATTR_RO(type) +#define CODEC_ATTR_WO(type) \ + __ATTR(type, 0200, NULL, type##_store) + +static struct device_attribute codec_attrs[] = { + CODEC_ATTR_RW(vendor_id), + CODEC_ATTR_RW(subsystem_id), + CODEC_ATTR_RW(revision_id), + CODEC_ATTR_RO(afg), + CODEC_ATTR_RO(mfg), + CODEC_ATTR_RW(name), + CODEC_ATTR_RW(modelname), + CODEC_ATTR_WO(reconfig), + CODEC_ATTR_WO(clear), +}; + +/* + * create sysfs files on hwdep directory + */ +int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) +{ + struct snd_hwdep *hwdep = codec->hwdep; + int i; + + for (i = 0; i < ARRAY_SIZE(codec_attrs); i++) + snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, + hwdep->device, &codec_attrs[i]); + return 0; +} diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index d8283f1ab21a..4a08c31b498a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -401,7 +401,12 @@ void snd_hda_ctls_clear(struct hda_codec *codec); /* * hwdep interface */ +#ifdef CONFIG_SND_HDA_HWDEP int snd_hda_create_hwdep(struct hda_codec *codec); +int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); +#else +static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } +#endif /* * power-management From 11aeff082ad9bd00e8475bf1630c3264344d3764 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:46 +0200 Subject: [PATCH 008/367] ALSA: hda - Add init_verbs entries This patch enables the additional init verbs for each codec. The verbs can be entered via hwdep sysfs file. These verbs are executed at reconfiguring the codec for non-standard setups like overriding the pin-defcfg. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 13 +++++++++++++ sound/pci/hda/hda_codec.h | 3 +++ sound/pci/hda/hda_hwdep.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0741eda78a5e..9a8adc600a57 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1941,6 +1941,17 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, } } +#ifdef CONFIG_SND_HDA_HWDEP +/* execute additional init verbs */ +static void hda_exec_init_verbs(struct hda_codec *codec) +{ + if (codec->init_verbs.list) + snd_hda_sequence_write(codec, codec->init_verbs.list); +} +#else +static inline void hda_exec_init_verbs(struct hda_codec *codec) {} +#endif + #ifdef SND_HDA_NEEDS_RESUME /* * call suspend and power-down; used both from PM and power-save @@ -1967,6 +1978,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); + hda_exec_init_verbs(codec); if (codec->patch_ops.resume) codec->patch_ops.resume(codec); else { @@ -2008,6 +2020,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); + hda_exec_init_verbs(codec); /* continue to initialize... */ if (codec->patch_ops.init) err = codec->patch_ops.init(codec); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ce9f69bde328..38a9bb6bafb0 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -751,7 +751,10 @@ struct hda_codec { unsigned int spdif_in_enable; /* SPDIF input enable? */ hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ +#ifdef CONFIG_SND_HDA_HWDEP struct snd_hwdep *hwdep; /* assigned hwdep device */ + struct snd_array init_verbs; /* additional init verbs */ +#endif /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 214772c8b556..f3400d75eba4 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -96,6 +96,17 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) return 0; } +static void clear_hwdep_elements(struct hda_codec *codec) +{ + /* clear init verbs */ + snd_array_free(&codec->init_verbs); +} + +static void hwdep_free(struct snd_hwdep *hwdep) +{ + clear_hwdep_elements(hwdep->private_data); +} + int __devinit snd_hda_create_hwdep(struct hda_codec *codec) { char hwname[16]; @@ -110,6 +121,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) sprintf(hwdep->name, "HDA Codec %d", codec->addr); hwdep->iface = SNDRV_HWDEP_IFACE_HDA; hwdep->private_data = codec; + hwdep->private_free = hwdep_free; hwdep->exclusive = 1; hwdep->ops.open = hda_hwdep_open; @@ -118,6 +130,8 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; #endif + snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); + return 0; } @@ -128,6 +142,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) static int clear_codec(struct hda_codec *codec) { snd_hda_codec_reset(codec); + clear_hwdep_elements(codec); return 0; } @@ -244,6 +259,27 @@ static ssize_t type##_store(struct device *dev, \ CODEC_ACTION_STORE(reconfig); CODEC_ACTION_STORE(clear); +static ssize_t init_verbs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + char *p; + struct hda_verb verb, *v; + + verb.nid = simple_strtoul(buf, &p, 0); + verb.verb = simple_strtoul(p, &p, 0); + verb.param = simple_strtoul(p, &p, 0); + if (!verb.nid || !verb.verb || !verb.param) + return -EINVAL; + v = snd_array_new(&codec->init_verbs); + if (!v) + return -ENOMEM; + *v = verb; + return count; +} + #define CODEC_ATTR_RW(type) \ __ATTR(type, 0644, type##_show, type##_store) #define CODEC_ATTR_RO(type) \ @@ -259,6 +295,7 @@ static struct device_attribute codec_attrs[] = { CODEC_ATTR_RO(mfg), CODEC_ATTR_RW(name), CODEC_ATTR_RW(modelname), + CODEC_ATTR_WO(init_verbs), CODEC_ATTR_WO(reconfig), CODEC_ATTR_WO(clear), }; From 1e1be4329f2aec6a8ec63737a69258fedf34c55d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Jul 2008 15:01:46 +0200 Subject: [PATCH 009/367] ALSA: hda - Add hints for reconfig This patch adds the "hints" for reconfiguring codecs. The hints are simply string arrays and can be freely used/parsed by the codec patch. The hints can be input via hwdep sysfs files. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_hwdep.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 38a9bb6bafb0..a77ba223af40 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -754,6 +754,7 @@ struct hda_codec { #ifdef CONFIG_SND_HDA_HWDEP struct snd_hwdep *hwdep; /* assigned hwdep device */ struct snd_array init_verbs; /* additional init verbs */ + struct snd_array hints; /* additional hints */ #endif /* misc flags */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index f3400d75eba4..653da1d3e4df 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "hda_codec.h" #include "hda_local.h" @@ -98,8 +99,16 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) static void clear_hwdep_elements(struct hda_codec *codec) { + char **head; + int i; + /* clear init verbs */ snd_array_free(&codec->init_verbs); + /* clear hints */ + head = codec->hints.list; + for (i = 0; i < codec->hints.used; i++, head++) + kfree(*head); + snd_array_free(&codec->hints); } static void hwdep_free(struct snd_hwdep *hwdep) @@ -131,6 +140,7 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) #endif snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); + snd_array_init(&codec->hints, sizeof(char *), 32); return 0; } @@ -280,6 +290,29 @@ static ssize_t init_verbs_store(struct device *dev, return count; } +static ssize_t hints_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_hwdep *hwdep = dev_get_drvdata(dev); + struct hda_codec *codec = hwdep->private_data; + char *p; + char **hint; + + if (!*buf || isspace(*buf) || *buf == '#' || *buf == '\n') + return count; + p = kstrndup_noeol(buf, 1024); + if (!p) + return -ENOMEM; + hint = snd_array_new(&codec->hints); + if (!hint) { + kfree(p); + return -ENOMEM; + } + *hint = p; + return count; +} + #define CODEC_ATTR_RW(type) \ __ATTR(type, 0644, type##_show, type##_store) #define CODEC_ATTR_RO(type) \ @@ -296,6 +329,7 @@ static struct device_attribute codec_attrs[] = { CODEC_ATTR_RW(name), CODEC_ATTR_RW(modelname), CODEC_ATTR_WO(init_verbs), + CODEC_ATTR_WO(hints), CODEC_ATTR_WO(reconfig), CODEC_ATTR_WO(clear), }; From 45a6ac16c2136e4b902b09bf0b6192b940e8d732 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Wed, 15 Oct 2008 14:45:38 -0400 Subject: [PATCH 010/367] ALSA: hda: add support for jack detection on IDT/Sigmatel Added support for jack detection reporting to userspace for IDT/Sigmatel codecs. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 1 + sound/pci/hda/patch_sigmatel.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7003711f4fcc..7e408908b755 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -501,6 +501,7 @@ config SND_HDA_INTEL tristate "Intel HD Audio" select SND_PCM select SND_VMASTER + select SND_JACK if INPUT=y || INPUT=SND help Say Y here to include support for Intel "High Definition Audio" (Azalia) motherboard devices. diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a2ac7205d45d..ec88ba881482 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "hda_codec.h" #include "hda_local.h" #include "hda_patch.h" @@ -216,6 +217,9 @@ struct sigmatel_spec { struct hda_pcm pcm_rec[2]; /* PCM information */ + /* jack detection */ + struct snd_jack *jack; + /* dynamic controls and input_mux */ struct auto_pin_cfg autocfg; unsigned int num_kctl_alloc, num_kctl_used; @@ -3617,7 +3621,7 @@ static int stac92xx_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + int i, err; snd_hda_sequence_write(codec, spec->init); @@ -3639,6 +3643,12 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); stac92xx_auto_init_hp_out(codec); + /* jack detection */ + err = snd_jack_new(codec->bus->card, + "Headphone Jack", + SND_JACK_HEADPHONE, &spec->jack); + if (err < 0) + return err; /* fake event to set up pins */ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); } else { @@ -3796,6 +3806,8 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) break; presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); } + snd_jack_report(spec->jack, + presence ? SND_JACK_HEADPHONE : 0); if (presence) { /* disable lineouts, enable hp */ From 17be5522f6de1d4920e7d9235bfb0e0c682c6f8f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 15 Oct 2008 19:57:12 +0200 Subject: [PATCH 011/367] ALSA: ASoC: Convert wm8580 to a new-style i2c driver Convert the wm8580 codec driver to the new (standard) device driver binding model. Signed-off-by: Jean Delvare Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8580.c | 108 +++++++++++++++++++------------------- sound/soc/codecs/wm8580.h | 1 + 2 files changed, 54 insertions(+), 55 deletions(-) diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 627ebfb4209b..cbcd7c324ab9 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -900,85 +900,85 @@ static struct snd_soc_device *wm8580_socdev; * low = 0x1a * high = 0x1b */ -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver wm8580_i2c_driver; -static struct i2c_client client_template; - -static int wm8580_codec_probe(struct i2c_adapter *adap, int addr, int kind) +static int wm8580_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct snd_soc_device *socdev = wm8580_socdev; - struct wm8580_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; int ret; - if (addr != setup->i2c_address) - return -ENODEV; - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = i2c_attach_client(i2c); - if (ret < 0) { - dev_err(&i2c->dev, "failed to attach codec at addr %x\n", addr); - goto err; - } - ret = wm8580_init(socdev); - if (ret < 0) { + if (ret < 0) dev_err(&i2c->dev, "failed to initialise WM8580\n"); - goto err; - } - - return ret; - -err: - kfree(codec); - kfree(i2c); return ret; } -static int wm8580_i2c_detach(struct i2c_client *client) +static int wm8580_i2c_remove(struct i2c_client *client) { struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); kfree(codec->reg_cache); - kfree(client); return 0; } -static int wm8580_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, wm8580_codec_probe); -} +static const struct i2c_device_id wm8580_i2c_id[] = { + { "wm8580", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); -/* corgi i2c codec control layer */ static struct i2c_driver wm8580_i2c_driver = { .driver = { .name = "WM8580 I2C Codec", .owner = THIS_MODULE, }, - .attach_adapter = wm8580_i2c_attach, - .detach_client = wm8580_i2c_detach, - .command = NULL, + .probe = wm8580_i2c_probe, + .remove = wm8580_i2c_remove, + .id_table = wm8580_i2c_id, }; -static struct i2c_client client_template = { - .name = "WM8580", - .driver = &wm8580_i2c_driver, -}; +static int wm8580_add_i2c_device(struct platform_device *pdev, + const struct wm8580_setup_data *setup) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + int ret; + + ret = i2c_add_driver(&wm8580_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = setup->i2c_address; + strlcpy(info.type, "wm8580", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(setup->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "can't get i2c adapter %d\n", + setup->i2c_bus); + goto err_driver; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + goto err_driver; + } + + return 0; + +err_driver: + i2c_del_driver(&wm8580_i2c_driver); + return -ENODEV; +} #endif static int wm8580_probe(struct platform_device *pdev) @@ -1011,11 +1011,8 @@ static int wm8580_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8580_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); + ret = wm8580_add_i2c_device(pdev, setup); } #else /* Add other interfaces here */ @@ -1034,6 +1031,7 @@ static int wm8580_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_unregister_device(codec->control_data); i2c_del_driver(&wm8580_i2c_driver); #endif kfree(codec->private_data); diff --git a/sound/soc/codecs/wm8580.h b/sound/soc/codecs/wm8580.h index 589ddaba21d7..09e4422f6f2f 100644 --- a/sound/soc/codecs/wm8580.h +++ b/sound/soc/codecs/wm8580.h @@ -29,6 +29,7 @@ #define WM8580_CLKSRC_NONE 5 struct wm8580_setup_data { + int i2c_bus; unsigned short i2c_address; }; From 8ae6a5523f4188dbe2b98a9385f5860df6ee47a3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 15 Oct 2008 19:58:12 +0200 Subject: [PATCH 012/367] ALSA: ASoC: Convert wm8900 to a new-style i2c driver Convert the wm8900 codec driver to the new (standard) device driver binding model. Signed-off-by: Jean Delvare Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8900.c | 113 ++++++++++++++++++-------------------- sound/soc/codecs/wm8900.h | 1 + 2 files changed, 55 insertions(+), 59 deletions(-) diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 3b326c9b5586..de016f41e04c 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1387,89 +1387,86 @@ static struct snd_soc_device *wm8900_socdev; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; - -/* Magic definition of all other variables and things */ -I2C_CLIENT_INSMOD; - -static struct i2c_driver wm8900_i2c_driver; -static struct i2c_client client_template; - /* If the i2c layer weren't so broken, we could pass this kind of data around */ -static int wm8900_codec_probe(struct i2c_adapter *adap, int addr, int kind) +static int wm8900_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct snd_soc_device *socdev = wm8900_socdev; - struct wm8900_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c; int ret; - if (addr != setup->i2c_address) - return -ENODEV; - - dev_err(&adap->dev, "Probe on %x\n", addr); - - client_template.adapter = adap; - client_template.addr = addr; - - i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); - if (i2c == NULL) { - kfree(codec); - return -ENOMEM; - } i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = i2c_attach_client(i2c); - if (ret < 0) { - dev_err(&adap->dev, - "failed to attach codec at addr %x\n", addr); - goto err; - } - ret = wm8900_init(socdev); - if (ret < 0) { - dev_err(&adap->dev, "failed to initialise WM8900\n"); - goto err; - } - return ret; - -err: - kfree(codec); - kfree(i2c); + if (ret < 0) + dev_err(&i2c->dev, "failed to initialise WM8900\n"); return ret; } -static int wm8900_i2c_detach(struct i2c_client *client) +static int wm8900_i2c_remove(struct i2c_client *client) { struct snd_soc_codec *codec = i2c_get_clientdata(client); - i2c_detach_client(client); kfree(codec->reg_cache); - kfree(client); return 0; } -static int wm8900_i2c_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, wm8900_codec_probe); -} +static const struct i2c_device_id wm8900_i2c_id[] = { + { "wm8900", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); -/* corgi i2c codec control layer */ static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "WM8900 I2C codec", .owner = THIS_MODULE, }, - .attach_adapter = wm8900_i2c_attach, - .detach_client = wm8900_i2c_detach, - .command = NULL, + .probe = wm8900_i2c_probe, + .remove = wm8900_i2c_remove, + .id_table = wm8900_i2c_id, }; -static struct i2c_client client_template = { - .name = "WM8900", - .driver = &wm8900_i2c_driver, -}; +static int wm8900_add_i2c_device(struct platform_device *pdev, + const struct wm8900_setup_data *setup) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + int ret; + + ret = i2c_add_driver(&wm8900_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = setup->i2c_address; + strlcpy(info.type, "wm8900", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(setup->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "can't get i2c adapter %d\n", + setup->i2c_bus); + goto err_driver; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + goto err_driver; + } + + return 0; + +err_driver: + i2c_del_driver(&wm8900_i2c_driver); + return -ENODEV; +} #endif static int wm8900_probe(struct platform_device *pdev) @@ -1497,11 +1494,8 @@ static int wm8900_probe(struct platform_device *pdev) wm8900_socdev = socdev; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { - normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8900_i2c_driver); - if (ret != 0) - printk(KERN_ERR "can't add i2c driver"); + ret = wm8900_add_i2c_device(pdev, setup); } #else #error Non-I2C interfaces not yet supported @@ -1521,6 +1515,7 @@ static int wm8900_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_unregister_device(codec->control_data); i2c_del_driver(&wm8900_i2c_driver); #endif kfree(codec); diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h index ba450d99e902..2249a446ad37 100644 --- a/sound/soc/codecs/wm8900.h +++ b/sound/soc/codecs/wm8900.h @@ -55,6 +55,7 @@ #define WM8900_ struct wm8900_setup_data { + int i2c_bus; unsigned short i2c_address; }; From 6b9331165e9827e055389e22d1cbdb5fe3cff835 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Oct 2008 11:00:07 +0100 Subject: [PATCH 013/367] ALSA: ASoC: Remove snd_soc_dapm_connect_input() This was marked as deprecated in 2.6.27 and all users except for playpaq_wm8510 fixed in that release. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- include/sound/soc-dapm.h | 2 -- sound/soc/soc-dapm.c | 22 ---------------------- 2 files changed, 24 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index ca699a3017f3..7ee2f70ca42e 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -221,8 +221,6 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, int num); /* dapm path setup */ -int __deprecated snd_soc_dapm_connect_input(struct snd_soc_codec *codec, - const char *sink_name, const char *control_name, const char *src_name); int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); void snd_soc_dapm_free(struct snd_soc_device *socdev); int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index efbd0b37810a..4060fc54bbb1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1006,28 +1006,6 @@ err: return ret; } -/** - * snd_soc_dapm_connect_input - connect dapm widgets - * @codec: audio codec - * @sink: name of target widget - * @control: mixer control name - * @source: name of source name - * - * Connects 2 dapm widgets together via a named audio path. The sink is - * the widget receiving the audio signal, whilst the source is the sender - * of the audio signal. - * - * This function has been deprecated in favour of snd_soc_dapm_add_routes(). - * - * Returns 0 for success else error. - */ -int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, - const char *control, const char *source) -{ - return snd_soc_dapm_add_route(codec, sink, control, source); -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); - /** * snd_soc_dapm_add_routes - Add routes between DAPM widgets * @codec: codec From 76a4d10e522bfc238ddf70f35272088d420d2dcf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Oct 2008 16:17:30 +0200 Subject: [PATCH 014/367] ALSA: Print function symbol in the error messages Use the new %pF for error messages in snd_device_*() functions to give more understandable results. Signed-off-by: Takashi Iwai --- sound/core/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/device.c b/sound/core/device.c index c58d8227254c..a67dfac08c03 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -98,7 +98,7 @@ int snd_device_free(struct snd_card *card, void *device_data) kfree(dev); return 0; } - snd_printd("device free %p (from %p), not found\n", device_data, + snd_printd("device free %p (from %pF), not found\n", device_data, __builtin_return_address(0)); return -ENXIO; } @@ -135,7 +135,7 @@ int snd_device_disconnect(struct snd_card *card, void *device_data) } return 0; } - snd_printd("device disconnect %p (from %p), not found\n", device_data, + snd_printd("device disconnect %p (from %pF), not found\n", device_data, __builtin_return_address(0)); return -ENXIO; } From ebaa0470586eec83627fa03dcd0a1107f54258f8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 16 Oct 2008 16:39:56 +0200 Subject: [PATCH 015/367] ALSA: hda - Release jack instance for dynamic reconfigure The jack instance has to be release manually in free callback in patch_sigmatel.c for dynamic reconfiguration. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 579b32817836..d106ea52a90d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3717,6 +3717,9 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; + if (spec->jack) + snd_device_free(codec->bus->card, spec->jack); + if (spec->bios_pin_configs) kfree(spec->bios_pin_configs); From 96c7d478efad594e483ee8a826395b1342404885 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Aug 2008 10:18:39 +0200 Subject: [PATCH 016/367] ALSA: pcsp - Fix locking messes in snd-pcsp snd-pcsp driver takes chip->substream_lock together with PCM substream lock. These are even mixed up with hrtimer's lock, resulting in messy lock depencies. Right now, snd-pcsp driver resolves the deadlock by using HRTIMER_CB_SOFTIRQ. However, this isn't nice for a really fast path like bit-flipping. This patch introduces a tasklet for PCM period handling so that the hrtimer callback can be handled fast. This also reduce the use of chip->substream_lock to avoid deadlocks. It's still used in pointer callback, but even this could be removed with a proper barrier. Another good solution is to introduce async trigger callback. But, this will involve with a major rewrite of the PCM core code, so I take first this easy fix. Signed-off-by: Takashi Iwai --- sound/drivers/pcsp/pcsp.c | 8 ++- sound/drivers/pcsp/pcsp.h | 1 + sound/drivers/pcsp/pcsp_lib.c | 95 +++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index 1899cf0685bc..87219bf0a35e 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -96,7 +96,7 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) return -EINVAL; hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - pcsp_chip.timer.cb_mode = HRTIMER_CB_SOFTIRQ; + pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE; pcsp_chip.timer.function = pcsp_do_timer; card = snd_card_new(index, id, THIS_MODULE, 0); @@ -188,10 +188,8 @@ static int __devexit pcsp_remove(struct platform_device *dev) static void pcsp_stop_beep(struct snd_pcsp *chip) { - spin_lock_irq(&chip->substream_lock); - if (!chip->playback_substream) - pcspkr_stop_sound(); - spin_unlock_irq(&chip->substream_lock); + pcsp_sync_stop(chip); + pcspkr_stop_sound(); } #ifdef CONFIG_PM diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h index 1d661f795e8c..70533a333b5b 100644 --- a/sound/drivers/pcsp/pcsp.h +++ b/sound/drivers/pcsp/pcsp.h @@ -77,6 +77,7 @@ struct snd_pcsp { extern struct snd_pcsp pcsp_chip; extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle); +extern void pcsp_sync_stop(struct snd_pcsp *chip); extern int snd_pcsp_new_pcm(struct snd_pcsp *chip); extern int snd_pcsp_new_mixer(struct snd_pcsp *chip); diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index e341f3f83b6a..40f95f549d2b 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include "pcsp.h" @@ -19,6 +20,22 @@ MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround " #define DMIX_WANTS_S16 1 +/* + * Call snd_pcm_period_elapsed in a tasklet + * This avoids spinlock messes and long-running irq contexts + */ +static void pcsp_call_pcm_elapsed(unsigned long priv) +{ + if (atomic_read(&pcsp_chip.timer_active)) { + struct snd_pcm_substream *substream; + substream = pcsp_chip.playback_substream; + if (substream) + snd_pcm_period_elapsed(substream); + } +} + +static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); + enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) { unsigned char timer_cnt, val; @@ -28,41 +45,23 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); + unsigned long flags; if (chip->thalf) { outb(chip->val61, 0x61); chip->thalf = 0; if (!atomic_read(&chip->timer_active)) - return HRTIMER_NORESTART; + goto stop; hrtimer_forward(&chip->timer, chip->timer.expires, ktime_set(0, chip->ns_rem)); return HRTIMER_RESTART; } - spin_lock_irq(&chip->substream_lock); - /* Takashi Iwai says regarding this extra lock: - - If the irq handler handles some data on the DMA buffer, it should - do snd_pcm_stream_lock(). - That protects basically against all races among PCM callbacks, yes. - However, there are two remaining issues: - 1. The substream pointer you try to lock isn't protected _before_ - this lock yet. - 2. snd_pcm_period_elapsed() itself acquires the lock. - The requirement of another lock is because of 1. When you get - chip->playback_substream, it's not protected. - Keeping this lock while snd_pcm_period_elapsed() assures the substream - is still protected (at least, not released). And the other status is - handled properly inside snd_pcm_stream_lock() in - snd_pcm_period_elapsed(). - - */ - if (!chip->playback_substream) - goto exit_nr_unlock1; - substream = chip->playback_substream; - snd_pcm_stream_lock(substream); if (!atomic_read(&chip->timer_active)) - goto exit_nr_unlock2; + goto stop; + substream = chip->playback_substream; + if (!substream) + goto stop; runtime = substream->runtime; fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3; @@ -87,6 +86,8 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) period_bytes = snd_pcm_lib_period_bytes(substream); buffer_bytes = snd_pcm_lib_buffer_bytes(substream); + + spin_lock_irqsave(&chip->substream_lock, flags); chip->playback_ptr += PCSP_INDEX_INC() * fmt_size; periods_elapsed = chip->playback_ptr - chip->period_ptr; if (periods_elapsed < 0) { @@ -102,18 +103,15 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) * or ALSA will BUG on us. */ chip->playback_ptr %= buffer_bytes; - snd_pcm_stream_unlock(substream); - if (periods_elapsed) { - snd_pcm_period_elapsed(substream); chip->period_ptr += periods_elapsed * period_bytes; chip->period_ptr %= buffer_bytes; + tasklet_schedule(&pcsp_pcm_tasklet); } - - spin_unlock_irq(&chip->substream_lock); + spin_unlock_irqrestore(&chip->substream_lock, flags); if (!atomic_read(&chip->timer_active)) - return HRTIMER_NORESTART; + goto stop; chip->ns_rem = PCSP_PERIOD_NS(); ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); @@ -121,10 +119,7 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) hrtimer_forward(&chip->timer, chip->timer.expires, ktime_set(0, ns)); return HRTIMER_RESTART; -exit_nr_unlock2: - snd_pcm_stream_unlock(substream); -exit_nr_unlock1: - spin_unlock_irq(&chip->substream_lock); + stop: return HRTIMER_NORESTART; } @@ -164,26 +159,35 @@ static void pcsp_stop_playing(struct snd_pcsp *chip) spin_unlock(&i8253_lock); } +/* + * Force to stop and sync the stream + */ +void pcsp_sync_stop(struct snd_pcsp *chip) +{ + local_irq_disable(); + pcsp_stop_playing(chip); + local_irq_enable(); + hrtimer_cancel(&chip->timer); + tasklet_kill(&pcsp_pcm_tasklet); +} + static int snd_pcsp_playback_close(struct snd_pcm_substream *substream) { struct snd_pcsp *chip = snd_pcm_substream_chip(substream); #if PCSP_DEBUG printk(KERN_INFO "PCSP: close called\n"); #endif - if (atomic_read(&chip->timer_active)) { - printk(KERN_ERR "PCSP: timer still active\n"); - pcsp_stop_playing(chip); - } - spin_lock_irq(&chip->substream_lock); + pcsp_sync_stop(chip); chip->playback_substream = NULL; - spin_unlock_irq(&chip->substream_lock); return 0; } static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { + struct snd_pcsp *chip = snd_pcm_substream_chip(substream); int err; + pcsp_sync_stop(chip); err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) @@ -193,9 +197,11 @@ static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream, static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream) { + struct snd_pcsp *chip = snd_pcm_substream_chip(substream); #if PCSP_DEBUG printk(KERN_INFO "PCSP: hw_free called\n"); #endif + pcsp_sync_stop(chip); return snd_pcm_lib_free_pages(substream); } @@ -211,6 +217,7 @@ static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream) snd_pcm_lib_period_bytes(substream), substream->runtime->periods); #endif + pcsp_sync_stop(chip); chip->playback_ptr = 0; chip->period_ptr = 0; return 0; @@ -241,7 +248,11 @@ static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream *substream) { struct snd_pcsp *chip = snd_pcm_substream_chip(substream); - return bytes_to_frames(substream->runtime, chip->playback_ptr); + unsigned int pos; + spin_lock(&chip->substream_lock); + pos = chip->playback_ptr; + spin_unlock(&chip->substream_lock); + return bytes_to_frames(substream->runtime, pos); } static struct snd_pcm_hardware snd_pcsp_playback = { @@ -278,9 +289,7 @@ static int snd_pcsp_playback_open(struct snd_pcm_substream *substream) return -EBUSY; } runtime->hw = snd_pcsp_playback; - spin_lock_irq(&chip->substream_lock); chip->playback_substream = substream; - spin_unlock_irq(&chip->substream_lock); return 0; } From c872e8cab5b7cab0696bcf09c6f03c972edc1c49 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 12 Aug 2008 13:39:01 +0200 Subject: [PATCH 017/367] ALSA: Enable SPDIF output on ALC655 Some hardwares with ALC655 codec don't indicate the proper ext id bit for SPDIF output although it supports. Force to enable the bit. Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 6e831aff1bd0..2c7cd97d2234 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2832,6 +2832,8 @@ static int patch_alc655(struct snd_ac97 * ac97) val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ else val |= (1 << 1); /* Pin 47 is spdif input pin */ + /* this seems missing on some hardwares */ + ac97->ext_id |= AC97_EI_SPDIF; } val &= ~(1 << 12); /* vref enable */ snd_ac97_write_cache(ac97, 0x7a, val); From 1083206ff44af4baa03573b4a6bac430d9d70404 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 11 Aug 2008 10:18:39 +0200 Subject: [PATCH 018/367] ALSA: ice1724 - Fix TX IRQ lockup MPU TX causes IRQ floods on VT172x devices mysteriously. Disable TX IRQ if the IRQ flood is detected. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 1b3f11702713..79a9cd0881f7 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -382,23 +382,25 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) unsigned char status_mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM; int handled = 0; -#ifdef CONFIG_SND_DEBUG int timeout = 0; -#endif while (1) { status = inb(ICEREG1724(ice, IRQSTAT)); status &= status_mask; if (status == 0) break; -#ifdef CONFIG_SND_DEBUG if (++timeout > 10) { - printk(KERN_ERR - "ice1724: Too long irq loop, status = 0x%x\n", - status); + status = inb(ICEREG1724(ice, IRQSTAT)); + printk(KERN_ERR "ice1724: Too long irq loop, " + "status = 0x%x\n", status); + if (status & VT1724_IRQ_MPU_TX) { + printk(KERN_ERR "ice1724: Disabling MPU_TX\n"); + outb(inb(ICEREG1724(ice, IRQMASK)) & + ~VT1724_IRQ_MPU_TX, + ICEREG1724(ice, IRQMASK)); + } break; } -#endif handled = 1; if (status & VT1724_IRQ_MPU_TX) { spin_lock(&ice->reg_lock); @@ -2351,7 +2353,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card, { struct snd_ice1712 *ice; int err; - unsigned char mask; + /* unsigned char mask; */ static struct snd_device_ops ops = { .dev_free = snd_vt1724_dev_free, }; @@ -2413,8 +2415,10 @@ static int __devinit snd_vt1724_create(struct snd_card *card, } /* unmask used interrupts */ +#if 0 /* these are enabled/disabled dynamically */ mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX; outb(mask, ICEREG1724(ice, IRQMASK)); +#endif /* don't handle FIFO overrun/underruns (just yet), * since they cause machine lockups */ From 18c7109289625106cdc810b20b628cd13b46d6dd Mon Sep 17 00:00:00 2001 From: Vedran Miletic Date: Tue, 21 Oct 2008 17:42:54 +0200 Subject: [PATCH 019/367] ALSA: emu10k1: fix device names for Live!/Audigy1/2/4/E-mu * added missing SBxxxx, CTxxxx, PCxxx and MAEMxxxx where they were missing, and fixed some of them which were wrong (according to kx.inf, which is pretty accurate compared to anything out there) * fixed device names to make them more consistent across various cards * fixed order of devices where appropriate Signed-off-by: Vedran Miletic Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 146 ++++++++++++++++--------------- 1 file changed, 76 insertions(+), 70 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 2f283ea6ad9a..423aa0de1fad 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1292,21 +1292,6 @@ static int snd_emu10k1_dev_free(struct snd_device *device) } static struct snd_emu_chip_details emu_chip_details[] = { - /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ - /* Tested by James@superbug.co.uk 3rd July 2005 */ - /* DSP: CA0108-IAT - * DAC: CS4382-KQ - * ADC: Philips 1361T - * AC97: STAC9750 - * CA0151: None - */ - {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, - .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", - .id = "Audigy2", - .emu10k2_chip = 1, - .ca0108_chip = 1, - .spk71 = 1, - .ac97_chip = 1} , /* Audigy4 (Not PRO) SB0610 */ /* Tested by James@superbug.co.uk 4th April 2006 */ /* A_IOCFG bits @@ -1346,20 +1331,37 @@ static struct snd_emu_chip_details emu_chip_details[] = { * CA0151: None */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102, - .driver = "Audigy2", .name = "Audigy 4 [SB0610]", + .driver = "Audigy2", .name = "SB Audigy 4 [SB0610]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , + /* Audigy 2 Value AC3 out does not work yet. + * Need to find out how to turn off interpolators. + */ + /* Tested by James@superbug.co.uk 3rd July 2005 */ + /* DSP: CA0108-IAT + * DAC: CS4382-KQ + * ADC: Philips 1361T + * AC97: STAC9750 + * CA0151: None + */ + {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, + .driver = "Audigy2", .name = "SB Audigy 2 Value [SB0400]", + .id = "Audigy2", + .emu10k2_chip = 1, + .ca0108_chip = 1, + .spk71 = 1, + .ac97_chip = 1} , /* Audigy 2 ZS Notebook Cardbus card.*/ /* Tested by James@superbug.co.uk 6th November 2006 */ /* Audio output 7.1/Headphones working. * Digital output working. (AC3 not checked, only PCM) * Audio Mic/Line inputs working. * Digital input not tested. - */ + */ /* DSP: Tina2 * DAC: Wolfson WM8768/WM8568 * ADC: Wolfson WM8775 @@ -1386,7 +1388,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, - .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", + .driver = "Audigy2", .name = "SB Audigy 2 ZS Notebook [SB0530]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1396,7 +1398,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1} , /* Tested by James@superbug.co.uk 4th Nov 2007. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, - .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", + .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1404,47 +1406,50 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1 , .emu_model = EMU_MODEL_EMU1616}, /* Tested by James@superbug.co.uk 4th Nov 2007. */ + /* This is MAEM8960, 0202 is MAEM 8980 */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, - .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", + .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU1010B}, + .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */ /* Tested by James@superbug.co.uk 8th July 2005. */ + /* This is MAEM8810, 0202 is MAEM8820 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, - .driver = "Audigy2", .name = "E-mu 1010 [4001]", + .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]", .id = "EMU1010", .emu10k2_chip = 1, .ca0102_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU1010}, /* Emu 1010 */ + .emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */ /* EMU0404b */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102, - .driver = "Audigy2", .name = "E-mu 0404b [4002]", + .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]", .id = "EMU0404", .emu10k2_chip = 1, .ca0108_chip = 1, .spk71 = 1, - .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ + .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */ /* Tested by James@superbug.co.uk 20-3-2007. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102, - .driver = "Audigy2", .name = "E-mu 0404 [4002]", + .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]", .id = "EMU0404", .emu10k2_chip = 1, .ca0102_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ +#endif /* Audigy4 (Not PRO) SB0610 */ - {.vendor = 0x1102, .device = 0x0008, - .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", + {.vendor = 0x1102, .device = 0x0008, + .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]", .id = "Audigy2", .emu10k2_chip = 1, .ca0108_chip = 1, .ac97_chip = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, - .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", + .driver = "Audigy2", .name = "SB Audigy 4 PRO [SB0380]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1457,7 +1462,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * Just like 0x20021102 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20061102, - .driver = "Audigy2", .name = "Audigy 2 [SB0350b]", + .driver = "Audigy2", .name = "SB Audigy 2 [SB0350b]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1466,7 +1471,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, - .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", + .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1475,7 +1480,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, - .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", + .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0360]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1492,7 +1497,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { * CA0151: Yes */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102, - .driver = "Audigy2", .name = "Audigy 2 [SB0240]", + .driver = "Audigy2", .name = "SB Audigy 2 [SB0240]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1502,7 +1507,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, - .driver = "Audigy2", .name = "Audigy 2 EX [1005]", + .driver = "Audigy2", .name = "SB Audigy 2 Platinum EX [SB0280]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1512,7 +1517,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { /* Dell OEM/Creative Labs Audigy 2 ZS */ /* See ALSA bug#1365 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10031102, - .driver = "Audigy2", .name = "Audigy 2 ZS [SB0353]", + .driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0353]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1521,7 +1526,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, - .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", + .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1532,7 +1537,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */ .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .revision = 0x04, - .driver = "Audigy2", .name = "Audigy 2 [Unknown]", + .driver = "Audigy2", .name = "SB Audigy 2 [Unknown]", .id = "Audigy2", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1540,78 +1545,79 @@ static struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102, - .driver = "Audigy", .name = "Audigy 1 [SB0090]", + .driver = "Audigy", .name = "SB Audigy 1 [SB0092]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00521102, - .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", + .driver = "Audigy", .name = "SB Audigy 1 ES [SB0160]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .spdif_bug = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102, - .driver = "Audigy", .name = "Audigy 1 [SB0090]", + .driver = "Audigy", .name = "SB Audigy 1 [SB0090]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0004, - .driver = "Audigy", .name = "Audigy 1 [Unknown]", + .driver = "Audigy", .name = "Audigy 1 [Unknown]", .id = "Audigy", .emu10k2_chip = 1, .ca0102_chip = 1, .ac97_chip = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102, - .driver = "EMU10K1", .name = "SBLive! [SB0105]", + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102, + .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102, - .driver = "EMU10K1", .name = "SBLive! Value [SB0103]", + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806b1102, + .driver = "EMU10K1", .name = "SB Live! [SB0105]", + .id = "Live", + .emu10k1_chip = 1, + .ac97_chip = 1, + .sblive51 = 1} , + {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806a1102, + .driver = "EMU10K1", .name = "SB Live! Value [SB0103]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102, - .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", + .driver = "EMU10K1", .name = "SB Live! Value [SB0101]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by ALSA bug#1680 26th December 2005 */ - /* note: It really has SB0220 written on the card. */ + /* note: It really has SB0220 written on the card, */ + /* but it's SB0228 according to kx.inf */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80661102, - .driver = "EMU10K1", .name = "SB Live 5.1 Dell OEM [SB0220]", + .driver = "EMU10K1", .name = "SB Live! 5.1 Dell OEM [SB0228]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by Thomas Zehetbauer 27th Aug 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102, - .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", - .id = "Live", - .emu10k1_chip = 1, - .ac97_chip = 1, - .sblive51 = 1} , - {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102, - .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]", + .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, - .driver = "EMU10K1", .name = "SB Live 5.1", + .driver = "EMU10K1", .name = "SB Live! 5.1", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by alsa bugtrack user "hus" bug #1297 12th Aug 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, - .driver = "EMU10K1", .name = "SBLive 5.1 [SB0060]", + .driver = "EMU10K1", .name = "SB Live! 5.1 [SB0060]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 2, /* ac97 is optional; both SBLive 5.1 and platinum @@ -1619,78 +1625,78 @@ static struct snd_emu_chip_details emu_chip_details[] = { */ .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4850]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, - .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", + .driver = "EMU10K1", .name = "SB Live! Platinum [CT4760P]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4871]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4831]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4870]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , /* Tested by James@superbug.co.uk 3rd July 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4832]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4830]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102, - .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", + .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4780]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, - .driver = "EMU10K1", .name = "E-mu APS [4001]", + .driver = "EMU10K1", .name = "E-mu APS [PC545]", .id = "APS", .emu10k1_chip = 1, .ecard = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102, - .driver = "EMU10K1", .name = "SBLive! [CT4620]", + .driver = "EMU10K1", .name = "SB Live! [CT4620]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102, - .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", + .driver = "EMU10K1", .name = "SB Live! Value [CT4670]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, - .driver = "EMU10K1", .name = "SB Live [Unknown]", + .driver = "EMU10K1", .name = "SB Live! [Unknown]", .id = "Live", .emu10k1_chip = 1, .ac97_chip = 1, From 718a2594b6a8c1c050fea85abbb4932b11105c17 Mon Sep 17 00:00:00 2001 From: Vedran Miletic Date: Tue, 21 Oct 2008 21:31:27 +0200 Subject: [PATCH 020/367] ALSA: emu10k1: fix faulty commit 18c71092 Commit 18c7109289625106cdc810b20b628cd13b46d6dd had #endif leftoff from compilation. This patch fixes it. Also, I replaced a misplaced comment by a useful one, that explains why are here #ifdef and #endif added in compilation. Signed-off-by: Vedran Miletic Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 423aa0de1fad..0d7466bbd749 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1439,8 +1439,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { .ca0102_chip = 1, .spk71 = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ -#endif - /* Audigy4 (Not PRO) SB0610 */ + /* Note that all E-mu cards require kernel 2.6 or newer. */ {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]", .id = "Audigy2", From 888dcb7cb26fb85dfe3486d28a2431d69d3e8148 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 23 Oct 2008 15:47:56 +0200 Subject: [PATCH 021/367] ALSA: aoa: clean up file names This cleans up the apple onboard audio driver filenames. Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai --- sound/aoa/codecs/Makefile | 4 ++++ sound/aoa/codecs/{snd-aoa-codec-onyx.c => onyx.c} | 12 ++++++------ sound/aoa/codecs/{snd-aoa-codec-onyx.h => onyx.h} | 0 ...d-aoa-codec-tas-basstreble.h => tas-basstreble.h} | 0 ...d-aoa-codec-tas-gain-table.h => tas-gain-table.h} | 0 sound/aoa/codecs/{snd-aoa-codec-tas.c => tas.c} | 8 ++++---- sound/aoa/codecs/{snd-aoa-codec-tas.h => tas.h} | 0 .../aoa/codecs/{snd-aoa-codec-toonie.c => toonie.c} | 2 +- sound/aoa/core/Makefile | 8 ++++---- sound/aoa/core/{snd-aoa-alsa.c => alsa.c} | 4 ++-- sound/aoa/core/{snd-aoa-alsa.h => alsa.h} | 0 sound/aoa/core/{snd-aoa-core.c => core.c} | 2 +- .../core/{snd-aoa-gpio-feature.c => gpio-feature.c} | 2 +- sound/aoa/core/{snd-aoa-gpio-pmf.c => gpio-pmf.c} | 0 sound/aoa/fabrics/Makefile | 2 ++ .../fabrics/{snd-aoa-fabric-layout.c => layout.c} | 2 +- sound/aoa/soundbus/i2sbus/Makefile | 2 +- .../soundbus/i2sbus/{i2sbus-control.c => control.c} | 0 sound/aoa/soundbus/i2sbus/{i2sbus-core.c => core.c} | 4 ++-- sound/aoa/soundbus/i2sbus/i2sbus.h | 2 +- .../i2sbus/{i2sbus-interface.h => interface.h} | 0 sound/aoa/soundbus/i2sbus/{i2sbus-pcm.c => pcm.c} | 0 22 files changed, 30 insertions(+), 24 deletions(-) rename sound/aoa/codecs/{snd-aoa-codec-onyx.c => onyx.c} (99%) rename sound/aoa/codecs/{snd-aoa-codec-onyx.h => onyx.h} (100%) rename sound/aoa/codecs/{snd-aoa-codec-tas-basstreble.h => tas-basstreble.h} (100%) rename sound/aoa/codecs/{snd-aoa-codec-tas-gain-table.h => tas-gain-table.h} (100%) rename sound/aoa/codecs/{snd-aoa-codec-tas.c => tas.c} (99%) rename sound/aoa/codecs/{snd-aoa-codec-tas.h => tas.h} (100%) rename sound/aoa/codecs/{snd-aoa-codec-toonie.c => toonie.c} (98%) rename sound/aoa/core/{snd-aoa-alsa.c => alsa.c} (98%) rename sound/aoa/core/{snd-aoa-alsa.h => alsa.h} (100%) rename sound/aoa/core/{snd-aoa-core.c => core.c} (99%) rename sound/aoa/core/{snd-aoa-gpio-feature.c => gpio-feature.c} (99%) rename sound/aoa/core/{snd-aoa-gpio-pmf.c => gpio-pmf.c} (100%) rename sound/aoa/fabrics/{snd-aoa-fabric-layout.c => layout.c} (99%) rename sound/aoa/soundbus/i2sbus/{i2sbus-control.c => control.c} (100%) rename sound/aoa/soundbus/i2sbus/{i2sbus-core.c => core.c} (99%) rename sound/aoa/soundbus/i2sbus/{i2sbus-interface.h => interface.h} (100%) rename sound/aoa/soundbus/i2sbus/{i2sbus-pcm.c => pcm.c} (100%) diff --git a/sound/aoa/codecs/Makefile b/sound/aoa/codecs/Makefile index 31cbe68fd42f..c3ee77fc4b2d 100644 --- a/sound/aoa/codecs/Makefile +++ b/sound/aoa/codecs/Makefile @@ -1,3 +1,7 @@ +snd-aoa-codec-onyx-objs := onyx.o +snd-aoa-codec-tas-objs := tas.o +snd-aoa-codec-toonie-objs := toonie.o + obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o obj-$(CONFIG_SND_AOA_TOONIE) += snd-aoa-codec-toonie.o diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/onyx.c similarity index 99% rename from sound/aoa/codecs/snd-aoa-codec-onyx.c rename to sound/aoa/codecs/onyx.c index 6a3837d480e5..15500b9d2da0 100644 --- a/sound/aoa/codecs/snd-aoa-codec-onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -37,7 +37,7 @@ MODULE_AUTHOR("Johannes Berg "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa"); -#include "snd-aoa-codec-onyx.h" +#include "onyx.h" #include "../aoa.h" #include "../soundbus/soundbus.h" @@ -292,7 +292,7 @@ static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new capture_source_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* If we name this 'Input Source', it properly shows up in - * alsamixer as a selection, * but it's shown under the + * alsamixer as a selection, * but it's shown under the * 'Playback' category. * If I name it 'Capture Source', it shows up in strange * ways (two bools of which one can be selected at a @@ -477,7 +477,7 @@ static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol, ucontrol->value.iec958.status[3] = 0x3f; ucontrol->value.iec958.status[4] = 0x0f; - + return 0; } @@ -682,7 +682,7 @@ static int onyx_usable(struct codec_info_item *cii, onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); spdif_enabled = !!(v & ONYX_SPDIF_ENABLE); onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); - analog_enabled = + analog_enabled = (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT)) != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT); mutex_unlock(&onyx->mutex); @@ -882,7 +882,7 @@ static int onyx_init_codec(struct aoa_codec *codec) msleep(1); onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); msleep(1); - + if (onyx_register_init(onyx)) { printk(KERN_ERR PFX "failed to initialise onyx registers\n"); return -ENODEV; @@ -1069,7 +1069,7 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter) /* if that didn't work, try desperate mode for older * machines that have stuff missing from the device tree */ - + if (!of_device_is_compatible(busnode, "k2-i2c")) return -ENODEV; diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.h b/sound/aoa/codecs/onyx.h similarity index 100% rename from sound/aoa/codecs/snd-aoa-codec-onyx.h rename to sound/aoa/codecs/onyx.h diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h b/sound/aoa/codecs/tas-basstreble.h similarity index 100% rename from sound/aoa/codecs/snd-aoa-codec-tas-basstreble.h rename to sound/aoa/codecs/tas-basstreble.h diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h b/sound/aoa/codecs/tas-gain-table.h similarity index 100% rename from sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h rename to sound/aoa/codecs/tas-gain-table.h diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/tas.c similarity index 99% rename from sound/aoa/codecs/snd-aoa-codec-tas.c rename to sound/aoa/codecs/tas.c index 6c515b2b8bbd..008e0f85097d 100644 --- a/sound/aoa/codecs/snd-aoa-codec-tas.c +++ b/sound/aoa/codecs/tas.c @@ -71,9 +71,9 @@ MODULE_AUTHOR("Johannes Berg "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("tas codec driver for snd-aoa"); -#include "snd-aoa-codec-tas.h" -#include "snd-aoa-codec-tas-gain-table.h" -#include "snd-aoa-codec-tas-basstreble.h" +#include "tas.h" +#include "tas-gain-table.h" +#include "tas-basstreble.h" #include "../aoa.h" #include "../soundbus/soundbus.h" @@ -880,7 +880,7 @@ static void tas_exit_codec(struct aoa_codec *codec) return; tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas); } - + static struct i2c_driver tas_driver; diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.h b/sound/aoa/codecs/tas.h similarity index 100% rename from sound/aoa/codecs/snd-aoa-codec-tas.h rename to sound/aoa/codecs/tas.h diff --git a/sound/aoa/codecs/snd-aoa-codec-toonie.c b/sound/aoa/codecs/toonie.c similarity index 98% rename from sound/aoa/codecs/snd-aoa-codec-toonie.c rename to sound/aoa/codecs/toonie.c index 3c7d1d8a9a6f..f13827e17562 100644 --- a/sound/aoa/codecs/snd-aoa-codec-toonie.c +++ b/sound/aoa/codecs/toonie.c @@ -131,7 +131,7 @@ static int __init toonie_init(void) toonie->codec.owner = THIS_MODULE; toonie->codec.init = toonie_init_codec; toonie->codec.exit = toonie_exit_codec; - + if (aoa_codec_register(&toonie->codec)) { kfree(toonie); return -EINVAL; diff --git a/sound/aoa/core/Makefile b/sound/aoa/core/Makefile index 62dc7287f663..a1596e88c718 100644 --- a/sound/aoa/core/Makefile +++ b/sound/aoa/core/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_SND_AOA) += snd-aoa.o -snd-aoa-objs := snd-aoa-core.o \ - snd-aoa-alsa.o \ - snd-aoa-gpio-pmf.o \ - snd-aoa-gpio-feature.o +snd-aoa-objs := core.o \ + alsa.o \ + gpio-pmf.o \ + gpio-feature.o diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/alsa.c similarity index 98% rename from sound/aoa/core/snd-aoa-alsa.c rename to sound/aoa/core/alsa.c index 17fe689ed287..617850463582 100644 --- a/sound/aoa/core/snd-aoa-alsa.c +++ b/sound/aoa/core/alsa.c @@ -6,7 +6,7 @@ * GPL v2, can be found in COPYING. */ #include -#include "snd-aoa-alsa.h" +#include "alsa.h" static int index = -1; module_param(index, int, 0444); @@ -64,7 +64,7 @@ int aoa_snd_device_new(snd_device_type_t type, { struct snd_card *card = aoa_get_card(); int err; - + if (!card) return -ENOMEM; err = snd_device_new(card, type, device_data, ops); diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/alsa.h similarity index 100% rename from sound/aoa/core/snd-aoa-alsa.h rename to sound/aoa/core/alsa.h diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/core.c similarity index 99% rename from sound/aoa/core/snd-aoa-core.c rename to sound/aoa/core/core.c index 19fdae400687..10bec6c61382 100644 --- a/sound/aoa/core/snd-aoa-core.c +++ b/sound/aoa/core/core.c @@ -10,7 +10,7 @@ #include #include #include "../aoa.h" -#include "snd-aoa-alsa.h" +#include "alsa.h" MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver"); MODULE_AUTHOR("Johannes Berg "); diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/gpio-feature.c similarity index 99% rename from sound/aoa/core/snd-aoa-gpio-feature.c rename to sound/aoa/core/gpio-feature.c index 805dcbff2257..c93ad5dec66b 100644 --- a/sound/aoa/core/snd-aoa-gpio-feature.c +++ b/sound/aoa/core/gpio-feature.c @@ -5,7 +5,7 @@ * * GPL v2, can be found in COPYING. * - * This file contains the GPIO control routines for + * This file contains the GPIO control routines for * direct (through feature calls) access to the GPIO * registers. */ diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/gpio-pmf.c similarity index 100% rename from sound/aoa/core/snd-aoa-gpio-pmf.c rename to sound/aoa/core/gpio-pmf.c diff --git a/sound/aoa/fabrics/Makefile b/sound/aoa/fabrics/Makefile index 55fc5e7e52cf..da37c10eca51 100644 --- a/sound/aoa/fabrics/Makefile +++ b/sound/aoa/fabrics/Makefile @@ -1 +1,3 @@ +snd-aoa-fabric-layout-objs += layout.o + obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/layout.c similarity index 99% rename from sound/aoa/fabrics/snd-aoa-fabric-layout.c rename to sound/aoa/fabrics/layout.c index dea7abb082cd..ad60f5d10e82 100644 --- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c +++ b/sound/aoa/fabrics/layout.c @@ -66,7 +66,7 @@ struct layout { unsigned int layout_id; struct codec_connect_info codecs[MAX_CODECS_PER_BUS]; int flags; - + /* if busname is not assigned, we use 'Master' below, * so that our layout table doesn't need to be filled * too much. diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile index e57a5cf65655..1b949b2a4028 100644 --- a/sound/aoa/soundbus/i2sbus/Makefile +++ b/sound/aoa/soundbus/i2sbus/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o -snd-aoa-i2sbus-objs := i2sbus-core.o i2sbus-pcm.o i2sbus-control.o +snd-aoa-i2sbus-objs := core.o pcm.o control.o diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.c b/sound/aoa/soundbus/i2sbus/control.c similarity index 100% rename from sound/aoa/soundbus/i2sbus/i2sbus-control.c rename to sound/aoa/soundbus/i2sbus/control.c diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/core.c similarity index 99% rename from sound/aoa/soundbus/i2sbus/i2sbus-core.c rename to sound/aoa/soundbus/i2sbus/core.c index e6beb92c6933..d1b5cff92499 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c +++ b/sound/aoa/soundbus/i2sbus/core.c @@ -64,7 +64,7 @@ static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, struct dbdma_command_mem *r) { if (!r->space) return; - + dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, r->size, r->space, r->bus_addr); } @@ -247,7 +247,7 @@ static int i2sbus_add_dev(struct macio_dev *macio, * but request_resource doesn't know about parents and * contained resources... */ - dev->allocated_resource[i] = + dev->allocated_resource[i] = request_mem_region(dev->resources[i].start, dev->resources[i].end - dev->resources[i].start + 1, diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h index ff29654782c9..befefd99e271 100644 --- a/sound/aoa/soundbus/i2sbus/i2sbus.h +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h @@ -18,7 +18,7 @@ #include #include -#include "i2sbus-interface.h" +#include "interface.h" #include "../soundbus.h" struct i2sbus_control { diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-interface.h b/sound/aoa/soundbus/i2sbus/interface.h similarity index 100% rename from sound/aoa/soundbus/i2sbus/i2sbus-interface.h rename to sound/aoa/soundbus/i2sbus/interface.h diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c similarity index 100% rename from sound/aoa/soundbus/i2sbus/i2sbus-pcm.c rename to sound/aoa/soundbus/i2sbus/pcm.c From 67679b1fd166da8398e70b7dbffe12cfccf9c7bf Mon Sep 17 00:00:00 2001 From: Vedran Miletic Date: Thu, 23 Oct 2008 18:51:00 +0200 Subject: [PATCH 022/367] ALSA: emu10k1: fix coding style for emu10k1_main.c I fixed all of coding style errors and some warnings, now it is down to: checkpatch.pl-0.24 --no-tree --file --strict --terse emu10k1_main.c total: 0 errors, 62 warnings, 7 checks, 2075 lines checked Signed-off-by: Vedran Miletic Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 347 ++++++++++++++++--------------- 1 file changed, 182 insertions(+), 165 deletions(-) diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 0d7466bbd749..dee7ebabccee 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -69,7 +69,7 @@ MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME); * EMU10K1 init / done *************************************************************************/ -void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch) +void snd_emu10k1_voice_init(struct snd_emu10k1 *emu, int ch) { snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); snd_emu10k1_ptr_write(emu, IP, ch, 0); @@ -151,9 +151,9 @@ static unsigned int i2c_adc_init[][2] = { { 0x12, 0x32 }, /* ALC Control 3 */ { 0x13, 0x00 }, /* Noise gate control */ { 0x14, 0xa6 }, /* Limiter control */ - { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */ + { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for A2ZS Notebook */ }; - + static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) { unsigned int silent_page; @@ -161,8 +161,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) u32 tmp; /* disable audio and lock cache */ - outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, - emu->port + HCFG); + outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | + HCFG_MUTEBUTTONENABLE, emu->port + HCFG); /* reset recording buffers */ snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE); @@ -179,7 +179,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); - if (emu->audigy){ + if (emu->audigy) { /* set SPDIF bypass mode */ snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT); /* enable rear left + rear right AC97 slots */ @@ -197,12 +197,12 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ - //Setup SRCMulti_I2S SamplingRate + /* Setup SRCMulti_I2S SamplingRate */ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; tmp |= (0x2<<9); snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); - + /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14); /* Setup SRCMulti Input Audio Enable */ @@ -217,7 +217,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); - //Setup SRCMulti_I2S SamplingRate + /* Setup SRCMulti_I2S SamplingRate */ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; tmp |= (0x2<<9); @@ -270,13 +270,13 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) size = ARRAY_SIZE(i2c_adc_init); for (n = 0; n < size; n++) snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); - for (n=0; n < 4; n++) { - emu->i2c_capture_volume[n][0]= 0xcf; - emu->i2c_capture_volume[n][1]= 0xcf; + for (n = 0; n < 4; n++) { + emu->i2c_capture_volume[n][0] = 0xcf; + emu->i2c_capture_volume[n][1] = 0xcf; } } - + snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ @@ -313,7 +313,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) (emu->model == 0x21 && emu->revision < 6)) outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG); else - // With on-chip joystick + /* With on-chip joystick */ outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); if (enable_ir) { /* enable IR for SB Live */ @@ -335,9 +335,9 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG); udelay(100); outl(reg, emu->port + HCFG); - } + } } - + if (emu->card_capabilities->emu_model) { ; /* Disable all access to A_IOCFG for the emu1010 */ } else if (emu->card_capabilities->i2c_adc) { @@ -364,7 +364,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); - + if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Unmute Analog now. Set GPO6 to 1 for Apollo. * This has to be done after init ALice3 I2SOut beyond 48KHz. @@ -378,12 +378,12 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG); } } - + #if 0 { unsigned int tmp; /* FIXME: the following routine disables LiveDrive-II !! */ - // TOSLink detection + /* TOSLink detection */ emu->tos_link = 0; tmp = inl(emu->port + HCFG); if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { @@ -400,7 +400,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); } -int snd_emu10k1_done(struct snd_emu10k1 * emu) +int snd_emu10k1_done(struct snd_emu10k1 *emu) { int ch; @@ -495,7 +495,7 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu) #define EC_LAST_PROMFILE_ADDR 0x2f -#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The +#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The * can be up to 30 characters in length * and is stored as a NULL-terminated * ASCII string. Any unused bytes must be @@ -503,8 +503,8 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu) #define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */ -/* Most of this stuff is pretty self-evident. According to the hardware - * dudes, we need to leave the ADCCAL bit low in order to avoid a DC +/* Most of this stuff is pretty self-evident. According to the hardware + * dudes, we need to leave the ADCCAL bit low in order to avoid a DC * offset problem. Weird. */ #define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | \ @@ -523,7 +523,7 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu) * register. */ -static void snd_emu10k1_ecard_write(struct snd_emu10k1 * emu, unsigned int value) +static void snd_emu10k1_ecard_write(struct snd_emu10k1 *emu, unsigned int value) { unsigned short count; unsigned int data; @@ -561,7 +561,7 @@ static void snd_emu10k1_ecard_write(struct snd_emu10k1 * emu, unsigned int value * channel. */ -static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu, +static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 *emu, unsigned short gain) { unsigned int bit; @@ -574,7 +574,7 @@ static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu, for (bit = (1 << 15); bit; bit >>= 1) { unsigned int value; - + value = emu->ecard_ctrl & ~(EC_TRIM_CSN | EC_TRIM_SDATA); if (gain & bit) @@ -589,7 +589,7 @@ static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 * emu, snd_emu10k1_ecard_write(emu, emu->ecard_ctrl); } -static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_ecard_init(struct snd_emu10k1 *emu) { unsigned int hc_value; @@ -598,7 +598,7 @@ static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu) EC_SPDIF0_SELECT(EC_DEFAULT_SPDIF0_SEL) | EC_SPDIF1_SELECT(EC_DEFAULT_SPDIF1_SEL); - /* Step 0: Set the codec type in the hardware control register + /* Step 0: Set the codec type in the hardware control register * and enable audio output */ hc_value = inl(emu->port + HCFG); outl(hc_value | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S, emu->port + HCFG); @@ -629,7 +629,7 @@ static int snd_emu10k1_ecard_init(struct snd_emu10k1 * emu) return 0; } -static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) { unsigned long special_port; unsigned int value; @@ -656,7 +656,7 @@ 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, const char *filename) { int err; int n, i; @@ -666,11 +666,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file unsigned long flags; const struct firmware *fw_entry; - if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { - snd_printk(KERN_ERR "firmware: %s not found. Err=%d\n",filename, err); + 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); + snd_printk(KERN_INFO "firmware size = 0x%zx\n", fw_entry->size); /* The FPGA is a Xilinx Spartan IIE XC2S50E */ /* GPIO7 -> FPGA PGMN @@ -685,13 +686,13 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ write_post = inl(emu->port + A_IOCFG); udelay(100); /* Allow FPGA memory to clean */ - for(n = 0; n < fw_entry->size; n++) { - value=fw_entry->data[n]; - for(i = 0; i < 8; i++) { + for (n = 0; n < fw_entry->size; n++) { + value = fw_entry->data[n]; + for (i = 0; i < 8; i++) { reg = 0x80; if (value & 0x1) reg = reg | 0x20; - value = value >> 1; + value = value >> 1; outl(reg, emu->port + A_IOCFG); write_post = inl(emu->port + A_IOCFG); outl(reg | 0x40, emu->port + A_IOCFG); @@ -703,14 +704,14 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file write_post = inl(emu->port + A_IOCFG); spin_unlock_irqrestore(&emu->emu_lock, flags); - release_firmware(fw_entry); + release_firmware(fw_entry); return 0; } static int emu1010_firmware_thread(void *data) { - struct snd_emu10k1 * emu = data; - int tmp,tmp2; + struct snd_emu10k1 *emu = data; + int tmp, tmp2; int reg; int err; @@ -719,50 +720,50 @@ static int emu1010_firmware_thread(void *data) msleep_interruptible(1000); if (kthread_should_stop()) break; - 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 */ + 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) { /* Audio Dock attached */ /* 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 ); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { - if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { + err = snd_emu1010_load_firmware(emu, DOCK_FILENAME); + if (err != 0) continue; - } } else if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010B) { - if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { + err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); + if (err != 0) continue; - } } else if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { - if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { + err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); + if (err != 0) continue; - } } - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 ); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ® ); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", reg); /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); + snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg); if ((reg & 0x1f) != 0x15) { /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); + snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", reg); continue; } snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); - snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2 ); - snd_printk("Audio Dock ver:%d.%d\n",tmp ,tmp2); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2); + snd_printk("Audio Dock ver:%d.%d\n", tmp, tmp2); /* Sync clocking between 1010 and Dock */ /* Allow DLL to settle */ msleep(10); /* Unmute all. Default is muted after a firmware load */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); } } snd_printk(KERN_INFO "emu1010: firmware thread stopping\n"); @@ -800,10 +801,10 @@ static int emu1010_firmware_thread(void *data) * 16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops * 16 x 32-bit capture - snd_emu10k1_capture_efx_ops */ -static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) +static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) { unsigned int i; - int tmp,tmp2; + int tmp, tmp2; int reg; int err; const char *filename = NULL; @@ -818,7 +819,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) * Lock Tank Memory Cache, * Mute all codecs. */ - outl(0x0005a004, emu->port + HCFG); + outl(0x0005a004, emu->port + HCFG); /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, * Mute all codecs. */ @@ -829,25 +830,25 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) outl(0x0005a000, emu->port + HCFG); /* Disable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); - snd_printdd("reg1=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); + snd_printdd("reg1 = 0x%x\n", reg); if ((reg & 0x3f) == 0x15) { /* FPGA netlist already present so clear it */ /* Return to programming mode */ - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02 ); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02); } - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); - snd_printdd("reg2=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); + snd_printdd("reg2 = 0x%x\n", reg); if ((reg & 0x3f) == 0x15) { /* FPGA failed to return to programming mode */ snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n"); return -ENODEV; } - snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); + 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; @@ -876,25 +877,25 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) } /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ® ); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); if ((reg & 0x3f) != 0x15) { /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg); + snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg); return -ENODEV; } snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp ); - snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2 ); - snd_printk("Hana ver:%d.%d\n",tmp ,tmp2); + snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp); + snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2); + snd_printk("emu1010: Hana version: %d.%d\n", tmp, tmp2); /* Enable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); - snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); - snd_printk(KERN_INFO "emu1010: Card options=0x%x\n",reg); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); + snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); + snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp); /* Optical -> ADAT I/O */ /* 0 : SPDIF * 1 : ADAT @@ -904,41 +905,42 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) tmp = 0; tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); - snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp ); - snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); + snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp); /* Set no attenuation on Audio Dock pads. */ - snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00 ); + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00); emu->emu1010.adc_pads = 0x00; - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp); /* Unmute Audio dock DACs, Headphone source DAC-4. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); - snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); + snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp); /* DAC PADs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f ); + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f); emu->emu1010.dac_pads = 0x0f; - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp ); - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30 ); - snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); + snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30); + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ - snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* MIDI routing */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* Unknown. */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); - /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); // IRQ Enable: All on */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); + /* IRQ Enable: Alll on */ + /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); */ /* IRQ Enable: All off */ - snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00 ); + snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ® ); - snd_printk(KERN_INFO "emu1010: Card options3=0x%x\n",reg); + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); + snd_printk(KERN_INFO "emu1010: Card options3 = 0x%x\n", reg); /* Default WCLK set to 48kHz. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00); /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); - //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); + /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ /* Audio Dock LEDs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); #if 0 /* For 96kHz */ @@ -992,7 +994,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) * Defaults only, users will set their own values anyways, let's * just copy/paste. */ - + snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1); snd_emu1010_fpga_link_dst_src_write(emu, @@ -1037,19 +1039,19 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2); #endif - for (i = 0;i < 0x20; i++ ) { - /* AudioDock Elink <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0100+i, EMU_SRC_SILENCE); + for (i = 0; i < 0x20; i++) { + /* AudioDock Elink <- Silence */ + snd_emu1010_fpga_link_dst_src_write(emu, 0x0100 + i, EMU_SRC_SILENCE); } - for (i = 0;i < 4; i++) { + for (i = 0; i < 4; i++) { /* Hana SPDIF Out <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0200+i, EMU_SRC_SILENCE); + snd_emu1010_fpga_link_dst_src_write(emu, 0x0200 + i, EMU_SRC_SILENCE); } - for (i = 0;i < 7; i++) { + for (i = 0; i < 7; i++) { /* Hamoa DAC <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0300+i, EMU_SRC_SILENCE); + snd_emu1010_fpga_link_dst_src_write(emu, 0x0300 + i, EMU_SRC_SILENCE); } - for (i = 0;i < 7; i++) { + for (i = 0; i < 7; i++) { /* Hana ADAT Out <- Silence */ snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE); } @@ -1065,30 +1067,30 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1); snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1); - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01 ); // Unmute all + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01); /* Unmute all */ + + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); - /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, * Lock Sound Memory Cache, Lock Tank Memory Cache, * Mute all codecs. */ - outl(0x0000a000, emu->port + HCFG); + outl(0x0000a000, emu->port + HCFG); /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, * Lock Sound Memory Cache, Lock Tank Memory Cache, * Un-Mute all codecs. */ outl(0x0000a001, emu->port + HCFG); - + /* Initial boot complete. Now patches */ - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp ); - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19 ); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c ); /* Unknown */ - snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp ); - snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */ + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */ + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ /* Start Micro/Audio Dock firmware loader thread */ if (!emu->emu1010.firmware_thread) { @@ -1218,20 +1220,20 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) emu->emu1010.output_source[23] = 28; } /* TEMP: Select SPDIF in/out */ - //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ + /* snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); */ /* Output spdif */ /* TEMP: Select 48kHz SPDIF out */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */ /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K ); - //snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X ); + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); + /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ emu->emu1010.internal_clock = 1; /* 48000 */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12);/* Set LEDs on Audio Dock */ + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); /* Set LEDs on Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ - //snd_emu1010_fpga_write(emu, 0x7, 0x0); /* Mute all */ - //snd_emu1010_fpga_write(emu, 0x7, 0x1); /* Unmute all */ - //snd_emu1010_fpga_write(emu, 0xe, 0x12); /* Set LEDs on Audio Dock */ + /* snd_emu1010_fpga_write(emu, 0x7, 0x0); */ /* Mute all */ + /* snd_emu1010_fpga_write(emu, 0x7, 0x1); */ /* Unmute all */ + /* snd_emu1010_fpga_write(emu, 0xe, 0x12); */ /* Set LEDs on Audio Dock */ return 0; } @@ -1247,13 +1249,13 @@ static void free_pm_buffer(struct snd_emu10k1 *emu); static int snd_emu10k1_free(struct snd_emu10k1 *emu) { if (emu->port) { /* avoid access to already used hardware */ - snd_emu10k1_fx8010_tram_setup(emu, 0); + snd_emu10k1_fx8010_tram_setup(emu, 0); snd_emu10k1_done(emu); snd_emu10k1_free_efx(emu); - } + } if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { /* Disable 48Volt power to Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); } if (emu->emu1010.firmware_thread) kthread_stop(emu->emu1010.firmware_thread); @@ -1278,7 +1280,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) #endif if (emu->port) pci_release_regions(emu->pci); - if (emu->card_capabilities->ca0151_chip) /* P16V */ + if (emu->card_capabilities->ca0151_chip) /* P16V */ snd_p16v_free(emu); pci_disable_device(emu->pci); kfree(emu); @@ -1704,13 +1706,13 @@ static struct snd_emu_chip_details emu_chip_details[] = { }; int __devinit snd_emu10k1_create(struct snd_card *card, - struct pci_dev * pci, + struct pci_dev *pci, unsigned short extin_mask, unsigned short extout_mask, long max_cache_bytes, int enable_ir, uint subsystem, - struct snd_emu10k1 ** remu) + struct snd_emu10k1 **remu) { struct snd_emu10k1 *emu; int idx, err; @@ -1720,11 +1722,12 @@ int __devinit snd_emu10k1_create(struct snd_card *card, static struct snd_device_ops ops = { .dev_free = snd_emu10k1_dev_free, }; - + *remu = NULL; /* enable PCI device */ - if ((err = pci_enable_device(pci)) < 0) + err = pci_enable_device(pci); + if (err < 0) return err; emu = kzalloc(sizeof(*emu), GFP_KERNEL); @@ -1751,16 +1754,17 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); - snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model); + snd_printdd("vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", pci->vendor, pci->device, emu->serial, emu->model); for (c = emu_chip_details; c->vendor; c++) { if (c->vendor == pci->vendor && c->device == pci->device) { if (subsystem) { - if (c->subsystem && (c->subsystem == subsystem) ) { + if (c->subsystem && (c->subsystem == subsystem)) break; - } else continue; + else + continue; } else { - if (c->subsystem && (c->subsystem != emu->serial) ) + if (c->subsystem && (c->subsystem != emu->serial)) continue; if (c->revision && c->revision != emu->revision) continue; @@ -1776,14 +1780,18 @@ int __devinit snd_emu10k1_create(struct snd_card *card, } emu->card_capabilities = c; if (c->subsystem && !subsystem) - snd_printdd("Sound card name=%s\n", c->name); - else if (subsystem) - snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x. Forced to subsytem=0x%x\n", - c->name, pci->vendor, pci->device, emu->serial, c->subsystem); - else - snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x.\n", - c->name, pci->vendor, pci->device, emu->serial); - + snd_printdd("Sound card name = %s\n", c->name); + else if (subsystem) + snd_printdd("Sound card name = %s, " + "vendor = 0x%x, device = 0x%x, subsystem = 0x%x. " + "Forced to subsytem = 0x%x\n", c->name, + pci->vendor, pci->device, emu->serial, c->subsystem); + else + snd_printdd("Sound card name = %s, " + "vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n", + c->name, pci->vendor, pci->device, + emu->serial); + if (!*card->id && c->id) { int i, n = 0; strlcpy(card->id, c->id, sizeof(card->id)); @@ -1817,7 +1825,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card, else emu->gpr_base = FXGPREGBASE; - if ((err = pci_request_regions(pci, "EMU10K1")) < 0) { + err = pci_request_regions(pci, "EMU10K1"); + if (err < 0) { kfree(emu); pci_disable_device(pci); return err; @@ -1864,21 +1873,25 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->enable_ir = enable_ir; if (emu->card_capabilities->ca_cardbus_chip) { - if ((err = snd_emu10k1_cardbus_init(emu)) < 0) + err = snd_emu10k1_cardbus_init(emu); + if (err < 0) goto error; } if (emu->card_capabilities->ecard) { - if ((err = snd_emu10k1_ecard_init(emu)) < 0) + err = snd_emu10k1_ecard_init(emu); + if (err < 0) goto error; } else if (emu->card_capabilities->emu_model) { - if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { - snd_emu10k1_free(emu); - return err; - } + err = snd_emu10k1_emu1010_init(emu); + if (err < 0) { + snd_emu10k1_free(emu); + return err; + } } else { /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version does not support this, it shouldn't do any harm */ - snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); + snd_emu10k1_ptr_write(emu, AC97SLOT, 0, + AC97SLOT_CNTR|AC97SLOT_LFE); } /* initialize TRAM setup */ @@ -1918,7 +1931,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, snd_emu10k1_synth_alloc(emu, 4096); if (emu->reserved_page) emu->reserved_page->map_locked = 1; - + /* Clear silent pages and set up pointers */ memset(emu->silent_page.area, 0, PAGE_SIZE); silent_page = emu->silent_page.addr << 1; @@ -1931,19 +1944,23 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->voices[idx].number = idx; } - if ((err = snd_emu10k1_init(emu, enable_ir, 0)) < 0) + err = snd_emu10k1_init(emu, enable_ir, 0); + if (err < 0) goto error; #ifdef CONFIG_PM - if ((err = alloc_pm_buffer(emu)) < 0) + err = alloc_pm_buffer(emu); + if (err < 0) goto error; #endif /* Initialize the effect engine */ - if ((err = snd_emu10k1_init_efx(emu)) < 0) + err = snd_emu10k1_init_efx(emu); + if (err < 0) goto error; snd_emu10k1_audio_enable(emu); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0) + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops); + if (err < 0) goto error; #ifdef CONFIG_PROC_FS @@ -1983,7 +2000,7 @@ static int __devinit alloc_pm_buffer(struct snd_emu10k1 *emu) if (emu->audigy) size += ARRAY_SIZE(saved_regs_audigy); emu->saved_ptr = vmalloc(4 * NUM_G * size); - if (! emu->saved_ptr) + if (!emu->saved_ptr) return -ENOMEM; if (snd_emu10k1_efx_alloc_pm_buffer(emu) < 0) return -ENOMEM; @@ -2028,7 +2045,7 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) if (emu->card_capabilities->ecard) snd_emu10k1_ecard_init(emu); else if (emu->card_capabilities->emu_model) - snd_emu10k1_emu1010_init(emu); + snd_emu10k1_emu1010_init(emu); else snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); snd_emu10k1_init(emu, emu->enable_ir, 1); From bbaf5e97337287479eb78dbc3822d9560bbfd2e2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Oct 2008 18:16:50 +0200 Subject: [PATCH 023/367] ALSA: Add hrtimer backend for ALSA timer interface Added the hrtimer backend for ALSA timer interface. It can be used for the sequencer timer source. Signed-off-by: Takashi Iwai --- include/sound/asound.h | 1 + sound/core/Kconfig | 21 +++++++ sound/core/Makefile | 2 + sound/core/hrtimer.c | 140 +++++++++++++++++++++++++++++++++++++++++ sound/core/seq/seq.c | 4 +- 5 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 sound/core/hrtimer.c diff --git a/include/sound/asound.h b/include/sound/asound.h index 2c4dc908a54a..1c02ed1d7c4a 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -575,6 +575,7 @@ enum { #define SNDRV_TIMER_GLOBAL_SYSTEM 0 #define SNDRV_TIMER_GLOBAL_RTC 1 #define SNDRV_TIMER_GLOBAL_HPET 2 +#define SNDRV_TIMER_GLOBAL_HRTIMER 3 /* info flags */ #define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */ diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 66348c92f88d..406a45010985 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -95,6 +95,26 @@ config SND_SEQUENCER_OSS this will be compiled as a module. The module will be called snd-seq-oss. +config SND_HRTIMER + tristate "HR-timer backend support" + depends on HIGH_RES_TIMERS + select SND_TIMER + help + Say Y here to enable HR-timer backend for ALSA timer. ALSA uses + the hrtimer as a precise timing source. The ALSA sequencer code + also can use this timing source. + + To compile this driver as a module, choose M here: the module + will be called snd-hrtimer. + +config SND_SEQ_HRTIMER_DEFAULT + bool "Use HR-timer as default sequencer timer" + depends on SND_HRTIMER && SND_SEQUENCER + default y + help + Say Y here to use the HR-timer backend as the default sequencer + timer. + config SND_RTCTIMER tristate "RTC Timer support" depends on RTC @@ -114,6 +134,7 @@ config SND_RTCTIMER config SND_SEQ_RTCTIMER_DEFAULT bool "Use RTC as default sequencer timer" depends on SND_RTCTIMER && SND_SEQUENCER + dpeends on !SND_SEQ_HRTIMER_DEFAULT default y help Say Y here to use the RTC timer as the default sequencer diff --git a/sound/core/Makefile b/sound/core/Makefile index d57125a5687d..4229052e7b91 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -17,12 +17,14 @@ snd-page-alloc-$(CONFIG_HAS_DMA) += sgbuf.o snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o +snd-hrtimer-objs := hrtimer.o snd-rtctimer-objs := rtctimer.o snd-hwdep-objs := hwdep.o obj-$(CONFIG_SND) += snd.o obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o obj-$(CONFIG_SND_TIMER) += snd-timer.o +obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c new file mode 100644 index 000000000000..b712d7f211ff --- /dev/null +++ b/sound/core/hrtimer.c @@ -0,0 +1,140 @@ +/* + */ + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Takashi Iwai "); +MODULE_DESCRIPTION("ALSA hrtimer backend"); +MODULE_LICENSE("GPL"); + +MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_HRTIMER)); + +#define NANO_SEC 1000000000UL /* 10^9 in sec */ +static unsigned int resolution; + +struct snd_hrtimer { + struct snd_timer *timer; + struct hrtimer hrt; +}; + +static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) +{ + struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); + struct snd_timer *t = stime->timer; + hrtimer_forward_now(hrt, ktime_set(0, t->sticks * resolution)); + snd_timer_interrupt(stime->timer, t->sticks); + return HRTIMER_RESTART; +} + +static int snd_hrtimer_open(struct snd_timer *t) +{ + struct snd_hrtimer *stime; + + stime = kmalloc(sizeof(*stime), GFP_KERNEL); + if (!stime) + return -ENOMEM; + hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + stime->timer = t; + stime->hrt.cb_mode = HRTIMER_CB_SOFTIRQ; + stime->hrt.function = snd_hrtimer_callback; + t->private_data = stime; + return 0; +} + +static int snd_hrtimer_close(struct snd_timer *t) +{ + struct snd_hrtimer *stime = t->private_data; + + if (stime) { + hrtimer_cancel(&stime->hrt); + kfree(stime); + t->private_data = NULL; + } + return 0; +} + +static int snd_hrtimer_start(struct snd_timer *t) +{ + struct snd_hrtimer *stime = t->private_data; + + hrtimer_start(&stime->hrt, ktime_set(0, t->sticks * resolution), + HRTIMER_MODE_REL); + return 0; +} + +static int snd_hrtimer_stop(struct snd_timer *t) +{ + struct snd_hrtimer *stime = t->private_data; + + hrtimer_cancel(&stime->hrt); + return 0; +} + +static struct snd_timer_hardware hrtimer_hw = { + .flags = (SNDRV_TIMER_HW_AUTO | + /*SNDRV_TIMER_HW_FIRST |*/ + SNDRV_TIMER_HW_TASKLET), + .open = snd_hrtimer_open, + .close = snd_hrtimer_close, + .start = snd_hrtimer_start, + .stop = snd_hrtimer_stop, +}; + +/* + * entry functions + */ + +static struct snd_timer *mytimer; + +static int __init snd_hrtimer_init(void) +{ + struct snd_timer *timer; + struct timespec tp; + int err; + + hrtimer_get_res(CLOCK_MONOTONIC, &tp); + if (tp.tv_sec > 0 || !tp.tv_nsec) { + snd_printk(KERN_ERR + "snd-hrtimer: Invalid resolution %u.%09u", + (unsigned)tp.tv_sec, (unsigned)tp.tv_nsec); + return -EINVAL; + } + resolution = tp.tv_nsec; + + /* Create a new timer and set up the fields */ + err = snd_timer_global_new("hrtimer", SNDRV_TIMER_GLOBAL_HRTIMER, + &timer); + if (err < 0) + return err; + + timer->module = THIS_MODULE; + strcpy(timer->name, "HR timer"); + timer->hw = hrtimer_hw; + timer->hw.resolution = resolution; + timer->hw.ticks = NANO_SEC / resolution; + + err = snd_timer_global_register(timer); + if (err < 0) { + snd_timer_global_free(timer); + return err; + } + mytimer = timer; /* remember this */ + + return 0; +} + +static void __exit snd_hrtimer_exit(void) +{ + if (mytimer) { + snd_timer_global_free(mytimer); + mytimer = NULL; + } +} + +module_init(snd_hrtimer_init); +module_exit(snd_hrtimer_exit); diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index ee0f8405ab35..bf09a5ad1865 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -43,7 +43,9 @@ int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL; int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE; int seq_default_timer_card = -1; int seq_default_timer_device = -#ifdef CONFIG_SND_SEQ_RTCTIMER_DEFAULT +#ifdef CONFIG_SND_SEQ_HRTIMER_DEFAULT + SNDRV_TIMER_GLOBAL_HRTIMER +#elif defined(CONFIG_SND_SEQ_RTCTIMER_DEFAULT) SNDRV_TIMER_GLOBAL_RTC #else SNDRV_TIMER_GLOBAL_SYSTEM From 282cd76ffca781013151344c4b0f9229e9ea3c35 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 25 Oct 2008 01:05:29 -0400 Subject: [PATCH 024/367] ALSA: hda: dynamic jack id This patch duplicates the jack->id pointer with kstrdup() to prevent scoping issues from calling autoprobing functions from the HDA section. Signed-off-by: Matthew Ranostay Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/core/jack.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/core/jack.c b/sound/core/jack.c index c4bb9bad3133..438445f77d6d 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -34,6 +34,7 @@ static int snd_jack_dev_free(struct snd_device *device) else input_free_device(jack->input_dev); + kfree(jack->id); kfree(jack); return 0; @@ -87,7 +88,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (jack == NULL) return -ENOMEM; - jack->id = id; + jack->id = kstrdup(id, GFP_KERNEL); jack->input_dev = input_allocate_device(); if (jack->input_dev == NULL) { From a53ccab3ccac9e8676a683df9822a2daec83ef54 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 25 Oct 2008 01:05:04 -0400 Subject: [PATCH 025/367] ALSA: jack: lineout support to jack abstraction layer This patch introduces support for reporting SW_LINEOUT_INSERT detection events via the jack abstraction layer. Also adds a SND_JACK_LINEOUT define to the input system header. Signed-off-by: Matthew Ranostay Cc: Dmitry Torokhov Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- include/linux/input.h | 1 + include/sound/jack.h | 1 + sound/core/jack.c | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/include/linux/input.h b/include/linux/input.h index a5802c9c81a4..7323d2ff5151 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -644,6 +644,7 @@ struct input_absinfo { #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ +#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) diff --git a/include/sound/jack.h b/include/sound/jack.h index b1b2b8b59adb..7cb25f4b50bb 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -35,6 +35,7 @@ enum snd_jack_types { SND_JACK_HEADPHONE = 0x0001, SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, + SND_JACK_LINEOUT = 0x0004, }; struct snd_jack { diff --git a/sound/core/jack.c b/sound/core/jack.c index 8133a2b173a5..c4bb9bad3133 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -102,6 +102,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (type & SND_JACK_HEADPHONE) input_set_capability(jack->input_dev, EV_SW, SW_HEADPHONE_INSERT); + if (type & SND_JACK_LINEOUT) + input_set_capability(jack->input_dev, EV_SW, + SW_LINEOUT_INSERT); if (type & SND_JACK_MICROPHONE) input_set_capability(jack->input_dev, EV_SW, SW_MICROPHONE_INSERT); @@ -150,6 +153,9 @@ void snd_jack_report(struct snd_jack *jack, int status) if (jack->type & SND_JACK_HEADPHONE) input_report_switch(jack->input_dev, SW_HEADPHONE_INSERT, status & SND_JACK_HEADPHONE); + if (jack->type & SND_JACK_LINEOUT) + input_report_switch(jack->input_dev, SW_LINEOUT_INSERT, + status & SND_JACK_LINEOUT); if (jack->type & SND_JACK_MICROPHONE) input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, status & SND_JACK_MICROPHONE); From 50a9f7905fb3e6ae25e80ba443a14d878caef0c9 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 25 Oct 2008 01:05:45 -0400 Subject: [PATCH 026/367] ALSA: hda: add snd_hda_get_jack* functions This patch adds snd_hda_get_jack* functions for reporting jack location, device, and connectivity type. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 46 +++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_codec.h | 7 ++++++ sound/pci/hda/hda_proc.c | 39 +++------------------------------ 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9a8adc600a57..eaa8b5676eae 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -107,6 +107,52 @@ static void hda_keep_power_on(struct hda_codec *codec); static inline void hda_keep_power_on(struct hda_codec *codec) {} #endif +const char *snd_hda_get_jack_location(u32 cfg) +{ + static char *bases[7] = { + "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", + }; + static unsigned char specials_idx[] = { + 0x07, 0x08, + 0x17, 0x18, 0x19, + 0x37, 0x38 + }; + static char *specials[] = { + "Rear Panel", "Drive Bar", + "Riser", "HDMI", "ATAPI", + "Mobile-In", "Mobile-Out" + }; + int i; + cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; + if ((cfg & 0x0f) < 7) + return bases[cfg & 0x0f]; + for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { + if (cfg == specials_idx[i]) + return specials[i]; + } + return "UNKNOWN"; +} + +const char *snd_hda_get_jack_connectivity(u32 cfg) +{ + static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; + + return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; +} + +const char *snd_hda_get_jack_type(u32 cfg) +{ + static char *jack_types[16] = { + "Line Out", "Speaker", "HP Out", "CD", + "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", + "Line In", "Aux", "Mic", "Telephony", + "SPDIF In", "Digitial In", "Reserved", "Other" + }; + + return jack_types[(cfg & AC_DEFCFG_DEVICE) + >> AC_DEFCFG_DEVICE_SHIFT]; +} + /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index a77ba223af40..c5f91c918d19 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -859,6 +859,13 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); int snd_hda_resume(struct hda_bus *bus); #endif +/* + * get widget information + */ +const char *snd_hda_get_jack_connectivity(u32 cfg); +const char *snd_hda_get_jack_type(u32 cfg); +const char *snd_hda_get_jack_location(u32 cfg); + /* * power saving */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 64ab19f14f79..b36d4d06485d 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -145,32 +145,6 @@ static void print_pcm_caps(struct snd_info_buffer *buffer, print_pcm_formats(buffer, stream); } -static const char *get_jack_location(u32 cfg) -{ - static char *bases[7] = { - "N/A", "Rear", "Front", "Left", "Right", "Top", "Bottom", - }; - static unsigned char specials_idx[] = { - 0x07, 0x08, - 0x17, 0x18, 0x19, - 0x37, 0x38 - }; - static char *specials[] = { - "Rear Panel", "Drive Bar", - "Riser", "HDMI", "ATAPI", - "Mobile-In", "Mobile-Out" - }; - int i; - cfg = (cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT; - if ((cfg & 0x0f) < 7) - return bases[cfg & 0x0f]; - for (i = 0; i < ARRAY_SIZE(specials_idx); i++) { - if (cfg == specials_idx[i]) - return specials[i]; - } - return "UNKNOWN"; -} - static const char *get_jack_connection(u32 cfg) { static char *names[16] = { @@ -206,13 +180,6 @@ static void print_pin_caps(struct snd_info_buffer *buffer, int *supports_vref) { static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; - static char *jack_types[16] = { - "Line Out", "Speaker", "HP Out", "CD", - "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", - "Line In", "Aux", "Mic", "Telephony", - "SPDIF In", "Digitial In", "Reserved", "Other" - }; - static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; unsigned int caps, val; caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); @@ -274,9 +241,9 @@ static void print_pin_caps(struct snd_info_buffer *buffer, caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], - jack_types[(caps & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT], - jack_locations[(caps >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3], - get_jack_location(caps)); + snd_hda_get_jack_type(caps), + snd_hda_get_jack_connectivity(caps), + snd_hda_get_jack_location(caps)); snd_iprintf(buffer, " Conn = %s, Color = %s\n", get_jack_connection(caps), get_jack_color(caps)); From 74aeaabc3e452b29bc1b9eac5aa48923569f8a4e Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 25 Oct 2008 01:06:04 -0400 Subject: [PATCH 027/367] ALSA: hda: add support for jack detection on IDT codecs. This patch adds support to the IDT codec families to report jack status to the jack abstraction layer. This required some reorganization in the stac92xx_unsol_event function in which the index value is changed to reporting the nid with the event. Also adds an sigmatel_jack struct to keep track of the nid relation to the jack abstraction layer instance. Also adds functions to set and retrieve data values for each nid, this is used in stac92xx_unsol_event to retrieve the GPIO mask for STAC_VREF_EVENT. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 203 +++++++++++++++++++++++++++------ 1 file changed, 170 insertions(+), 33 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d106ea52a90d..c24d22fddd09 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -36,6 +36,7 @@ #include "hda_patch.h" #include "hda_beep.h" +#define STAC_INSERT_EVENT 0x10 #define STAC_PWR_EVENT 0x20 #define STAC_HP_EVENT 0x30 #define STAC_VREF_EVENT 0x40 @@ -129,6 +130,17 @@ enum { STAC_927X_MODELS }; +struct sigmatel_event { + hda_nid_t nid; + int data; +}; + +struct sigmatel_jack { + hda_nid_t nid; + int type; + struct snd_jack *jack; +}; + struct sigmatel_spec { struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; @@ -161,6 +173,12 @@ struct sigmatel_spec { hda_nid_t *pwr_nids; hda_nid_t *dac_list; + /* jack detection */ + struct snd_array jacks; + + /* events */ + struct snd_array events; + /* playback */ struct hda_input_mux *mono_mux; struct hda_input_mux *amp_mux; @@ -216,9 +234,6 @@ struct sigmatel_spec { struct hda_pcm pcm_rec[2]; /* PCM information */ - /* jack detection */ - struct snd_jack *jack; - /* dynamic controls and input_mux */ struct auto_pin_cfg autocfg; struct snd_array kctls; @@ -2458,13 +2473,15 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int nid = cfg->hp_pins[cfg->hp_outs - 1]; spec->hp_switch = ucontrol->value.integer.value[0]; /* check to be sure that the ports are upto date with * switch changes */ - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26); return 1; } @@ -2504,7 +2521,8 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ * appropriately according to the pin direction */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + codec->patch_ops.unsol_event(codec, + (STAC_HP_EVENT | nid) << 26); return 1; } @@ -3574,13 +3592,70 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ } +static int stac92xx_add_jack(struct hda_codec *codec, + hda_nid_t nid, int type) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_jack *jack; + int def_conf = snd_hda_codec_read(codec, nid, + 0, AC_VERB_GET_CONFIG_DEFAULT, 0); + int connectivity = get_defcfg_connect(def_conf); + char name[32]; + + if (connectivity && connectivity != AC_JACK_PORT_FIXED) + return 0; + + snd_array_init(&spec->jacks, sizeof(*jack), 32); + jack = snd_array_new(&spec->jacks); + if (!jack) + return -ENOMEM; + jack->nid = nid; + jack->type = type; + + sprintf(name, "%s at %s %s Jack", + snd_hda_get_jack_type(def_conf), + snd_hda_get_jack_connectivity(def_conf), + snd_hda_get_jack_location(def_conf)); + + return snd_jack_new(codec->bus->card, name, type, &jack->jack); +} + +static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, + int data) +{ + struct sigmatel_event *event; + + snd_array_init(&spec->events, sizeof(*event), 32); + event = snd_array_new(&spec->events); + if (!event) + return -ENOMEM; + event->nid = nid; + event->data = data; + + return 0; +} + +static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_event *events = spec->events.list; + if (events) { + int i; + for (i = 0; i < spec->events.used; i++) + if (events[i].nid == nid) + return events[i].data; + } + return 0; +} + static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, unsigned int event) { - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) + if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event)); + (AC_USRSP_EN | event | nid)); + } } static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) @@ -3623,27 +3698,36 @@ static int stac92xx_init(struct hda_codec *codec) /* set up pins */ if (spec->hp_detect) { /* Enable unsolicited responses on the HP widget */ - for (i = 0; i < cfg->hp_outs; i++) - enable_pin_detect(codec, cfg->hp_pins[i], - STAC_HP_EVENT); + for (i = 0; i < cfg->hp_outs; i++) { + int type = SND_JACK_HEADPHONE; + hda_nid_t nid = cfg->hp_pins[i]; + enable_pin_detect(codec, nid, STAC_HP_EVENT | nid); + /* jack detection */ + if (cfg->hp_outs == i) + type |= SND_JACK_LINEOUT; + err = stac92xx_add_jack(codec, nid, type); + if (err < 0) + return err; + + } /* 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); - stac92xx_auto_init_hp_out(codec); - /* jack detection */ - err = snd_jack_new(codec->bus->card, - "Headphone Jack", - SND_JACK_HEADPHONE, &spec->jack); - if (err < 0) - return err; + AC_PINCTL_OUT_EN); /* fake event to set up pins */ - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + codec->patch_ops.unsol_event(codec, + (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); } else { stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); } + for (i = 0; i < cfg->line_outs; i++) { + err = stac92xx_add_jack(codec, + cfg->line_out_pins[i], SND_JACK_LINEOUT); + if (err < 0) + return err; + } for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = cfg->input_pins[i]; if (nid) { @@ -3656,6 +3740,11 @@ static int stac92xx_init(struct hda_codec *codec) if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) pinctl |= stac92xx_get_vref(codec, nid); stac92xx_auto_set_pinctl(codec, nid, pinctl); + err = stac92xx_add_jack(codec, nid, + SND_JACK_MICROPHONE); + if (err < 0) + return err; + enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid); } } for (i = 0; i < spec->num_dmics; i++) @@ -3697,6 +3786,18 @@ static int stac92xx_init(struct hda_codec *codec) return 0; } +static void stac92xx_free_jacks(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + if (spec->jacks.list) { + struct sigmatel_jack *jacks = spec->jacks.list; + int i; + for (i = 0; i < spec->jacks.used; i++) + snd_device_free(codec->bus->card, &jacks[i].jack); + } + snd_array_free(&spec->jacks); +} + static void stac92xx_free_kctls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -3717,11 +3818,10 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; - if (spec->jack) - snd_device_free(codec->bus->card, spec->jack); - if (spec->bios_pin_configs) kfree(spec->bios_pin_configs); + stac92xx_free_jacks(codec); + snd_array_free(&spec->events); kfree(spec); snd_hda_detach_beep_device(codec); @@ -3804,8 +3904,6 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) break; presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); } - snd_jack_report(spec->jack, - presence ? SND_JACK_HEADPHONE : 0); if (presence) { /* disable lineouts, enable hp */ @@ -3862,24 +3960,57 @@ static void stac92xx_pin_sense(struct hda_codec *codec, int idx) /* power down unused output ports */ snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); -}; +} + +static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_jack *jacks = spec->jacks.list; + + if (jacks) { + int i; + for (i = 0; i < spec->jacks.used; i++) { + if (jacks->nid == nid) { + unsigned int pin_ctl = + snd_hda_codec_read(codec, nid, + 0, AC_VERB_GET_PIN_WIDGET_CONTROL, + 0x00); + int type = jacks->type; + if (type == (SND_JACK_LINEOUT + | SND_JACK_HEADPHONE)) + type = (pin_ctl & AC_PINCTL_HP_EN) + ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT; + snd_jack_report(jacks->jack, + get_hp_pin_presence(codec, nid) + ? type : 0); + } + jacks++; + } + } +} static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; - int idx = res >> 26 & 0x0f; + int event = (res >> 26) & 0x70; + int nid = res >> 26 & 0x0f; - switch ((res >> 26) & 0x70) { + switch (event) { case STAC_HP_EVENT: stac92xx_hp_detect(codec, res); /* fallthru */ + case STAC_INSERT_EVENT: case STAC_PWR_EVENT: - if (spec->num_pwrs > 0) - stac92xx_pin_sense(codec, idx); + if (nid) { + if (spec->num_pwrs > 0) + stac92xx_pin_sense(codec, nid); + stac92xx_report_jack(codec, nid); + } break; case STAC_VREF_EVENT: { int data = snd_hda_codec_read(codec, codec->afg, 0, AC_VERB_GET_GPIO_DATA, 0); + int idx = stac92xx_event_data(codec, nid); /* toggle VREF state based on GPIOx status */ snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, !!(data & (1 << idx))); @@ -4402,8 +4533,11 @@ again: snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_VREF_EVENT | 0x01)); + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); + err = stac92xx_add_event(spec, codec->afg, 0x02); + if (err < 0) + return err; spec->gpio_mask |= 0x02; break; } @@ -4802,8 +4936,11 @@ static int patch_stac9205(struct hda_codec *codec) snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_HP_EVENT)); + AC_VERB_SET_UNSOLICITED_ENABLE, + (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); + err = stac92xx_add_event(spec, codec->afg, 0x01); + if (err < 0) + return err; spec->gpio_dir = 0x0b; spec->eapd_mask = 0x01; From 34c25350acfc792747e861d1e36874abf7e73255 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Oct 2008 11:38:58 +0100 Subject: [PATCH 028/367] ALSA: hda - Remove old codec-probe limitation Removed the old workaround to avoid the non-existing codec slot. The current code should work without that workaround. If any, we can add a quirk table. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 7b0abf08a583..a13169cc95a2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1191,21 +1191,12 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { [AZX_DRIVER_TERA] = 1, }; -/* number of slots to probe as default - * this can be different from azx_max_codecs[] -- e.g. some boards - * report wrongly the non-existing 4th slot availability - */ -static unsigned int azx_default_codecs[AZX_NUM_DRIVERS] __devinitdata = { - [AZX_DRIVER_ICH] = 3, - [AZX_DRIVER_ATI] = 3, -}; - static int __devinit azx_codec_create(struct azx *chip, const char *model, unsigned int codec_probe_mask) { struct hda_bus_template bus_temp; - int c, codecs, audio_codecs, err; - int def_slots, max_slots; + int c, codecs, err; + int max_slots; memset(&bus_temp, 0, sizeof(bus_temp)); bus_temp.private_data = chip; @@ -1225,33 +1216,17 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, if (chip->driver_type == AZX_DRIVER_NVIDIA) chip->bus->needs_damn_long_delay = 1; - codecs = audio_codecs = 0; + codecs = 0; max_slots = azx_max_codecs[chip->driver_type]; if (!max_slots) max_slots = AZX_MAX_CODECS; - def_slots = azx_default_codecs[chip->driver_type]; - if (!def_slots) - def_slots = max_slots; - for (c = 0; c < def_slots; c++) { + for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { struct hda_codec *codec; err = snd_hda_codec_new(chip->bus, c, &codec); if (err < 0) continue; codecs++; - if (codec->afg) - audio_codecs++; - } - } - if (!audio_codecs) { - /* probe additional slots if no codec is found */ - for (; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { - err = snd_hda_codec_new(chip->bus, c, NULL); - if (err < 0) - continue; - codecs++; - } } } if (!codecs) { From d301fc320f3e673a49200d9ce51036caa9abd768 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Oct 2008 08:15:30 +0100 Subject: [PATCH 029/367] ALSA: hda - Fix indentation in hda_local.h Just cosmetic fixes of spacing that annoyed me. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_local.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 4a08c31b498a..aac569b05599 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -366,17 +366,17 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) #define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) -#define AMP_OUT_MUTE 0xb080 -#define AMP_OUT_UNMUTE 0xb000 -#define AMP_OUT_ZERO 0xb000 +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define AMP_OUT_ZERO 0xb000 /* pinctl values */ #define PIN_IN (AC_PINCTL_IN_EN) -#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ) +#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ) #define PIN_VREF50 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50) -#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD) +#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD) #define PIN_VREF80 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80) -#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100) -#define PIN_OUT (AC_PINCTL_OUT_EN) +#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100) +#define PIN_OUT (AC_PINCTL_OUT_EN) #define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN) #define PIN_HP_AMP (AC_PINCTL_HP_EN) From 9cbbb3ac628227ec5b65fc043539949db606cd17 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 29 Oct 2008 13:41:35 +0100 Subject: [PATCH 030/367] ALSA: Release v1.0.18 Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/version.h b/include/sound/version.h index 4aafeda88634..eae315573563 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.18rc3" +#define CONFIG_SND_VERSION "1.0.18" #define CONFIG_SND_DATE "" From e78a37bc7776955a142317b622818962c3ee75dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Oct 2008 16:08:01 +0100 Subject: [PATCH 031/367] ALSA: Fix a typo in Kconfig The previous commit bbaf5e97337287479eb78dbc3822d9560bbfd2e2 has an obvious typo. Fixed now. Signed-off-by: Takashi Iwai --- sound/core/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 406a45010985..7bbdda041a99 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -134,7 +134,7 @@ config SND_RTCTIMER config SND_SEQ_RTCTIMER_DEFAULT bool "Use RTC as default sequencer timer" depends on SND_RTCTIMER && SND_SEQUENCER - dpeends on !SND_SEQ_HRTIMER_DEFAULT + depends on !SND_SEQ_HRTIMER_DEFAULT default y help Say Y here to use the RTC timer as the default sequencer From 12ef193d5817504621e503e78d641265f6a86ac4 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 13 Oct 2008 17:42:14 -0700 Subject: [PATCH 032/367] ASoC: Allow setting codec register with debugfs filesystem i.e. echo 6 59 >/sys/kernel/debug/soc-audio.0/codec_reg will set register 0x06 to a value of 0x59. Also, pop_time debugfs interface setup is moved so that it is setup in the same function as codec_reg Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++ sound/soc/soc-core.c | 116 +++++++++++++++++++++++++++++++++++++++++-- sound/soc/soc-dapm.c | 33 +++--------- 3 files changed, 125 insertions(+), 28 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index a1e0357a84d7..d33825d624a5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -425,6 +425,7 @@ struct snd_soc_codec { short reg_cache_step; /* dapm */ + u32 pop_time; struct list_head dapm_widgets; struct list_head dapm_paths; enum snd_soc_bias_level bias_level; @@ -516,6 +517,9 @@ struct snd_soc_device { struct delayed_work delayed_work; struct work_struct deferred_resume_work; void *codec_data; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; +#endif }; /* runtime channel data */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 462e635dfc74..4707042b3dad 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -961,10 +962,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, } /* codec register dump */ -static ssize_t codec_reg_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf) { - struct snd_soc_device *devdata = dev_get_drvdata(dev); struct snd_soc_codec *codec = devdata->codec; int i, step = 1, count = 0; @@ -1001,8 +1000,117 @@ static ssize_t codec_reg_show(struct device *dev, return count; } +static ssize_t codec_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_soc_device *devdata = dev_get_drvdata(dev); + return soc_codec_reg_show(devdata, buf); +} + static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); +#ifdef CONFIG_DEBUG_FS +static int codec_reg_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + struct snd_soc_device *devdata = file->private_data; + char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = soc_codec_reg_show(devdata, buf); + if (ret >= 0) + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + kfree(buf); + return ret; +} + +static ssize_t codec_reg_write_file(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + char buf[32]; + int buf_size; + char *start = buf; + unsigned long reg, value; + int step = 1; + struct snd_soc_device *devdata = file->private_data; + struct snd_soc_codec *codec = devdata->codec; + + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + if (codec->reg_cache_step) + step = codec->reg_cache_step; + + while (*start == ' ') + start++; + reg = simple_strtoul(start, &start, 16); + if ((reg >= codec->reg_cache_size) || (reg % step)) + return -EINVAL; + while (*start == ' ') + start++; + if (strict_strtoul(start, 16, &value)) + return -EINVAL; + codec->write(codec, reg, value); + return buf_size; +} + +static const struct file_operations codec_reg_fops = { + .open = codec_reg_open_file, + .read = codec_reg_read_file, + .write = codec_reg_write_file, +}; + +static void soc_init_debugfs(struct snd_soc_device *socdev) +{ + struct dentry *root, *file; + struct snd_soc_codec *codec = socdev->codec; + root = debugfs_create_dir(dev_name(socdev->dev), NULL); + if (IS_ERR(root) || !root) + goto exit1; + + file = debugfs_create_file("codec_reg", 0644, + root, socdev, &codec_reg_fops); + if (!file) + goto exit2; + + file = debugfs_create_u32("dapm_pop_time", 0744, + root, &codec->pop_time); + if (!file) + goto exit2; + socdev->debugfs_root = root; + return; +exit2: + debugfs_remove_recursive(root); +exit1: + dev_err(socdev->dev, "debugfs is not available\n"); +} + +static void soc_cleanup_debugfs(struct snd_soc_device *socdev) +{ + debugfs_remove_recursive(socdev->debugfs_root); + socdev->debugfs_root = NULL; +} + +#else + +static inline void soc_init_debugfs(struct snd_soc_device *socdev) +{ +} + +static inline void soc_cleanup_debugfs(struct snd_soc_device *socdev) +{ +} +#endif + /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec @@ -1216,6 +1324,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) if (err < 0) printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); + soc_init_debugfs(socdev); mutex_unlock(&codec->mutex); out: @@ -1239,6 +1348,7 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) #endif mutex_lock(&codec->mutex); + soc_cleanup_debugfs(socdev); #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7e9f423f5b09..b51d82285be4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -67,17 +66,13 @@ static int dapm_status = 1; module_param(dapm_status, int, 0); MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); -static struct dentry *asoc_debugfs; - -static u32 pop_time; - -static void pop_wait(void) +static void pop_wait(u32 pop_time) { if (pop_time) schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); } -static void pop_dbg(const char *fmt, ...) +static void pop_dbg(u32 pop_time, const char *fmt, ...) { va_list args; @@ -85,7 +80,7 @@ static void pop_dbg(const char *fmt, ...) if (pop_time) { vprintk(fmt, args); - pop_wait(); + pop_wait(pop_time); } va_end(args); @@ -230,10 +225,11 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget) change = old != new; if (change) { - pop_dbg("pop test %s : %s in %d ms\n", widget->name, - widget->power ? "on" : "off", pop_time); + pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n", + widget->name, widget->power ? "on" : "off", + codec->pop_time); snd_soc_write(codec, widget->reg, new); - pop_wait(); + pop_wait(codec->pop_time); } pr_debug("reg %x old %x new %x change %d\n", widget->reg, old, new, change); @@ -821,23 +817,13 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { - int ret = 0; - if (!dapm_status) return 0; ret = device_create_file(dev, &dev_attr_dapm_widget); if (ret != 0) return ret; - - asoc_debugfs = debugfs_create_dir("asoc", NULL); - if (!IS_ERR(asoc_debugfs) && asoc_debugfs) - debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs, - &pop_time); - else - asoc_debugfs = NULL; - - return 0; + return device_create_file(dev, &dev_attr_dapm_widget); } static void snd_soc_dapm_sys_remove(struct device *dev) @@ -845,9 +831,6 @@ static void snd_soc_dapm_sys_remove(struct device *dev) if (dapm_status) { device_remove_file(dev, &dev_attr_dapm_widget); } - - if (asoc_debugfs) - debugfs_remove_recursive(asoc_debugfs); } /* free all dapm widgets and resources */ From d45f6219d256b4e02f9ebee2e3911f4ea80bac70 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 14 Oct 2008 13:58:36 +0100 Subject: [PATCH 033/367] ASoC: Fix handling of DAPM suspend work Since we can query the playback stream power state directly we do not need to infer if it is powered up from the timer being scheduled. Doing this avoids problems that previously existed with streams being incorrectly determined to be powered up caused when the timer is scheduled when streams are closed after being partially set up. Reported-by: Nobin Mathew Reported-by: Jukka Hynninen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 65 +++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4707042b3dad..411fd3bcf44f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -429,51 +429,42 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - /* we only want to start a DAPM playback stream if we are not waiting - * on an existing one stopping */ - if (codec_dai->pop_wait) { - /* we are waiting for the delayed work to start */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - snd_soc_dapm_stream_event(socdev->codec, + /* cancel any delayed stream shutdown that is pending */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + codec_dai->pop_wait) { + codec_dai->pop_wait = 0; + cancel_delayed_work(&socdev->delayed_work); + } + + /* do we need to power up codec */ + if (codec->bias_level != SND_SOC_BIAS_ON) { + snd_soc_dapm_set_bias_level(socdev, + SND_SOC_BIAS_PREPARE); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, + codec_dai->playback.stream_name, + SND_SOC_DAPM_STREAM_START); + else + snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - else { - codec_dai->pop_wait = 0; - cancel_delayed_work(&socdev->delayed_work); - snd_soc_dai_digital_mute(codec_dai, 0); - } + + snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); + snd_soc_dai_digital_mute(codec_dai, 0); + } else { - /* no delayed work - do we need to power up codec */ - if (codec->bias_level != SND_SOC_BIAS_ON) { - - snd_soc_dapm_set_bias_level(socdev, - SND_SOC_BIAS_PREPARE); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, + /* codec already powered - power on widgets */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name, SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, + else + snd_soc_dapm_stream_event(codec, codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_START); - snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON); - snd_soc_dai_digital_mute(codec_dai, 0); - - } else { - /* codec already powered - power on widgets */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(codec, - codec_dai->playback.stream_name, - SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(codec, - codec_dai->capture.stream_name, - SND_SOC_DAPM_STREAM_START); - - snd_soc_dai_digital_mute(codec_dai, 0); - } + snd_soc_dai_digital_mute(codec_dai, 0); } out: From f24368c2fb524e911b831b86b5f0acfb38c70317 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Oct 2008 21:45:08 +0100 Subject: [PATCH 034/367] ASoC: Convert core to use standard debug print macros Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 411fd3bcf44f..8f384df941fd 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -35,14 +35,6 @@ #include #include -/* debug */ -#define SOC_DEBUG 0 -#if SOC_DEBUG -#define dbg(format, arg...) printk(format, ## arg) -#else -#define dbg(format, arg...) -#endif - static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); @@ -229,12 +221,12 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto machine_err; } - dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); - dbg("asoc: rate mask 0x%x\n", runtime->hw.rates); - dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, - runtime->hw.channels_max); - dbg("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, - runtime->hw.rate_max); + 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, + runtime->hw.channels_max); + pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, + runtime->hw.rate_max); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) cpu_dai->playback.active = codec_dai->playback.active = 1; @@ -279,18 +271,18 @@ static void close_delayed_work(struct work_struct *work) for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - dbg("pop wq checking: %s status: %s waiting: %s\n", - codec_dai->playback.stream_name, - codec_dai->playback.active ? "active" : "inactive", - codec_dai->pop_wait ? "yes" : "no"); + pr_debug("pop wq checking: %s status: %s waiting: %s\n", + codec_dai->playback.stream_name, + codec_dai->playback.active ? "active" : "inactive", + codec_dai->pop_wait ? "yes" : "no"); /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { /* Reduce power if no longer active */ if (codec->active == 0) { - dbg("pop wq D1 %s %s\n", codec->name, - codec_dai->playback.stream_name); + pr_debug("pop wq D1 %s %s\n", codec->name, + codec_dai->playback.stream_name); snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE); } @@ -302,8 +294,8 @@ static void close_delayed_work(struct work_struct *work) /* Fall into standby if no longer active */ if (codec->active == 0) { - dbg("pop wq D3 %s %s\n", codec->name, - codec_dai->playback.stream_name); + pr_debug("pop wq D3 %s %s\n", codec->name, + codec_dai->playback.stream_name); snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY); } From 219b93f5252086c8c8d647c77fc9e1377aab0c8d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Oct 2008 13:02:31 +0000 Subject: [PATCH 035/367] ASoC: Remove DAPM restriction on mixer control name lengths As well as ensuring that UI-relevant parts of control names don't get truncated in the DAPM code this avoids conflicts in long control names that differ only at the end of a long string. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b51d82285be4..407092c226f9 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -289,7 +289,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, struct snd_soc_dapm_widget *w) { int i, ret = 0; - char name[32]; + size_t name_len; struct snd_soc_dapm_path *path; /* add kcontrol */ @@ -303,11 +303,16 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, continue; /* add dapm control with long name */ - snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name); - path->long_name = kstrdup (name, GFP_KERNEL); + name_len = 2 + strlen(w->name) + + strlen(w->kcontrols[i].name); + path->long_name = kmalloc(name_len, GFP_KERNEL); if (path->long_name == NULL) return -ENOMEM; + snprintf(path->long_name, name_len, "%s %s", + w->name, w->kcontrols[i].name); + path->long_name[name_len - 1] = '\0'; + path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, path->long_name); ret = snd_ctl_add(codec->card, path->kcontrol); From 1b340bd7e444f20eb2df88c65fa34960c4736ee9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 30 Jul 2008 19:12:04 +0100 Subject: [PATCH 036/367] ASoC: Add PXA SSP support The SSP ports PXA series processors can be used to implement a variety of audio interface formats. This patch implements support for I2S, DSP A and DSP B modes on these ports. This patch is based on the previous out of tree pxa2xx-ssp driver (which was originally written by Liam Girdwood with updates from Philipp Zabel and Nicola Perrino) and pxa3xx-ssp driver (originally written by Seth Forsee based on the pxa2xx-ssp driver). Testing coverage is not complete currently. Tested-by: Daniel Ribeiro Signed-off-by: Mark Brown --- sound/soc/pxa/Kconfig | 13 + sound/soc/pxa/Makefile | 2 + sound/soc/pxa/pxa-ssp.c | 929 ++++++++++++++++++++++++++++++++++++++++ sound/soc/pxa/pxa-ssp.h | 47 ++ 4 files changed, 991 insertions(+) create mode 100644 sound/soc/pxa/pxa-ssp.c create mode 100644 sound/soc/pxa/pxa-ssp.h diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index f8c1cdd940ac..4235524238f9 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -21,6 +21,9 @@ config SND_PXA2XX_SOC_AC97 config SND_PXA2XX_SOC_I2S tristate +config SND_PXA_SOC_SSP + tristate + config SND_PXA2XX_SOC_CORGI tristate "SoC Audio support for Sharp Zaurus SL-C7x0" depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx @@ -75,3 +78,13 @@ config SND_PXA2XX_SOC_EM_X270 help Say Y if you want to add support for SoC audio on CompuLab EM-x270. + +config SND_SOC_ZYLONITE + tristate "SoC Audio support for Marvell Zylonite" + depends on SND_PXA2XX_SOC && MACH_ZYLONITE + select SND_PXA2XX_SOC_AC97 + select SND_PXA_SOC_SSP + select SND_SOC_WM9713 + help + Say Y if you want to add support for SoC audio on the + Marvell Zylonite reference platform. diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 5bc8edf9dca9..00258abb84a8 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -2,10 +2,12 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o +snd-soc-pxa-ssp-objs := pxa-ssp.o obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o +obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o # PXA Machine Support snd-soc-corgi-objs := corgi.o diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c new file mode 100644 index 000000000000..e2b54b88c380 --- /dev/null +++ b/sound/soc/pxa/pxa-ssp.c @@ -0,0 +1,929 @@ +#define DEBUG +/* + * pxa-ssp.c -- ALSA Soc Audio Layer + * + * Copyright 2005,2008 Wolfson Microelectronics PLC. + * Author: Liam Girdwood + * Mark Brown + * + * 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. + * + * TODO: + * o Test network mode for > 16bit sample size + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pxa2xx-pcm.h" +#include "pxa-ssp.h" + +/* + * SSP audio private data + */ +struct ssp_priv { + struct ssp_dev dev; + unsigned int sysclk; + int dai_fmt; +#ifdef CONFIG_PM + struct ssp_state state; +#endif +}; + +#define PXA2xx_SSP1_BASE 0x41000000 +#define PXA27x_SSP2_BASE 0x41700000 +#define PXA27x_SSP3_BASE 0x41900000 +#define PXA3xx_SSP4_BASE 0x41a00000 + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_out = { + .name = "SSP1 PCM Mono out", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(14), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_mono_in = { + .name = "SSP1 PCM Mono in", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(13), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_out = { + .name = "SSP1 PCM Stereo out", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(14), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp1_pcm_stereo_in = { + .name = "SSP1 PCM Stereo in", + .dev_addr = PXA2xx_SSP1_BASE + SSDR, + .drcmr = &DRCMR(13), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_out = { + .name = "SSP2 PCM Mono out", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(16), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_mono_in = { + .name = "SSP2 PCM Mono in", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(15), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_out = { + .name = "SSP2 PCM Stereo out", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(16), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp2_pcm_stereo_in = { + .name = "SSP2 PCM Stereo in", + .dev_addr = PXA27x_SSP2_BASE + SSDR, + .drcmr = &DRCMR(15), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_out = { + .name = "SSP3 PCM Mono out", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_mono_in = { + .name = "SSP3 PCM Mono in", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_out = { + .name = "SSP3 PCM Stereo out", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp3_pcm_stereo_in = { + .name = "SSP3 PCM Stereo in", + .dev_addr = PXA27x_SSP3_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_out = { + .name = "SSP4 PCM Mono out", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_mono_in = { + .name = "SSP4 PCM Mono in", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH2, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_out = { + .name = "SSP4 PCM Stereo out", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(67), + .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static struct pxa2xx_pcm_dma_params pxa_ssp4_pcm_stereo_in = { + .name = "SSP4 PCM Stereo in", + .dev_addr = PXA3xx_SSP4_BASE + SSDR, + .drcmr = &DRCMR(66), + .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC | + DCMD_BURST16 | DCMD_WIDTH4, +}; + +static void dump_registers(struct ssp_device *ssp) +{ + dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n", + ssp_read_reg(ssp, SSCR0), ssp_read_reg(ssp, SSCR1), + ssp_read_reg(ssp, SSTO)); + + dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n", + ssp_read_reg(ssp, SSPSP), ssp_read_reg(ssp, SSSR), + ssp_read_reg(ssp, SSACD)); +} + +static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = { + { + &pxa_ssp1_pcm_mono_out, &pxa_ssp1_pcm_mono_in, + &pxa_ssp1_pcm_stereo_out, &pxa_ssp1_pcm_stereo_in, + }, + { + &pxa_ssp2_pcm_mono_out, &pxa_ssp2_pcm_mono_in, + &pxa_ssp2_pcm_stereo_out, &pxa_ssp2_pcm_stereo_in, + }, + { + &pxa_ssp3_pcm_mono_out, &pxa_ssp3_pcm_mono_in, + &pxa_ssp3_pcm_stereo_out, &pxa_ssp3_pcm_stereo_in, + }, + { + &pxa_ssp4_pcm_mono_out, &pxa_ssp4_pcm_mono_in, + &pxa_ssp4_pcm_stereo_out, &pxa_ssp4_pcm_stereo_in, + }, +}; + +static int pxa_ssp_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct ssp_priv *priv = cpu_dai->private_data; + int ret = 0; + + if (!cpu_dai->active) { + ret = ssp_init(&priv->dev, cpu_dai->id + 1, SSP_NO_IRQ); + if (ret < 0) + return ret; + ssp_disable(&priv->dev); + } + return ret; +} + +static void pxa_ssp_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct ssp_priv *priv = cpu_dai->private_data; + + if (!cpu_dai->active) { + ssp_disable(&priv->dev); + ssp_exit(&priv->dev); + } +} + +#ifdef CONFIG_PM + +static int pxa_ssp_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct ssp_priv *priv = cpu_dai->private_data; + + if (!cpu_dai->active) + return 0; + + ssp_save_state(&priv->dev, &priv->state); + clk_disable(priv->dev.ssp->clk); + return 0; +} + +static int pxa_ssp_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct ssp_priv *priv = cpu_dai->private_data; + + if (!cpu_dai->active) + return 0; + + clk_enable(priv->dev.ssp->clk); + ssp_restore_state(&priv->dev, &priv->state); + ssp_enable(&priv->dev); + + return 0; +} + +#else +#define pxa_ssp_suspend NULL +#define pxa_ssp_resume NULL +#endif + +/** + * ssp_set_clkdiv - set SSP clock divider + * @div: serial clock rate divider + */ +static void ssp_set_scr(struct ssp_dev *dev, u32 div) +{ + struct ssp_device *ssp = dev->ssp; + u32 sscr0 = ssp_read_reg(dev->ssp, SSCR0) & ~SSCR0_SCR; + + ssp_write_reg(ssp, SSCR0, (sscr0 | SSCR0_SerClkDiv(div))); +} + +/* + * Set the SSP ports SYSCLK. + */ +static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + int val; + + u32 sscr0 = ssp_read_reg(ssp, SSCR0) & + ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); + + dev_dbg(&ssp->pdev->dev, + "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %d\n", + cpu_dai->id, clk_id, freq); + + switch (clk_id) { + case PXA_SSP_CLK_NET_PLL: + sscr0 |= SSCR0_MOD; + break; + case PXA_SSP_CLK_PLL: + /* Internal PLL is fixed */ + if (cpu_is_pxa25x()) + priv->sysclk = 1843200; + else + priv->sysclk = 13000000; + break; + case PXA_SSP_CLK_EXT: + priv->sysclk = freq; + sscr0 |= SSCR0_ECS; + break; + case PXA_SSP_CLK_NET: + priv->sysclk = freq; + sscr0 |= SSCR0_NCS | SSCR0_MOD; + break; + case PXA_SSP_CLK_AUDIO: + priv->sysclk = 0; + ssp_set_scr(&priv->dev, 1); + sscr0 |= SSCR0_ADC; + break; + default: + return -ENODEV; + } + + /* The SSP clock must be disabled when changing SSP clock mode + * on PXA2xx. On PXA3xx it must be enabled when doing so. */ + if (!cpu_is_pxa3xx()) + clk_disable(priv->dev.ssp->clk); + val = ssp_read_reg(ssp, SSCR0) | sscr0; + ssp_write_reg(ssp, SSCR0, val); + if (!cpu_is_pxa3xx()) + clk_enable(priv->dev.ssp->clk); + + return 0; +} + +/* + * Set the SSP clock dividers. + */ +static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + int val; + + switch (div_id) { + case PXA_SSP_AUDIO_DIV_ACDS: + val = (ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div); + ssp_write_reg(ssp, SSACD, val); + break; + case PXA_SSP_AUDIO_DIV_SCDB: + val = ssp_read_reg(ssp, SSACD); + val &= ~SSACD_SCDB; +#if defined(CONFIG_PXA3xx) + if (cpu_is_pxa3xx()) + val &= ~SSACD_SCDX8; +#endif + switch (div) { + case PXA_SSP_CLK_SCDB_1: + val |= SSACD_SCDB; + break; + case PXA_SSP_CLK_SCDB_4: + break; +#if defined(CONFIG_PXA3xx) + case PXA_SSP_CLK_SCDB_8: + if (cpu_is_pxa3xx()) + val |= SSACD_SCDX8; + else + return -EINVAL; + break; +#endif + default: + return -EINVAL; + } + ssp_write_reg(ssp, SSACD, val); + break; + case PXA_SSP_DIV_SCR: + ssp_set_scr(&priv->dev, div); + break; + default: + return -ENODEV; + } + + return 0; +} + +/* + * Configure the PLL frequency pxa27x and (afaik - pxa320 only) + */ +static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, + int pll_id, unsigned int freq_in, unsigned int freq_out) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + u32 ssacd = ssp_read_reg(ssp, SSACD) & ~0x70; + +#if defined(CONFIG_PXA3xx) + if (cpu_is_pxa3xx()) + ssp_write_reg(ssp, SSACDD, 0); +#endif + + switch (freq_out) { + case 5622000: + break; + case 11345000: + ssacd |= (0x1 << 4); + break; + case 12235000: + ssacd |= (0x2 << 4); + break; + case 14857000: + ssacd |= (0x3 << 4); + break; + case 32842000: + ssacd |= (0x4 << 4); + break; + case 48000000: + ssacd |= (0x5 << 4); + break; + case 0: + /* Disable */ + break; + + default: +#ifdef CONFIG_PXA3xx + /* PXA3xx has a clock ditherer which can be used to generate + * a wider range of frequencies - calculate a value for it. + */ + if (cpu_is_pxa3xx()) { + u32 val; + u64 tmp = 19968; + tmp *= 1000000; + do_div(tmp, freq_out); + val = tmp; + + val = (val << 16) | 64;; + ssp_write_reg(ssp, SSACDD, val); + + ssacd |= (0x6 << 4); + + dev_dbg(&ssp->pdev->dev, + "Using SSACDD %x to supply %dHz\n", + val, freq_out); + break; + } +#endif + + return -EINVAL; + } + + ssp_write_reg(ssp, SSACD, ssacd); + + return 0; +} + +/* + * Set the active slots in TDM/Network mode + */ +static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, + unsigned int mask, int slots) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + u32 sscr0; + + sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7); + + /* set number of active slots */ + sscr0 |= SSCR0_SlotsPerFrm(slots); + ssp_write_reg(ssp, SSCR0, sscr0); + + /* set active slot mask */ + ssp_write_reg(ssp, SSTSA, mask); + ssp_write_reg(ssp, SSRSA, mask); + return 0; +} + +/* + * Tristate the SSP DAI lines + */ +static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai, + int tristate) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + u32 sscr1; + + sscr1 = ssp_read_reg(ssp, SSCR1); + if (tristate) + sscr1 &= ~SSCR1_TTE; + else + sscr1 |= SSCR1_TTE; + ssp_write_reg(ssp, SSCR1, sscr1); + + return 0; +} + +/* + * Set up the SSP DAI format. + * The SSP Port must be inactive before calling this function as the + * physical interface format is changed. + */ +static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + u32 sscr0; + u32 sscr1; + u32 sspsp; + + /* reset port settings */ + sscr0 = ssp_read_reg(ssp, SSCR0) & + (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ADC); + sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); + sspsp = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR; + break; + case SND_SOC_DAIFMT_CBM_CFS: + sscr1 |= SSCR1_SCLKDIR; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + ssp_write_reg(ssp, SSCR0, sscr0); + ssp_write_reg(ssp, SSCR1, sscr1); + ssp_write_reg(ssp, SSPSP, sspsp); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + sscr0 |= SSCR0_MOD | SSCR0_PSP; + sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + sspsp |= SSPSP_FSRT; + break; + case SND_SOC_DAIFMT_NB_IF: + sspsp |= SSPSP_SFRMP | SSPSP_FSRT; + break; + case SND_SOC_DAIFMT_IB_IF: + sspsp |= SSPSP_SFRMP; + break; + default: + return -EINVAL; + } + break; + + case SND_SOC_DAIFMT_DSP_A: + sspsp |= SSPSP_FSRT; + case SND_SOC_DAIFMT_DSP_B: + sscr0 |= SSCR0_MOD | SSCR0_PSP; + sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + sspsp |= SSPSP_SFRMP; + break; + case SND_SOC_DAIFMT_IB_IF: + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + ssp_write_reg(ssp, SSCR0, sscr0); + ssp_write_reg(ssp, SSCR1, sscr1); + ssp_write_reg(ssp, SSPSP, sspsp); + + dump_registers(ssp); + + /* Since we are configuring the timings for the format by hand + * we have to defer some things until hw_params() where we + * know parameters like the sample size. + */ + priv->dai_fmt = fmt; + + return 0; +} + +/* + * Set the SSP audio DMA parameters and sample size. + * Can be called multiple times by oss emulation. + */ +static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + int dma = 0, chn = params_channels(params); + u32 sscr0; + u32 sspsp; + int width = snd_pcm_format_physical_width(params_format(params)); + + /* select correct DMA params */ + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) + dma = 1; /* capture DMA offset is 1,3 */ + if (chn == 2) + dma += 2; /* stereo DMA offset is 2, mono is 0 */ + cpu_dai->dma_data = ssp_dma_params[cpu_dai->id][dma]; + + dev_dbg(&ssp->pdev->dev, "pxa_ssp_hw_params: dma %d\n", dma); + + /* we can only change the settings if the port is not in use */ + if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) + return 0; + + /* clear selected SSP bits */ + sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS); + ssp_write_reg(ssp, SSCR0, sscr0); + + /* bit size */ + sscr0 = ssp_read_reg(ssp, SSCR0); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: +#ifdef CONFIG_PXA3xx + if (cpu_is_pxa3xx()) + sscr0 |= SSCR0_FPCKE; +#endif + sscr0 |= SSCR0_DataSize(16); + if (params_channels(params) > 1) + sscr0 |= SSCR0_EDSS; + break; + case SNDRV_PCM_FORMAT_S24_LE: + sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); + /* we must be in network mode (2 slots) for 24 bit stereo */ + break; + case SNDRV_PCM_FORMAT_S32_LE: + sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); + /* we must be in network mode (2 slots) for 32 bit stereo */ + break; + } + ssp_write_reg(ssp, SSCR0, sscr0); + + switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* Cleared when the DAI format is set */ + sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width); + ssp_write_reg(ssp, SSPSP, sspsp); + break; + default: + break; + } + + /* We always use a network mode so we always require TDM slots + * - complain loudly and fail if they've not been set up yet. + */ + if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { + dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); + return -EINVAL; + } + + dump_registers(ssp); + + return 0; +} + +static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret = 0; + struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->dev.ssp; + int val; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + ssp_enable(&priv->dev); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + val = ssp_read_reg(ssp, SSCR1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val |= SSCR1_TSRE; + else + val |= SSCR1_RSRE; + ssp_write_reg(ssp, SSCR1, val); + val = ssp_read_reg(ssp, SSSR); + ssp_write_reg(ssp, SSSR, val); + break; + case SNDRV_PCM_TRIGGER_START: + val = ssp_read_reg(ssp, SSCR1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val |= SSCR1_TSRE; + else + val |= SSCR1_RSRE; + ssp_write_reg(ssp, SSCR1, val); + ssp_enable(&priv->dev); + break; + case SNDRV_PCM_TRIGGER_STOP: + val = ssp_read_reg(ssp, SSCR1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val &= ~SSCR1_TSRE; + else + val &= ~SSCR1_RSRE; + ssp_write_reg(ssp, SSCR1, val); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + ssp_disable(&priv->dev); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + val = ssp_read_reg(ssp, SSCR1); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + val &= ~SSCR1_TSRE; + else + val &= ~SSCR1_RSRE; + ssp_write_reg(ssp, SSCR1, val); + break; + + default: + ret = -EINVAL; + } + + dump_registers(ssp); + + return ret; +} + +static int pxa_ssp_probe(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct ssp_priv *priv; + int ret; + + priv = kzalloc(sizeof(struct ssp_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev.ssp = ssp_request(dai->id, "SoC audio"); + if (priv->dev.ssp == NULL) { + ret = -ENODEV; + goto err_priv; + } + + dai->private_data = priv; + + return 0; + +err_priv: + kfree(priv); + return ret; +} + +static void pxa_ssp_remove(struct platform_device *pdev, + struct snd_soc_dai *dai) +{ + struct ssp_priv *priv = dai->private_data; + ssp_free(priv->dev.ssp); +} + +#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) + +#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +struct snd_soc_dai pxa_ssp_dai[] = { + { + .name = "pxa2xx-ssp1", + .id = 0, + .type = SND_SOC_DAI_PCM, + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .ops = { + .startup = pxa_ssp_startup, + .shutdown = pxa_ssp_shutdown, + .trigger = pxa_ssp_trigger, + .hw_params = pxa_ssp_hw_params, + }, + .dai_ops = { + .set_sysclk = pxa_ssp_set_dai_sysclk, + .set_clkdiv = pxa_ssp_set_dai_clkdiv, + .set_pll = pxa_ssp_set_dai_pll, + .set_fmt = pxa_ssp_set_dai_fmt, + .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, + .set_tristate = pxa_ssp_set_dai_tristate, + }, + }, + { .name = "pxa2xx-ssp2", + .id = 1, + .type = SND_SOC_DAI_PCM, + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .ops = { + .startup = pxa_ssp_startup, + .shutdown = pxa_ssp_shutdown, + .trigger = pxa_ssp_trigger, + .hw_params = pxa_ssp_hw_params, + }, + .dai_ops = { + .set_sysclk = pxa_ssp_set_dai_sysclk, + .set_clkdiv = pxa_ssp_set_dai_clkdiv, + .set_pll = pxa_ssp_set_dai_pll, + .set_fmt = pxa_ssp_set_dai_fmt, + .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, + .set_tristate = pxa_ssp_set_dai_tristate, + }, + }, + { + .name = "pxa2xx-ssp3", + .id = 2, + .type = SND_SOC_DAI_PCM, + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .ops = { + .startup = pxa_ssp_startup, + .shutdown = pxa_ssp_shutdown, + .trigger = pxa_ssp_trigger, + .hw_params = pxa_ssp_hw_params, + }, + .dai_ops = { + .set_sysclk = pxa_ssp_set_dai_sysclk, + .set_clkdiv = pxa_ssp_set_dai_clkdiv, + .set_pll = pxa_ssp_set_dai_pll, + .set_fmt = pxa_ssp_set_dai_fmt, + .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, + .set_tristate = pxa_ssp_set_dai_tristate, + }, + }, + { + .name = "pxa2xx-ssp4", + .id = 3, + .type = SND_SOC_DAI_PCM, + .probe = pxa_ssp_probe, + .remove = pxa_ssp_remove, + .suspend = pxa_ssp_suspend, + .resume = pxa_ssp_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = PXA_SSP_RATES, + .formats = PXA_SSP_FORMATS, + }, + .ops = { + .startup = pxa_ssp_startup, + .shutdown = pxa_ssp_shutdown, + .trigger = pxa_ssp_trigger, + .hw_params = pxa_ssp_hw_params, + }, + .dai_ops = { + .set_sysclk = pxa_ssp_set_dai_sysclk, + .set_clkdiv = pxa_ssp_set_dai_clkdiv, + .set_pll = pxa_ssp_set_dai_pll, + .set_fmt = pxa_ssp_set_dai_fmt, + .set_tdm_slot = pxa_ssp_set_dai_tdm_slot, + .set_tristate = pxa_ssp_set_dai_tristate, + }, + }, +}; +EXPORT_SYMBOL_GPL(pxa_ssp_dai); + +/* Module information */ +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h new file mode 100644 index 000000000000..91deadd55675 --- /dev/null +++ b/sound/soc/pxa/pxa-ssp.h @@ -0,0 +1,47 @@ +/* + * ASoC PXA SSP port support + * + * 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 _PXA_SSP_H +#define _PXA_SSP_H + +/* pxa DAI SSP IDs */ +#define PXA_DAI_SSP1 0 +#define PXA_DAI_SSP2 1 +#define PXA_DAI_SSP3 2 +#define PXA_DAI_SSP4 3 + +/* SSP clock sources */ +#define PXA_SSP_CLK_PLL 0 +#define PXA_SSP_CLK_EXT 1 +#define PXA_SSP_CLK_NET 2 +#define PXA_SSP_CLK_AUDIO 3 +#define PXA_SSP_CLK_NET_PLL 4 + +/* SSP audio dividers */ +#define PXA_SSP_AUDIO_DIV_ACDS 0 +#define PXA_SSP_AUDIO_DIV_SCDB 1 +#define PXA_SSP_DIV_SCR 2 + +/* SSP ACDS audio dividers values */ +#define PXA_SSP_CLK_AUDIO_DIV_1 0 +#define PXA_SSP_CLK_AUDIO_DIV_2 1 +#define PXA_SSP_CLK_AUDIO_DIV_4 2 +#define PXA_SSP_CLK_AUDIO_DIV_8 3 +#define PXA_SSP_CLK_AUDIO_DIV_16 4 +#define PXA_SSP_CLK_AUDIO_DIV_32 5 + +/* SSP divider bypass */ +#define PXA_SSP_CLK_SCDB_4 0 +#define PXA_SSP_CLK_SCDB_1 1 +#define PXA_SSP_CLK_SCDB_8 2 + +#define PXA_SSP_PLL_OUT 0 + +extern struct snd_soc_dai pxa_ssp_dai[4]; + +#endif From e775f6c0fb6ac25ab8845d4ad1e17b4b015487f0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Oct 2008 15:04:35 +0000 Subject: [PATCH 037/367] ASoC: Do a warm reset after cold when resetting the WM9713 The WM9713 comes out of cold reset in low power mode so always requires a warm reset to bring up the AC97 link after a cold reset. Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index aba402b3c999..3214aa503ead 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1097,6 +1097,8 @@ int wm9713_reset(struct snd_soc_codec *codec, int try_warm) } soc_ac97_ops.reset(codec->ac97); + if (soc_ac97_ops.warm_reset) + soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, 0) != wm9713_reg[0]) return -EIO; return 0; From ca53fb24dd21bff32c4b41b2be1035a1adfc0135 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 22 Oct 2008 22:41:11 +0100 Subject: [PATCH 038/367] ASoC: Use finer grained dependencies in SND_SOC_ALL_CODECS Move the bus dependencies in SND_SOC_ALL_CODECS into the individual codec options rather than have them centrally. This allows the inclusion of AC97 codecs when testing on platforms with AC97 support and will also handle codecs on multi-function devices more gracefully. Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 44 ++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 38a0e3b620a7..3c76cae68b4a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1,31 +1,35 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" - depends on I2C - select SPI - select SPI_MASTER - select SND_SOC_AD73311 - select SND_SOC_AK4535 - select SND_SOC_CS4270 - select SND_SOC_SSM2602 - select SND_SOC_TLV320AIC23 - select SND_SOC_TLV320AIC26 - select SND_SOC_TLV320AIC3X - select SND_SOC_UDA1380 - select SND_SOC_WM8510 - select SND_SOC_WM8580 - select SND_SOC_WM8731 - select SND_SOC_WM8750 - select SND_SOC_WM8753 - select SND_SOC_WM8900 - select SND_SOC_WM8903 - select SND_SOC_WM8971 - select SND_SOC_WM8990 + select SND_SOC_AC97 if SND_SOC_AC97_BUS + select SND_SOC_AD1980 if SND_SOC_AC97_BUS + select SND_SOC_AD73311 if I2C + select SND_SOC_AK4535 if I2C + select SND_SOC_CS4270 if I2C + select SND_SOC_SSM2602 if I2C + select SND_SOC_TLV320AIC23 if I2C + select SND_SOC_TLV320AIC26 if SPI_MASTER + select SND_SOC_TLV320AIC3X if I2C + select SND_SOC_UDA1380 if I2C + select SND_SOC_WM8510 if (I2C || SPI_MASTER) + select SND_SOC_WM8580 if I2C + select SND_SOC_WM8731 if (I2C || SPI_MASTER) + select SND_SOC_WM8750 if (I2C || SPI_MASTER) + select SND_SOC_WM8753 if (I2C || SPI_MASTER) + select SND_SOC_WM8900 if I2C + select SND_SOC_WM8903 if I2C + select SND_SOC_WM8971 if I2C + select SND_SOC_WM8990 if I2C + select SND_SOC_WM9712 if SND_SOC_AC97_BUS + select SND_SOC_WM9713 if SND_SOC_AC97_BUS help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine driver. Selecting this option will allow these drivers to be built without an explicit machine driver for test and development purposes. + Support for the bus types used to access the codecs to be built must + be selected separately. + If unsure select "N". From 0c235d1e837c142b7565814318b6ba5917d5ac32 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Thu, 7 Aug 2008 11:22:32 -0500 Subject: [PATCH 039/367] ASoC: Disable automatic volume control in the CS4270 sound driver Disable the automatic volume control feature of the CS4270 audio codec. This feature, which is enabled by default, causes volume change commands to be delayed. Sometimes the volume change happens after playback is started. Signed-off-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 0bbd94501d7e..0ff476d7057c 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -450,6 +450,19 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, return ret; } + /* Disable automatic volume control. It's enabled by default, and + * it causes volume change commands to be delayed, sometimes until + * after playback has started. + */ + + reg = cs4270_read_reg_cache(codec, CS4270_TRANS); + reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO); + ret = cs4270_i2c_write(codec, CS4270_TRANS, reg); + if (ret < 0) { + printk(KERN_ERR "I2C write failed\n"); + return ret; + } + /* Thaw and power-up the codec */ ret = snd_soc_write(codec, CS4270_PWRCTL, 0); From 0763722d28b7b58fa1f9b83d3378efcde855b18a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 30 Oct 2008 17:53:19 +0100 Subject: [PATCH 040/367] ALSA: ASoC - Fix a typo in Kconfig The last change to Kconfig ca53fb24dd21bff32c4b41b2be1035a1adfc0135 added a wrong item SND_SOC_AC97, which must be SND_SOC_AC97_CODEC. Signed-off-by: Takashi Iwai --- sound/soc/codecs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3c76cae68b4a..0fd3341e6e3b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1,6 +1,6 @@ config SND_SOC_ALL_CODECS tristate "Build all ASoC CODEC drivers" - select SND_SOC_AC97 if SND_SOC_AC97_BUS + select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS select SND_SOC_AD1980 if SND_SOC_AC97_BUS select SND_SOC_AD73311 if I2C select SND_SOC_AK4535 if I2C From 57b41898c2ecd13a9d338b66ef23f66caab5c4e9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 31 Oct 2008 14:41:06 +1100 Subject: [PATCH 041/367] ALSA: ASoC - restore removed variable declaration sound/soc/soc-dapm.c: In function 'snd_soc_dapm_sys_add': sound/soc/soc-dapm.c:828: error: 'ret' undeclared (first use in this function) Signed-off-by: Stephen Rothwell Signed-off-by: Takashi Iwai --- sound/soc/soc-dapm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 407092c226f9..7bf3c4094592 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -822,6 +822,8 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { + int ret; + if (!dapm_status) return 0; From cc17557e7876a92e11d4b406a367d28e103e42e6 Mon Sep 17 00:00:00 2001 From: Steve Sakoman Date: Thu, 30 Oct 2008 21:35:26 -0700 Subject: [PATCH 042/367] ASoC: Add support for TWL4030 audio codec Signed-off-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/twl4030.c | 653 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/twl4030.h | 197 +++++++++++ 4 files changed, 857 insertions(+) create mode 100644 sound/soc/codecs/twl4030.c create mode 100644 sound/soc/codecs/twl4030.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0fd3341e6e3b..b73c36aad677 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -9,6 +9,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC3X if I2C + select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_UDA1380 if I2C select SND_SOC_WM8510 if (I2C || SPI_MASTER) select SND_SOC_WM8580 if I2C @@ -79,6 +80,10 @@ config SND_SOC_TLV320AIC3X tristate depends on I2C +config SND_SOC_TWL4030 + tristate + depends on TWL4030_CORE + config SND_SOC_UDA1380 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 90f0a585fc70..3b9b58a0ea7d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -7,6 +7,7 @@ snd-soc-ssm2602-objs := ssm2602.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o +snd-soc-twl4030-objs := twl4030.o snd-soc-uda1380-objs := uda1380.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o @@ -29,6 +30,7 @@ obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o +obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c new file mode 100644 index 000000000000..ee2f0d37765c --- /dev/null +++ b/sound/soc/codecs/twl4030.c @@ -0,0 +1,653 @@ +/* + * ALSA SoC TWL4030 codec driver + * + * Author: Steve Sakoman, + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "twl4030.h" + +/* + * twl4030 register cache & default register settings + */ +static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { + 0x00, /* this register not used */ + 0x93, /* REG_CODEC_MODE (0x1) */ + 0xc3, /* REG_OPTION (0x2) */ + 0x00, /* REG_UNKNOWN (0x3) */ + 0x00, /* REG_MICBIAS_CTL (0x4) */ + 0x24, /* REG_ANAMICL (0x5) */ + 0x04, /* REG_ANAMICR (0x6) */ + 0x0a, /* REG_AVADC_CTL (0x7) */ + 0x00, /* REG_ADCMICSEL (0x8) */ + 0x00, /* REG_DIGMIXING (0x9) */ + 0x0c, /* REG_ATXL1PGA (0xA) */ + 0x0c, /* REG_ATXR1PGA (0xB) */ + 0x00, /* REG_AVTXL2PGA (0xC) */ + 0x00, /* REG_AVTXR2PGA (0xD) */ + 0x01, /* REG_AUDIO_IF (0xE) */ + 0x00, /* REG_VOICE_IF (0xF) */ + 0x00, /* REG_ARXR1PGA (0x10) */ + 0x00, /* REG_ARXL1PGA (0x11) */ + 0x6c, /* REG_ARXR2PGA (0x12) */ + 0x6c, /* REG_ARXL2PGA (0x13) */ + 0x00, /* REG_VRXPGA (0x14) */ + 0x00, /* REG_VSTPGA (0x15) */ + 0x00, /* REG_VRX2ARXPGA (0x16) */ + 0x0c, /* REG_AVDAC_CTL (0x17) */ + 0x00, /* REG_ARX2VTXPGA (0x18) */ + 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ + 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ + 0x4b, /* REG_ARXL2_APGA_CTL (0x1B) */ + 0x4b, /* REG_ARXR2_APGA_CTL (0x1C) */ + 0x00, /* REG_ATX2ARXPGA (0x1D) */ + 0x00, /* REG_BT_IF (0x1E) */ + 0x00, /* REG_BTPGA (0x1F) */ + 0x00, /* REG_BTSTPGA (0x20) */ + 0x00, /* REG_EAR_CTL (0x21) */ + 0x24, /* REG_HS_SEL (0x22) */ + 0x0a, /* REG_HS_GAIN_SET (0x23) */ + 0x00, /* REG_HS_POPN_SET (0x24) */ + 0x00, /* REG_PREDL_CTL (0x25) */ + 0x00, /* REG_PREDR_CTL (0x26) */ + 0x00, /* REG_PRECKL_CTL (0x27) */ + 0x00, /* REG_PRECKR_CTL (0x28) */ + 0x00, /* REG_HFL_CTL (0x29) */ + 0x00, /* REG_HFR_CTL (0x2A) */ + 0x00, /* REG_ALC_CTL (0x2B) */ + 0x00, /* REG_ALC_SET1 (0x2C) */ + 0x00, /* REG_ALC_SET2 (0x2D) */ + 0x00, /* REG_BOOST_CTL (0x2E) */ + 0x01, /* REG_SOFTVOL_CTL (0x2F) */ + 0x00, /* REG_DTMF_FREQSEL (0x30) */ + 0x00, /* REG_DTMF_TONEXT1H (0x31) */ + 0x00, /* REG_DTMF_TONEXT1L (0x32) */ + 0x00, /* REG_DTMF_TONEXT2H (0x33) */ + 0x00, /* REG_DTMF_TONEXT2L (0x34) */ + 0x00, /* REG_DTMF_TONOFF (0x35) */ + 0x00, /* REG_DTMF_WANONOFF (0x36) */ + 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ + 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ + 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ + 0x16, /* REG_APLL_CTL (0x3A) */ + 0x00, /* REG_DTMF_CTL (0x3B) */ + 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ + 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ + 0x00, /* REG_MISC_SET_1 (0x3E) */ + 0x00, /* REG_PCMBTMUX (0x3F) */ + 0x00, /* not used (0x40) */ + 0x00, /* not used (0x41) */ + 0x00, /* not used (0x42) */ + 0x00, /* REG_RX_PATH_SEL (0x43) */ + 0x00, /* REG_VDL_APGA_CTL (0x44) */ + 0x00, /* REG_VIBRA_CTL (0x45) */ + 0x00, /* REG_VIBRA_SET (0x46) */ + 0x00, /* REG_VIBRA_PWM_SET (0x47) */ + 0x00, /* REG_ANAMIC_GAIN (0x48) */ + 0x00, /* REG_MISC_SET_2 (0x49) */ +}; + +/* + * read twl4030 register cache + */ +static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + + return cache[reg]; +} + +/* + * write twl4030 register cache + */ +static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec, + u8 reg, u8 value) +{ + u8 *cache = codec->reg_cache; + + if (reg >= TWL4030_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the twl4030 register space + */ +static int twl4030_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + twl4030_write_reg_cache(codec, reg, value); + return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); +} + +static void twl4030_clear_codecpdz(struct snd_soc_codec *codec) +{ + u8 mode; + + mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); + twl4030_write(codec, TWL4030_REG_CODEC_MODE, + mode & ~TWL4030_CODECPDZ); + + /* REVISIT: this delay is present in TI sample drivers */ + /* but there seems to be no TRM requirement for it */ + udelay(10); +} + +static void twl4030_set_codecpdz(struct snd_soc_codec *codec) +{ + u8 mode; + + mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); + twl4030_write(codec, TWL4030_REG_CODEC_MODE, + mode | TWL4030_CODECPDZ); + + /* REVISIT: this delay is present in TI sample drivers */ + /* but there seems to be no TRM requirement for it */ + udelay(10); +} + +static void twl4030_init_chip(struct snd_soc_codec *codec) +{ + int i; + + /* clear CODECPDZ prior to setting register defaults */ + twl4030_clear_codecpdz(codec); + + /* set all audio section registers to reasonable defaults */ + for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) + twl4030_write(codec, i, twl4030_reg[i]); + +} + +static const struct snd_kcontrol_new twl4030_snd_controls[] = { + SOC_DOUBLE_R("Master Playback Volume", + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, + 0, 127, 0), + SOC_DOUBLE_R("Capture Volume", + TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, + 0, 127, 0), +}; + +/* add non dapm controls */ +static int twl4030_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&twl4030_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("INL"), + SND_SOC_DAPM_INPUT("INR"), + + SND_SOC_DAPM_OUTPUT("OUTL"), + SND_SOC_DAPM_OUTPUT("OUTR"), + + SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route intercon[] = { + /* outputs */ + {"OUTL", NULL, "DACL"}, + {"OUTR", NULL, "DACR"}, + + /* inputs */ + {"ADCL", NULL, "INL"}, + {"ADCR", NULL, "INR"}, +}; + +static int twl4030_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets, + ARRAY_SIZE(twl4030_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static void twl4030_power_up(struct snd_soc_codec *codec) +{ + u8 anamicl, regmisc1, byte, popn, hsgain; + int i = 0; + + /* set CODECPDZ to turn on codec */ + twl4030_set_codecpdz(codec); + + /* initiate offset cancellation */ + anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); + twl4030_write(codec, TWL4030_REG_ANAMICL, + anamicl | TWL4030_CNCL_OFFSET_START); + + /* wait for offset cancellation to complete */ + do { + /* this takes a little while, so don't slam i2c */ + udelay(2000); + twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, + TWL4030_REG_ANAMICL); + } while ((i++ < 100) && + ((byte & TWL4030_CNCL_OFFSET_START) == + TWL4030_CNCL_OFFSET_START)); + + /* anti-pop when changing analog gain */ + regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); + twl4030_write(codec, TWL4030_REG_MISC_SET_1, + regmisc1 | TWL4030_SMOOTH_ANAVOL_EN); + + /* toggle CODECPDZ as per TRM */ + twl4030_clear_codecpdz(codec); + twl4030_set_codecpdz(codec); + + /* program anti-pop with bias ramp delay */ + popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + popn &= TWL4030_RAMP_DELAY; + popn |= TWL4030_RAMP_DELAY_645MS; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); + popn |= TWL4030_VMID_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); + + /* enable output stage and gain setting */ + hsgain = TWL4030_HSR_GAIN_0DB | TWL4030_HSL_GAIN_0DB; + twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain); + + /* enable anti-pop ramp */ + popn |= TWL4030_RAMP_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); +} + +static void twl4030_power_down(struct snd_soc_codec *codec) +{ + u8 popn, hsgain; + + /* disable anti-pop ramp */ + popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + popn &= ~TWL4030_RAMP_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); + + /* disable output stage and gain setting */ + hsgain = TWL4030_HSR_GAIN_PWR_DOWN | TWL4030_HSL_GAIN_PWR_DOWN; + twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain); + + /* disable bias out */ + popn &= ~TWL4030_VMID_EN; + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); + + /* power down */ + twl4030_clear_codecpdz(codec); +} + +static int twl4030_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_ON: + twl4030_power_up(codec); + break; + case SND_SOC_BIAS_PREPARE: + /* TODO: develop a twl4030_prepare function */ + break; + case SND_SOC_BIAS_STANDBY: + /* TODO: develop a twl4030_standby function */ + twl4030_power_down(codec); + break; + case SND_SOC_BIAS_OFF: + twl4030_power_down(codec); + break; + } + codec->bias_level = level; + + return 0; +} + +static int twl4030_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u8 mode, old_mode, format, old_format; + + + /* bit rate */ + old_mode = twl4030_read_reg_cache(codec, + TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; + mode = old_mode & ~TWL4030_APLL_RATE; + + switch (params_rate(params)) { + case 8000: + mode |= TWL4030_APLL_RATE_8000; + break; + case 11025: + mode |= TWL4030_APLL_RATE_11025; + break; + case 12000: + mode |= TWL4030_APLL_RATE_12000; + break; + case 16000: + mode |= TWL4030_APLL_RATE_16000; + break; + case 22050: + mode |= TWL4030_APLL_RATE_22050; + break; + case 24000: + mode |= TWL4030_APLL_RATE_24000; + break; + case 32000: + mode |= TWL4030_APLL_RATE_32000; + break; + case 44100: + mode |= TWL4030_APLL_RATE_44100; + break; + case 48000: + mode |= TWL4030_APLL_RATE_48000; + break; + default: + printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n", + params_rate(params)); + return -EINVAL; + } + + if (mode != old_mode) { + /* change rate and set CODECPDZ */ + twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); + twl4030_set_codecpdz(codec); + } + + /* sample size */ + old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + format = old_format; + format &= ~TWL4030_DATA_WIDTH; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + format |= TWL4030_DATA_WIDTH_16S_16W; + break; + case SNDRV_PCM_FORMAT_S24_LE: + format |= TWL4030_DATA_WIDTH_32S_24W; + break; + default: + printk(KERN_ERR "TWL4030 hw params: unknown format %d\n", + params_format(params)); + return -EINVAL; + } + + if (format != old_format) { + + /* clear CODECPDZ before changing format (codec requirement) */ + twl4030_clear_codecpdz(codec); + + /* change format */ + twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); + + /* set CODECPDZ afterwards */ + twl4030_set_codecpdz(codec); + } + return 0; +} + +static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 infreq; + + switch (freq) { + case 19200000: + infreq = TWL4030_APLL_INFREQ_19200KHZ; + break; + case 26000000: + infreq = TWL4030_APLL_INFREQ_26000KHZ; + break; + case 38400000: + infreq = TWL4030_APLL_INFREQ_38400KHZ; + break; + default: + printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n", + freq); + return -EINVAL; + } + + infreq |= TWL4030_APLL_EN; + twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq); + + return 0; +} + +static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 old_format, format; + + /* get format */ + old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + format = old_format; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + format &= ~(TWL4030_AIF_SLAVE_EN); + format |= TWL4030_CLK256FS_EN; + break; + case SND_SOC_DAIFMT_CBS_CFS: + format &= ~(TWL4030_CLK256FS_EN); + format |= TWL4030_AIF_SLAVE_EN; + break; + default: + return -EINVAL; + } + + /* interface format */ + format &= ~TWL4030_AIF_FORMAT; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + format |= TWL4030_AIF_FORMAT_CODEC; + break; + default: + return -EINVAL; + } + + if (format != old_format) { + + /* clear CODECPDZ before changing format (codec requirement) */ + twl4030_clear_codecpdz(codec); + + /* change format */ + twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); + + /* set CODECPDZ afterwards */ + twl4030_set_codecpdz(codec); + } + + return 0; +} + +#define TWL4030_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) + +struct snd_soc_dai twl4030_dai = { + .name = "twl4030", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = TWL4030_RATES, + .formats = TWL4030_FORMATS,}, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = TWL4030_RATES, + .formats = TWL4030_FORMATS,}, + .ops = { + .hw_params = twl4030_hw_params, + }, + .dai_ops = { + .set_sysclk = twl4030_set_dai_sysclk, + .set_fmt = twl4030_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(twl4030_dai); + +static int twl4030_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int twl4030_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + twl4030_set_bias_level(codec, codec->suspend_bias_level); + return 0; +} + +/* + * initialize the driver + * register the mixer and dsp interfaces with the kernel + */ + +static int twl4030_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int ret = 0; + + printk(KERN_INFO "TWL4030 Audio Codec init \n"); + + codec->name = "twl4030"; + codec->owner = THIS_MODULE; + codec->read = twl4030_read_reg_cache; + codec->write = twl4030_write; + codec->set_bias_level = twl4030_set_bias_level; + codec->dai = &twl4030_dai; + codec->num_dai = 1; + codec->reg_cache_size = sizeof(twl4030_reg); + codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), + GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "twl4030: failed to create pcms\n"); + goto pcm_err; + } + + twl4030_init_chip(codec); + + /* power on device */ + twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + twl4030_add_controls(codec); + twl4030_add_widgets(codec); + + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "twl4030: failed to register card\n"); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +static struct snd_soc_device *twl4030_socdev; + +static int twl4030_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + twl4030_socdev = socdev; + twl4030_init(socdev); + + return 0; +} + +static int twl4030_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + printk(KERN_INFO "TWL4030 Audio Codec remove\n"); + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_twl4030 = { + .probe = twl4030_probe, + .remove = twl4030_remove, + .suspend = twl4030_suspend, + .resume = twl4030_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); + +MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); +MODULE_AUTHOR("Steve Sakoman"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h new file mode 100644 index 000000000000..09865d9f5203 --- /dev/null +++ b/sound/soc/codecs/twl4030.h @@ -0,0 +1,197 @@ +/* + * ALSA SoC TWL4030 codec driver + * + * Author: Steve Sakoman + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef __TWL4030_AUDIO_H__ +#define __TWL4030_AUDIO_H__ + +#define TWL4030_REG_CODEC_MODE 0x1 +#define TWL4030_REG_OPTION 0x2 +#define TWL4030_REG_UNKNOWN 0x3 +#define TWL4030_REG_MICBIAS_CTL 0x4 +#define TWL4030_REG_ANAMICL 0x5 +#define TWL4030_REG_ANAMICR 0x6 +#define TWL4030_REG_AVADC_CTL 0x7 +#define TWL4030_REG_ADCMICSEL 0x8 +#define TWL4030_REG_DIGMIXING 0x9 +#define TWL4030_REG_ATXL1PGA 0xA +#define TWL4030_REG_ATXR1PGA 0xB +#define TWL4030_REG_AVTXL2PGA 0xC +#define TWL4030_REG_AVTXR2PGA 0xD +#define TWL4030_REG_AUDIO_IF 0xE +#define TWL4030_REG_VOICE_IF 0xF +#define TWL4030_REG_ARXR1PGA 0x10 +#define TWL4030_REG_ARXL1PGA 0x11 +#define TWL4030_REG_ARXR2PGA 0x12 +#define TWL4030_REG_ARXL2PGA 0x13 +#define TWL4030_REG_VRXPGA 0x14 +#define TWL4030_REG_VSTPGA 0x15 +#define TWL4030_REG_VRX2ARXPGA 0x16 +#define TWL4030_REG_AVDAC_CTL 0x17 +#define TWL4030_REG_ARX2VTXPGA 0x18 +#define TWL4030_REG_ARXL1_APGA_CTL 0x19 +#define TWL4030_REG_ARXR1_APGA_CTL 0x1A +#define TWL4030_REG_ARXL2_APGA_CTL 0x1B +#define TWL4030_REG_ARXR2_APGA_CTL 0x1C +#define TWL4030_REG_ATX2ARXPGA 0x1D +#define TWL4030_REG_BT_IF 0x1E +#define TWL4030_REG_BTPGA 0x1F +#define TWL4030_REG_BTSTPGA 0x20 +#define TWL4030_REG_EAR_CTL 0x21 +#define TWL4030_REG_HS_SEL 0x22 +#define TWL4030_REG_HS_GAIN_SET 0x23 +#define TWL4030_REG_HS_POPN_SET 0x24 +#define TWL4030_REG_PREDL_CTL 0x25 +#define TWL4030_REG_PREDR_CTL 0x26 +#define TWL4030_REG_PRECKL_CTL 0x27 +#define TWL4030_REG_PRECKR_CTL 0x28 +#define TWL4030_REG_HFL_CTL 0x29 +#define TWL4030_REG_HFR_CTL 0x2A +#define TWL4030_REG_ALC_CTL 0x2B +#define TWL4030_REG_ALC_SET1 0x2C +#define TWL4030_REG_ALC_SET2 0x2D +#define TWL4030_REG_BOOST_CTL 0x2E +#define TWL4030_REG_SOFTVOL_CTL 0x2F +#define TWL4030_REG_DTMF_FREQSEL 0x30 +#define TWL4030_REG_DTMF_TONEXT1H 0x31 +#define TWL4030_REG_DTMF_TONEXT1L 0x32 +#define TWL4030_REG_DTMF_TONEXT2H 0x33 +#define TWL4030_REG_DTMF_TONEXT2L 0x34 +#define TWL4030_REG_DTMF_TONOFF 0x35 +#define TWL4030_REG_DTMF_WANONOFF 0x36 +#define TWL4030_REG_I2S_RX_SCRAMBLE_H 0x37 +#define TWL4030_REG_I2S_RX_SCRAMBLE_M 0x38 +#define TWL4030_REG_I2S_RX_SCRAMBLE_L 0x39 +#define TWL4030_REG_APLL_CTL 0x3A +#define TWL4030_REG_DTMF_CTL 0x3B +#define TWL4030_REG_DTMF_PGA_CTL2 0x3C +#define TWL4030_REG_DTMF_PGA_CTL1 0x3D +#define TWL4030_REG_MISC_SET_1 0x3E +#define TWL4030_REG_PCMBTMUX 0x3F +#define TWL4030_REG_RX_PATH_SEL 0x43 +#define TWL4030_REG_VDL_APGA_CTL 0x44 +#define TWL4030_REG_VIBRA_CTL 0x45 +#define TWL4030_REG_VIBRA_SET 0x46 +#define TWL4030_REG_VIBRA_PWM_SET 0x47 +#define TWL4030_REG_ANAMIC_GAIN 0x48 +#define TWL4030_REG_MISC_SET_2 0x49 + +#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) + +/* Bitfield Definitions */ + +/* TWL4030_CODEC_MODE (0x01) Fields */ + +#define TWL4030_APLL_RATE 0xF0 +#define TWL4030_APLL_RATE_8000 0x00 +#define TWL4030_APLL_RATE_11025 0x10 +#define TWL4030_APLL_RATE_12000 0x20 +#define TWL4030_APLL_RATE_16000 0x40 +#define TWL4030_APLL_RATE_22050 0x50 +#define TWL4030_APLL_RATE_24000 0x60 +#define TWL4030_APLL_RATE_32000 0x80 +#define TWL4030_APLL_RATE_44100 0x90 +#define TWL4030_APLL_RATE_48000 0xA0 +#define TWL4030_SEL_16K 0x04 +#define TWL4030_CODECPDZ 0x02 +#define TWL4030_OPT_MODE 0x01 + +/* ANAMICL (0x05) Fields */ +#define TWL4030_CNCL_OFFSET_START 0x80 +#define TWL4030_OFFSET_CNCL_SEL 0x60 +#define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 +#define TWL4030_OFFSET_CNCL_SEL_ARX2 0x20 +#define TWL4030_OFFSET_CNCL_SEL_VRX 0x40 +#define TWL4030_OFFSET_CNCL_SEL_ALL 0x60 +#define TWL4030_MICAMPL_EN 0x10 +#define TWL4030_CKMIC_EN 0x08 +#define TWL4030_AUXL_EN 0x04 +#define TWL4030_HSMIC_EN 0x02 +#define TWL4030_MAINMIC_EN 0x01 + +/* ANAMICR (0x06) Fields */ +#define TWL4030_MICAMPR_EN 0x10 +#define TWL4030_AUXR_EN 0x04 +#define TWL4030_SUBMIC_EN 0x01 + +/* AUDIO_IF (0x0E) Fields */ + +#define TWL4030_AIF_SLAVE_EN 0x80 +#define TWL4030_DATA_WIDTH 0x60 +#define TWL4030_DATA_WIDTH_16S_16W 0x00 +#define TWL4030_DATA_WIDTH_32S_16W 0x40 +#define TWL4030_DATA_WIDTH_32S_24W 0x60 +#define TWL4030_AIF_FORMAT 0x18 +#define TWL4030_AIF_FORMAT_CODEC 0x00 +#define TWL4030_AIF_FORMAT_LEFT 0x08 +#define TWL4030_AIF_FORMAT_RIGHT 0x10 +#define TWL4030_AIF_FORMAT_TDM 0x18 +#define TWL4030_AIF_TRI_EN 0x04 +#define TWL4030_CLK256FS_EN 0x02 +#define TWL4030_AIF_EN 0x01 + +/* HS_GAIN_SET (0x23) Fields */ + +#define TWL4030_HSR_GAIN 0x0C +#define TWL4030_HSR_GAIN_PWR_DOWN 0x00 +#define TWL4030_HSR_GAIN_PLUS_6DB 0x04 +#define TWL4030_HSR_GAIN_0DB 0x08 +#define TWL4030_HSR_GAIN_MINUS_6DB 0x0C +#define TWL4030_HSL_GAIN 0x03 +#define TWL4030_HSL_GAIN_PWR_DOWN 0x00 +#define TWL4030_HSL_GAIN_PLUS_6DB 0x01 +#define TWL4030_HSL_GAIN_0DB 0x02 +#define TWL4030_HSL_GAIN_MINUS_6DB 0x03 + +/* HS_POPN_SET (0x24) Fields */ + +#define TWL4030_VMID_EN 0x40 +#define TWL4030_EXTMUTE 0x20 +#define TWL4030_RAMP_DELAY 0x1C +#define TWL4030_RAMP_DELAY_20MS 0x00 +#define TWL4030_RAMP_DELAY_40MS 0x04 +#define TWL4030_RAMP_DELAY_81MS 0x08 +#define TWL4030_RAMP_DELAY_161MS 0x0C +#define TWL4030_RAMP_DELAY_323MS 0x10 +#define TWL4030_RAMP_DELAY_645MS 0x14 +#define TWL4030_RAMP_DELAY_1291MS 0x18 +#define TWL4030_RAMP_DELAY_2581MS 0x1C +#define TWL4030_RAMP_EN 0x02 + +/* APLL_CTL (0x3A) Fields */ + +#define TWL4030_APLL_EN 0x10 +#define TWL4030_APLL_INFREQ 0x0F +#define TWL4030_APLL_INFREQ_19200KHZ 0x05 +#define TWL4030_APLL_INFREQ_26000KHZ 0x06 +#define TWL4030_APLL_INFREQ_38400KHZ 0x0F + +/* REG_MISC_SET_1 (0x3E) Fields */ + +#define TWL4030_CLK64_EN 0x80 +#define TWL4030_SCRAMBLE_EN 0x40 +#define TWL4030_FMLOOP_EN 0x20 +#define TWL4030_SMOOTH_ANAVOL_EN 0x02 +#define TWL4030_DIGMIC_LR_SWAP_EN 0x01 + +extern struct snd_soc_dai twl4030_dai; +extern struct snd_soc_codec_device soc_codec_dev_twl4030; + +#endif /* End of __TWL4030_AUDIO_H__ */ From 4e207873736adc55cbf92796eb4f26f280f84034 Mon Sep 17 00:00:00 2001 From: Steve Sakoman Date: Thu, 30 Oct 2008 21:50:13 -0700 Subject: [PATCH 043/367] ASoC: Add support for Gumstix Overo Signed-off-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 10 +++ sound/soc/omap/Makefile | 3 + sound/soc/omap/overo.c | 148 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 sound/soc/omap/overo.c diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 8b7766b998d7..cf40e42954af 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -21,3 +21,13 @@ config SND_OMAP_SOC_OSK5912 select SND_SOC_TLV320AIC23 help Say Y if you want to add support for SoC audio on osk5912. + +config SND_OMAP_SOC_OVERO + tristate "SoC Audio support for Gumstix Overo" + depends on SND_OMAP_SOC && MACH_OVERO + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the Gumstix Overo. + + diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index e09d1f297f64..fefc9bed053a 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -8,6 +8,9 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o # OMAP Machine Support snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o +snd-soc-overo-objs := overo.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o +obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o + diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c new file mode 100644 index 000000000000..c26d1de7da51 --- /dev/null +++ b/sound/soc/omap/overo.c @@ -0,0 +1,148 @@ +/* + * overo.c -- SoC audio for Gumstix Overo + * + * Author: Steve Sakoman + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int overo_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops overo_ops = { + .hw_params = overo_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link overo_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &overo_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_overo = { + .name = "overo", + .dai_link = &overo_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device overo_snd_devdata = { + .machine = &snd_soc_machine_overo, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *overo_snd_device; + +static int __init overo_soc_init(void) +{ + int ret; + + if (!machine_is_overo()) { + pr_debug("Not Overo!\n"); + return -ENODEV; + } + printk(KERN_INFO "overo SoC init\n"); + + overo_snd_device = platform_device_alloc("soc-audio", -1); + if (!overo_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(overo_snd_device, &overo_snd_devdata); + overo_snd_devdata.dev = &overo_snd_device->dev; + *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(overo_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(overo_snd_device); + + return ret; +} +module_init(overo_soc_init); + +static void __exit overo_soc_exit(void) +{ + platform_device_unregister(overo_snd_device); +} +module_exit(overo_soc_exit); + +MODULE_AUTHOR("Steve Sakoman "); +MODULE_DESCRIPTION("ALSA SoC overo"); +MODULE_LICENSE("GPL"); From dc06102a0c8b5aa0dd7f9a40ce241e793c252a87 Mon Sep 17 00:00:00 2001 From: Steve Sakoman Date: Thu, 30 Oct 2008 21:55:24 -0700 Subject: [PATCH 044/367] ASoC: Add support for Beagleboard Signed-off-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/omap/omap3beagle.c | 149 +++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 sound/soc/omap/omap3beagle.c diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c new file mode 100644 index 000000000000..ec84a9bbc563 --- /dev/null +++ b/sound/soc/omap/omap3beagle.c @@ -0,0 +1,149 @@ +/* + * omap3beagle.c -- SoC audio for OMAP3 Beagle + * + * Author: Steve Sakoman + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int omap3beagle_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops omap3beagle_ops = { + .hw_params = omap3beagle_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap3beagle_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap3beagle_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_omap3beagle = { + .name = "omap3beagle", + .dai_link = &omap3beagle_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device omap3beagle_snd_devdata = { + .machine = &snd_soc_machine_omap3beagle, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap3beagle_snd_device; + +static int __init omap3beagle_soc_init(void) +{ + int ret; + + if (!machine_is_omap3_beagle()) { + pr_debug("Not OMAP3 Beagle!\n"); + return -ENODEV; + } + pr_info("OMAP3 Beagle SoC init\n"); + + omap3beagle_snd_device = platform_device_alloc("soc-audio", -1); + if (!omap3beagle_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata); + omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev; + *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(omap3beagle_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(omap3beagle_snd_device); + + return ret; +} + +static void __exit omap3beagle_soc_exit(void) +{ + platform_device_unregister(omap3beagle_snd_device); +} + +module_init(omap3beagle_soc_init); +module_exit(omap3beagle_soc_exit); + +MODULE_AUTHOR("Steve Sakoman "); +MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle"); +MODULE_LICENSE("GPL"); From 6c7425095c9ee23d080dba3e27217a254cce4562 Mon Sep 17 00:00:00 2001 From: Sedji Gaouaou Date: Fri, 3 Oct 2008 16:57:50 +0200 Subject: [PATCH 045/367] ASoC: Merge AT91 and AVR32 support into a single atmel architecture The Ateml AT91 and AVR32 SoC share common IP for audio and can share the same driver code using the atmel-ssc API provided for both architectures. Do this, creating a new unified atmel ASoC architecture to replace the previous at32 and at91 ones. [This was contributed as a patch series for reviewability but has been squashed down to a single commit to help preserve both the history and bisectability. A small bugfix from Jukka is included.] Tested-by: Jukka Hynninen Signed-off-by: Sedji Gaouaou Signed-off-by: Mark Brown --- sound/soc/Kconfig | 3 +- sound/soc/Makefile | 2 +- sound/soc/at32/Kconfig | 34 - sound/soc/at32/Makefile | 11 - sound/soc/at32/at32-pcm.h | 79 -- sound/soc/at32/at32-ssc.c | 849 ------------------ sound/soc/at32/at32-ssc.h | 59 -- sound/soc/at91/Kconfig | 10 - sound/soc/at91/Makefile | 6 - sound/soc/at91/at91-pcm.c | 434 --------- sound/soc/at91/at91-pcm.h | 72 -- sound/soc/at91/at91-ssc.c | 791 ---------------- sound/soc/at91/at91-ssc.h | 27 - sound/soc/atmel/Kconfig | 43 + sound/soc/atmel/Makefile | 15 + .../{at32/at32-pcm.c => atmel/atmel-pcm.c} | 370 ++++---- sound/soc/atmel/atmel-pcm.h | 86 ++ sound/soc/atmel/atmel_ssc_dai.c | 782 ++++++++++++++++ sound/soc/atmel/atmel_ssc_dai.h | 121 +++ sound/soc/{at32 => atmel}/playpaq_wm8510.c | 4 +- 20 files changed, 1232 insertions(+), 2566 deletions(-) delete mode 100644 sound/soc/at32/Kconfig delete mode 100644 sound/soc/at32/Makefile delete mode 100644 sound/soc/at32/at32-pcm.h delete mode 100644 sound/soc/at32/at32-ssc.c delete mode 100644 sound/soc/at32/at32-ssc.h delete mode 100644 sound/soc/at91/Kconfig delete mode 100644 sound/soc/at91/Makefile delete mode 100644 sound/soc/at91/at91-pcm.c delete mode 100644 sound/soc/at91/at91-pcm.h delete mode 100644 sound/soc/at91/at91-ssc.c delete mode 100644 sound/soc/at91/at91-ssc.h create mode 100644 sound/soc/atmel/Kconfig create mode 100644 sound/soc/atmel/Makefile rename sound/soc/{at32/at32-pcm.c => atmel/atmel-pcm.c} (50%) create mode 100644 sound/soc/atmel/atmel-pcm.h create mode 100644 sound/soc/atmel/atmel_ssc_dai.c create mode 100644 sound/soc/atmel/atmel_ssc_dai.h rename sound/soc/{at32 => atmel}/playpaq_wm8510.c (99%) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 4dfda6674bec..615ebf0b76e7 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -23,8 +23,7 @@ config SND_SOC_AC97_BUS bool # All the supported Soc's -source "sound/soc/at32/Kconfig" -source "sound/soc/at91/Kconfig" +source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index d849349f2c66..4d475c3ceb91 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,5 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ at32/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ +obj-$(CONFIG_SND_SOC) += codecs/ atmel/ pxa/ s3c24xx/ sh/ fsl/ davinci/ obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ diff --git a/sound/soc/at32/Kconfig b/sound/soc/at32/Kconfig deleted file mode 100644 index b0765e86c085..000000000000 --- a/sound/soc/at32/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config SND_AT32_SOC - tristate "SoC Audio for the Atmel AT32 System-on-a-Chip" - depends on AVR32 && SND_SOC - help - Say Y or M if you want to add support for codecs attached to - the AT32 SSC interface. You will also need to - to select the audio interfaces to support below. - - -config SND_AT32_SOC_SSC - tristate - - - -config SND_AT32_SOC_PLAYPAQ - tristate "SoC Audio support for PlayPaq with WM8510" - depends on SND_AT32_SOC && BOARD_PLAYPAQ - select SND_AT32_SOC_SSC - select SND_SOC_WM8510 - help - Say Y or M here if you want to add support for SoC audio - on the LRS PlayPaq. - - - -config SND_AT32_SOC_PLAYPAQ_SLAVE - bool "Run CODEC on PlayPaq in slave mode" - depends on SND_AT32_SOC_PLAYPAQ - default n - help - Say Y if you want to run with the AT32 SSC generating the BCLK - and FRAME signals on the PlayPaq. Unless you want to play - with the AT32 as the SSC master, you probably want to say N here, - as this will give you better sound quality. diff --git a/sound/soc/at32/Makefile b/sound/soc/at32/Makefile deleted file mode 100644 index c03e55ececeb..000000000000 --- a/sound/soc/at32/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# AT32 Platform Support -snd-soc-at32-objs := at32-pcm.o -snd-soc-at32-ssc-objs := at32-ssc.o - -obj-$(CONFIG_SND_AT32_SOC) += snd-soc-at32.o -obj-$(CONFIG_SND_AT32_SOC_SSC) += snd-soc-at32-ssc.o - -# AT32 Machine Support -snd-soc-playpaq-objs := playpaq_wm8510.o - -obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o diff --git a/sound/soc/at32/at32-pcm.h b/sound/soc/at32/at32-pcm.h deleted file mode 100644 index 2a52430417da..000000000000 --- a/sound/soc/at32/at32-pcm.h +++ /dev/null @@ -1,79 +0,0 @@ -/* sound/soc/at32/at32-pcm.h - * ASoC PCM interface for Atmel AT32 SoC - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * 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 __SOUND_SOC_AT32_AT32_PCM_H -#define __SOUND_SOC_AT32_AT32_PCM_H __FILE__ - -#include - - -/* - * Registers and status bits that are required by the PCM driver - * TODO: Is ptcr really used? - */ -struct at32_pdc_regs { - u32 xpr; /* PDC RX/TX pointer */ - u32 xcr; /* PDC RX/TX counter */ - u32 xnpr; /* PDC next RX/TX pointer */ - u32 xncr; /* PDC next RX/TX counter */ - u32 ptcr; /* PDC transfer control */ -}; - - - -/* - * SSC mask info - */ -struct at32_ssc_mask { - u32 ssc_enable; /* SSC RX/TX enable */ - u32 ssc_disable; /* SSC RX/TX disable */ - u32 ssc_endx; /* SSC ENDTX or ENDRX */ - u32 ssc_endbuf; /* SSC TXBUFF or RXBUFF */ - u32 pdc_enable; /* PDC RX/TX enable */ - u32 pdc_disable; /* PDC RX/TX disable */ -}; - - - -/* - * This structure, shared between the PCM driver and the interface, - * contains all information required by the PCM driver to perform the - * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dms_intr_handler() pointer is set by the PCM - * driver and called by the interface SSC interrupt handler if it is - * non-NULL. - */ -struct at32_pcm_dma_params { - char *name; /* stream identifier */ - int pdc_xfer_size; /* PDC counter increment in bytes */ - struct ssc_device *ssc; /* SSC device for stream */ - struct at32_pdc_regs *pdc; /* PDC register info */ - struct at32_ssc_mask *mask; /* SSC mask info */ - struct snd_pcm_substream *substream; - void (*dma_intr_handler) (u32, struct snd_pcm_substream *); -}; - - - -/* - * The AT32 ASoC platform driver - */ -extern struct snd_soc_platform at32_soc_platform; - - - -/* - * SSC register access (since ssc_writel() / ssc_readl() require literal name) - */ -#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) -#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) - -#endif /* __SOUND_SOC_AT32_AT32_PCM_H */ diff --git a/sound/soc/at32/at32-ssc.c b/sound/soc/at32/at32-ssc.c deleted file mode 100644 index 4ef6492c902e..000000000000 --- a/sound/soc/at32/at32-ssc.c +++ /dev/null @@ -1,849 +0,0 @@ -/* sound/soc/at32/at32-ssc.c - * ASoC platform driver for AT32 using SSC as DAI - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * 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. - * - * Note that this is basically a port of the sound/soc/at91-ssc.c to - * the AVR32 kernel. Thanks to Frank Mandarino for that code. - */ - -/* #define DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "at32-pcm.h" -#include "at32-ssc.h" - - - -/*-------------------------------------------------------------------------*\ - * Constants -\*-------------------------------------------------------------------------*/ -#define NUM_SSC_DEVICES 3 - -/* - * SSC direction masks - */ -#define SSC_DIR_MASK_UNUSED 0 -#define SSC_DIR_MASK_PLAYBACK 1 -#define SSC_DIR_MASK_CAPTURE 2 - -/* - * SSC register values that Atmel left out of . These - * are expected to be used with SSC_BF - */ -/* START bit field values */ -#define SSC_START_CONTINUOUS 0 -#define SSC_START_TX_RX 1 -#define SSC_START_LOW_RF 2 -#define SSC_START_HIGH_RF 3 -#define SSC_START_FALLING_RF 4 -#define SSC_START_RISING_RF 5 -#define SSC_START_LEVEL_RF 6 -#define SSC_START_EDGE_RF 7 -#define SSS_START_COMPARE_0 8 - -/* CKI bit field values */ -#define SSC_CKI_FALLING 0 -#define SSC_CKI_RISING 1 - -/* CKO bit field values */ -#define SSC_CKO_NONE 0 -#define SSC_CKO_CONTINUOUS 1 -#define SSC_CKO_TRANSFER 2 - -/* CKS bit field values */ -#define SSC_CKS_DIV 0 -#define SSC_CKS_CLOCK 1 -#define SSC_CKS_PIN 2 - -/* FSEDGE bit field values */ -#define SSC_FSEDGE_POSITIVE 0 -#define SSC_FSEDGE_NEGATIVE 1 - -/* FSOS bit field values */ -#define SSC_FSOS_NONE 0 -#define SSC_FSOS_NEGATIVE 1 -#define SSC_FSOS_POSITIVE 2 -#define SSC_FSOS_LOW 3 -#define SSC_FSOS_HIGH 4 -#define SSC_FSOS_TOGGLE 5 - -#define START_DELAY 1 - - - -/*-------------------------------------------------------------------------*\ - * Module data -\*-------------------------------------------------------------------------*/ -/* - * SSC PDC registered required by the PCM DMA engine - */ -static struct at32_pdc_regs pdc_tx_reg = { - .xpr = SSC_PDC_TPR, - .xcr = SSC_PDC_TCR, - .xnpr = SSC_PDC_TNPR, - .xncr = SSC_PDC_TNCR, -}; - - - -static struct at32_pdc_regs pdc_rx_reg = { - .xpr = SSC_PDC_RPR, - .xcr = SSC_PDC_RCR, - .xnpr = SSC_PDC_RNPR, - .xncr = SSC_PDC_RNCR, -}; - - - -/* - * SSC and PDC status bits for transmit and receive - */ -static struct at32_ssc_mask ssc_tx_mask = { - .ssc_enable = SSC_BIT(CR_TXEN), - .ssc_disable = SSC_BIT(CR_TXDIS), - .ssc_endx = SSC_BIT(SR_ENDTX), - .ssc_endbuf = SSC_BIT(SR_TXBUFE), - .pdc_enable = SSC_BIT(PDC_PTCR_TXTEN), - .pdc_disable = SSC_BIT(PDC_PTCR_TXTDIS), -}; - - - -static struct at32_ssc_mask ssc_rx_mask = { - .ssc_enable = SSC_BIT(CR_RXEN), - .ssc_disable = SSC_BIT(CR_RXDIS), - .ssc_endx = SSC_BIT(SR_ENDRX), - .ssc_endbuf = SSC_BIT(SR_RXBUFF), - .pdc_enable = SSC_BIT(PDC_PTCR_RXTEN), - .pdc_disable = SSC_BIT(PDC_PTCR_RXTDIS), -}; - - - -/* - * DMA parameters for each SSC - */ -static struct at32_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { - { - { - .name = "SSC0 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC0 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, - { - { - .name = "SSC1 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, - { - { - .name = "SSC2 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC2 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }, - }, -}; - - - -static struct at32_ssc_info ssc_info[NUM_SSC_DEVICES] = { - { - .name = "ssc0", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc1", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, - { - .name = "ssc2", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), - .dir_mask = SSC_DIR_MASK_UNUSED, - .initialized = 0, - }, -}; - - - - -/*-------------------------------------------------------------------------*\ - * ISR -\*-------------------------------------------------------------------------*/ -/* - * SSC interrupt handler. Passes PDC interrupts to the DMA interrupt - * handler in the PCM driver. - */ -static irqreturn_t at32_ssc_interrupt(int irq, void *dev_id) -{ - struct at32_ssc_info *ssc_p = dev_id; - struct at32_pcm_dma_params *dma_params; - u32 ssc_sr; - u32 ssc_substream_mask; - int i; - - ssc_sr = (ssc_readl(ssc_p->ssc->regs, SR) & - ssc_readl(ssc_p->ssc->regs, IMR)); - - /* - * Loop through substreams attached to this SSC. If a DMA-related - * interrupt occured on that substream, call the DMA interrupt - * handler function, if one has been registered in the dma_param - * structure by the PCM driver. - */ - for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { - dma_params = ssc_p->dma_params[i]; - - if ((dma_params != NULL) && - (dma_params->dma_intr_handler != NULL)) { - ssc_substream_mask = (dma_params->mask->ssc_endx | - dma_params->mask->ssc_endbuf); - if (ssc_sr & ssc_substream_mask) { - dma_params->dma_intr_handler(ssc_sr, - dma_params-> - substream); - } - } - } - - - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*\ - * DAI functions -\*-------------------------------------------------------------------------*/ -/* - * Startup. Only that one substream allowed in each direction. - */ -static int at32_ssc_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - int dir_mask; - - dir_mask = ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? - SSC_DIR_MASK_PLAYBACK : SSC_DIR_MASK_CAPTURE); - - spin_lock_irq(&ssc_p->lock); - if (ssc_p->dir_mask & dir_mask) { - spin_unlock_irq(&ssc_p->lock); - return -EBUSY; - } - ssc_p->dir_mask |= dir_mask; - spin_unlock_irq(&ssc_p->lock); - - return 0; -} - - - -/* - * Shutdown. Clear DMA parameters and shutdown the SSC if there - * are no other substreams open. - */ -static void at32_ssc_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at32_pcm_dma_params *dma_params; - int dir_mask; - - dma_params = ssc_p->dma_params[substream->stream]; - - if (dma_params != NULL) { - ssc_writel(dma_params->ssc->regs, CR, - dma_params->mask->ssc_disable); - pr_debug("%s disabled SSC_SR=0x%08x\n", - (substream->stream ? "receiver" : "transmit"), - ssc_readl(ssc_p->ssc->regs, SR)); - - dma_params->ssc = NULL; - dma_params->substream = NULL; - ssc_p->dma_params[substream->stream] = NULL; - } - - - dir_mask = 1 << substream->stream; - spin_lock_irq(&ssc_p->lock); - ssc_p->dir_mask &= ~dir_mask; - if (!ssc_p->dir_mask) { - /* Shutdown the SSC clock */ - pr_debug("at32-ssc: Stopping user %d clock\n", - ssc_p->ssc->user); - clk_disable(ssc_p->ssc->clk); - - if (ssc_p->initialized) { - free_irq(ssc_p->ssc->irq, ssc_p); - ssc_p->initialized = 0; - } - - /* Reset the SSC */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - - /* clear the SSC dividers */ - ssc_p->cmr_div = 0; - ssc_p->tcmr_period = 0; - ssc_p->rcmr_period = 0; - } - spin_unlock_irq(&ssc_p->lock); -} - - - -/* - * Set the SSC system clock rate - */ -static int at32_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - /* TODO: What the heck do I do here? */ - return 0; -} - - - -/* - * Record DAI format for use by hw_params() - */ -static int at32_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - ssc_p->daifmt = fmt; - return 0; -} - - - -/* - * Record SSC clock dividers for use in hw_params() - */ -static int at32_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct at32_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - switch (div_id) { - case AT32_SSC_CMR_DIV: - /* - * The same master clock divider is used for both - * transmit and receive, so if a value has already - * been set, it must match this value - */ - if (ssc_p->cmr_div == 0) - ssc_p->cmr_div = div; - else if (div != ssc_p->cmr_div) - return -EBUSY; - break; - - case AT32_SSC_TCMR_PERIOD: - ssc_p->tcmr_period = div; - break; - - case AT32_SSC_RCMR_PERIOD: - ssc_p->rcmr_period = div; - break; - - default: - return -EINVAL; - } - - return 0; -} - - - -/* - * Configure the SSC - */ -static int at32_ssc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int id = rtd->dai->cpu_dai->id; - struct at32_ssc_info *ssc_p = &ssc_info[id]; - struct at32_pcm_dma_params *dma_params; - int channels, bits; - u32 tfmr, rfmr, tcmr, rcmr; - int start_event; - int ret; - - - /* - * Currently, there is only one set of dma_params for each direction. - * If more are added, this code will have to be changed to select - * the proper set - */ - dma_params = &ssc_dma_params[id][substream->stream]; - dma_params->ssc = ssc_p->ssc; - dma_params->substream = substream; - - ssc_p->dma_params[substream->stream] = dma_params; - - - /* - * The cpu_dai->dma_data field is only used to communicate the - * appropriate DMA parameters to the PCM driver's hw_params() - * function. It should not be used for other purposes as it - * is common to all substreams. - */ - rtd->dai->cpu_dai->dma_data = dma_params; - - channels = params_channels(params); - - - /* - * Determine sample size in bits and the PDC increment - */ - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - bits = 8; - dma_params->pdc_xfer_size = 1; - break; - - case SNDRV_PCM_FORMAT_S16: - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - - case SNDRV_PCM_FORMAT_S24: - bits = 24; - dma_params->pdc_xfer_size = 4; - break; - - case SNDRV_PCM_FORMAT_S32: - bits = 32; - dma_params->pdc_xfer_size = 4; - break; - - default: - pr_warning("at32-ssc: Unsupported PCM format %d", - params_format(params)); - return -EINVAL; - } - pr_debug("at32-ssc: bits = %d, pdc_xfer_size = %d, channels = %d\n", - bits, dma_params->pdc_xfer_size, channels); - - - /* - * The SSC only supports up to 16-bit samples in I2S format, due - * to the size of the Frame Mode Register FSLEN field. - */ - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) - if (bits > 16) { - pr_warning("at32-ssc: " - "sample size %d is too large for I2S\n", - bits); - return -EINVAL; - } - - - /* - * Compute the SSC register settings - */ - switch (ssc_p->daifmt & (SND_SOC_DAIFMT_FORMAT_MASK | - SND_SOC_DAIFMT_MASTER_MASK)) { - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - /* - * I2S format, SSC provides BCLK and LRS clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line - */ - pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME master\n"); - rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | - SSC_BF(RCMR_STTDLY, START_DELAY) | - SSC_BF(RCMR_START, SSC_START_FALLING_RF) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_DIV)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) | - SSC_BF(RFMR_FSLEN, bits - 1) | - SSC_BF(RFMR_DATNB, channels - 1) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | - SSC_BF(TCMR_STTDLY, START_DELAY) | - SSC_BF(TCMR_START, SSC_START_FALLING_RF) | - SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | - SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | - SSC_BF(TCMR_CKS, SSC_CKS_DIV)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) | - SSC_BF(TFMR_FSLEN, bits - 1) | - SSC_BF(TFMR_DATNB, channels - 1) | SSC_BIT(TFMR_MSBF) | - SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* - * I2S format, CODEC supplies BCLK and LRC clock. - * - * The SSC transmit clock is obtained from the BCLK signal - * on the TK line, and the SSC receive clock is generated from - * the transmit clock. - * - * For single channel data, one sample is transferred on the - * falling edge of the LRC clock. For two channel data, one - * sample is transferred on both edges of the LRC clock. - */ - pr_debug("at32-ssc: SSC mode is I2S BCLK / FRAME slave\n"); - start_event = ((channels == 1) ? - SSC_START_FALLING_RF : SSC_START_EDGE_RF); - - rcmr = (SSC_BF(RCMR_STTDLY, START_DELAY) | - SSC_BF(RCMR_START, start_event) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_CLOCK)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_STTDLY, START_DELAY) | - SSC_BF(TCMR_START, start_event) | - SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | - SSC_BF(TCMR_CKO, SSC_CKO_NONE) | - SSC_BF(TCMR_CKS, SSC_CKS_PIN)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) | - SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line - */ - pr_debug("at32-ssc: SSC mode is DSP A BCLK / FRAME master\n"); - rcmr = (SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | - SSC_BF(RCMR_STTDLY, 1) | - SSC_BF(RCMR_START, SSC_START_RISING_RF) | - SSC_BF(RCMR_CKI, SSC_CKI_RISING) | - SSC_BF(RCMR_CKO, SSC_CKO_NONE) | - SSC_BF(RCMR_CKS, SSC_CKS_DIV)); - - rfmr = (SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) | - SSC_BF(RFMR_DATNB, channels - 1) | - SSC_BIT(RFMR_MSBF) | SSC_BF(RFMR_DATLEN, bits - 1)); - - tcmr = (SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) | - SSC_BF(TCMR_STTDLY, 1) | - SSC_BF(TCMR_START, SSC_START_RISING_RF) | - SSC_BF(TCMR_CKI, SSC_CKI_RISING) | - SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) | - SSC_BF(TCMR_CKS, SSC_CKS_DIV)); - - tfmr = (SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | - SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) | - SSC_BF(TFMR_DATNB, channels - 1) | - SSC_BIT(TFMR_MSBF) | SSC_BF(TFMR_DATLEN, bits - 1)); - break; - - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - default: - pr_warning("at32-ssc: unsupported DAI format 0x%x\n", - ssc_p->daifmt); - return -EINVAL; - break; - } - pr_debug("at32-ssc: RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", - rcmr, rfmr, tcmr, tfmr); - - - if (!ssc_p->initialized) { - /* enable peripheral clock */ - pr_debug("at32-ssc: Starting clock\n"); - clk_enable(ssc_p->ssc->clk); - - /* Reset the SSC and its PDC registers */ - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); - - ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); - - ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); - ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); - - ret = request_irq(ssc_p->ssc->irq, at32_ssc_interrupt, 0, - ssc_p->name, ssc_p); - if (ret < 0) { - pr_warning("at32-ssc: request irq failed (%d)\n", ret); - pr_debug("at32-ssc: Stopping clock\n"); - clk_disable(ssc_p->ssc->clk); - return ret; - } - - ssc_p->initialized = 1; - } - - /* Set SSC clock mode register */ - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); - - /* set receive clock mode and format */ - ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); - - /* set transmit clock mode and format */ - ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); - ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); - - pr_debug("at32-ssc: SSC initialized\n"); - return 0; -} - - - -static int at32_ssc_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at32_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at32_pcm_dma_params *dma_params; - - dma_params = ssc_p->dma_params[substream->stream]; - - ssc_writel(dma_params->ssc->regs, CR, dma_params->mask->ssc_enable); - - return 0; -} - - - -#ifdef CONFIG_PM -static int at32_ssc_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at32_ssc_info *ssc_p; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* Save the status register before disabling transmit and receive */ - ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); - ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); - - /* Save the current interrupt mask, then disable unmasked interrupts */ - ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); - ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); - - ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); - ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); - ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); - ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); - ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); - - return 0; -} - - - -static int at32_ssc_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at32_ssc_info *ssc_p; - u32 cr; - - if (!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* restore SSC register settings */ - ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); - ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); - ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); - ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); - - /* re-enable interrupts */ - ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); - - /* Re-enable recieve and transmit as appropriate */ - cr = 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; - cr |= - (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; - ssc_writel(ssc_p->ssc->regs, CR, cr); - - return 0; -} -#else /* CONFIG_PM */ -# define at32_ssc_suspend NULL -# define at32_ssc_resume NULL -#endif /* CONFIG_PM */ - - -#define AT32_SSC_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | 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) - - -#define AT32_SSC_FORMATS \ - (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16 | \ - SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_S32) - - -struct snd_soc_dai at32_ssc_dai[NUM_SSC_DEVICES] = { - { - .name = "at32-ssc0", - .id = 0, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[0], - }, - { - .name = "at32-ssc1", - .id = 1, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[1], - }, - { - .name = "at32-ssc2", - .id = 2, - .type = SND_SOC_DAI_PCM, - .suspend = at32_ssc_suspend, - .resume = at32_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT32_SSC_RATES, - .formats = AT32_SSC_FORMATS, - }, - .ops = { - .startup = at32_ssc_startup, - .shutdown = at32_ssc_shutdown, - .prepare = at32_ssc_prepare, - .hw_params = at32_ssc_hw_params, - }, - .dai_ops = { - .set_sysclk = at32_ssc_set_dai_sysclk, - .set_fmt = at32_ssc_set_dai_fmt, - .set_clkdiv = at32_ssc_set_dai_clkdiv, - }, - .private_data = &ssc_info[2], - }, -}; -EXPORT_SYMBOL_GPL(at32_ssc_dai); - - -MODULE_AUTHOR("Geoffrey Wossum "); -MODULE_DESCRIPTION("AT32 SSC ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at32/at32-ssc.h b/sound/soc/at32/at32-ssc.h deleted file mode 100644 index 3c052dbbe460..000000000000 --- a/sound/soc/at32/at32-ssc.h +++ /dev/null @@ -1,59 +0,0 @@ -/* sound/soc/at32/at32-ssc.h - * ASoC SSC interface for Atmel AT32 SoC - * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum - * - * 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 __SOUND_SOC_AT32_AT32_SSC_H -#define __SOUND_SOC_AT32_AT32_SSC_H __FILE__ - -#include -#include - -#include "at32-pcm.h" - - - -struct at32_ssc_state { - u32 ssc_cmr; - u32 ssc_rcmr; - u32 ssc_rfmr; - u32 ssc_tcmr; - u32 ssc_tfmr; - u32 ssc_sr; - u32 ssc_imr; -}; - - - -struct at32_ssc_info { - char *name; - struct ssc_device *ssc; - spinlock_t lock; /* lock for dir_mask */ - unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ - unsigned short initialized; /* true if SSC has been initialized */ - unsigned short daifmt; - unsigned short cmr_div; - unsigned short tcmr_period; - unsigned short rcmr_period; - struct at32_pcm_dma_params *dma_params[2]; - struct at32_ssc_state ssc_state; -}; - - -/* SSC divider ids */ -#define AT32_SSC_CMR_DIV 0 /* MCK divider for BCLK */ -#define AT32_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ -#define AT32_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ - - -extern struct snd_soc_dai at32_ssc_dai[]; - - - -#endif /* __SOUND_SOC_AT32_AT32_SSC_H */ diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig deleted file mode 100644 index 85a883299c2e..000000000000 --- a/sound/soc/at91/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config SND_AT91_SOC - tristate "SoC Audio for the Atmel AT91 System-on-Chip" - depends on ARCH_AT91 - help - Say Y or M if you want to add support for codecs attached to - the AT91 SSC interface. You will also need - to select the audio interfaces to support below. - -config SND_AT91_SOC_SSC - tristate diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile deleted file mode 100644 index b817f11df286..000000000000 --- a/sound/soc/at91/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# AT91 Platform Support -snd-soc-at91-objs := at91-pcm.o -snd-soc-at91-ssc-objs := at91-ssc.o - -obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o -obj-$(CONFIG_SND_AT91_SOC_SSC) += snd-soc-at91-ssc.o diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c deleted file mode 100644 index 7ab48bd25e4c..000000000000 --- a/sound/soc/at91/at91-pcm.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * Created: Mar 3, 2006 - * - * 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 version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "at91-pcm.h" - -#if 0 -#define DBG(x...) printk(KERN_INFO "at91-pcm: " x) -#else -#define DBG(x...) -#endif - -static const struct snd_pcm_hardware at91_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, -}; - -struct at91_runtime_data { - struct at91_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 */ - u32 pdc_xpr_save; /* PDC register save */ - u32 pdc_xcr_save; - u32 pdc_xnpr_save; - u32 pdc_xncr_save; -}; - -static void at91_pcm_dma_irq(u32 ssc_sr, - struct snd_pcm_substream *substream) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - static int count = 0; - - count++; - - if (ssc_sr & params->mask->ssc_endbuf) { - - printk(KERN_WARNING - "at91-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 */ - at91_ssc_write(params->ssc_base + 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; - } - - at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); - at91_ssc_write(params->ssc_base + params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - at91_ssc_write(params->ssc_base + 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; - } - at91_ssc_write(params->ssc_base + params->pdc->xnpr, - prtd->period_ptr); - at91_ssc_write(params->ssc_base + params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - } - - snd_pcm_period_elapsed(substream); -} - -static int at91_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at91_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 = rtd->dai->cpu_dai->dma_data; - prtd->params->dma_intr_handler = at91_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); - - DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n", - prtd->params->name, runtime->dma_bytes, prtd->period_size); - return 0; -} - -static int at91_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - - if (params != NULL) { - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - prtd->params->dma_intr_handler = NULL; - } - - return 0; -} - -static int at91_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - - at91_ssc_write(params->ssc_base + AT91_SSC_IDR, - params->mask->ssc_endx | params->mask->ssc_endbuf); - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - return 0; -} - -static int at91_pcm_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - prtd->period_ptr = prtd->dma_buffer; - - at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr); - at91_ssc_write(params->ssc_base + params->pdc->xcr, - prtd->period_size / params->pdc_xfer_size); - - prtd->period_ptr += prtd->period_size; - at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr); - at91_ssc_write(params->ssc_base + params->pdc->xncr, - prtd->period_size / params->pdc_xfer_size); - - DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n", - (unsigned long) prtd->period_ptr, - at91_ssc_read(params->ssc_base + params->pdc->xpr), - at91_ssc_read(params->ssc_base + params->pdc->xcr), - at91_ssc_read(params->ssc_base + params->pdc->xnpr), - at91_ssc_read(params->ssc_base + params->pdc->xncr)); - - at91_ssc_write(params->ssc_base + AT91_SSC_IER, - params->mask->ssc_endx | params->mask->ssc_endbuf); - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, - params->mask->pdc_enable); - - DBG("sr=%lx imr=%lx\n", - at91_ssc_read(params->ssc_base + AT91_SSC_SR), - at91_ssc_read(params->ssc_base + AT91_SSC_IMR)); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - break; - - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -static snd_pcm_uframes_t at91_pcm_pointer( - struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at91_runtime_data *prtd = runtime->private_data; - struct at91_pcm_dma_params *params = prtd->params; - dma_addr_t ptr; - snd_pcm_uframes_t x; - - ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr); - x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); - - if (x == runtime->buffer_size) - x = 0; - return x; -} - -static int at91_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct at91_runtime_data *prtd; - int ret = 0; - - snd_soc_set_runtime_hwparams(substream, &at91_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 at91_runtime_data), GFP_KERNEL); - if (prtd == NULL) { - ret = -ENOMEM; - goto out; - } - runtime->private_data = prtd; - - out: - return ret; -} - -static int at91_pcm_close(struct snd_pcm_substream *substream) -{ - struct at91_runtime_data *prtd = substream->runtime->private_data; - - kfree(prtd); - return 0; -} - -static int at91_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - return dma_mmap_writecombine(substream->pcm->card->dev, vma, - runtime->dma_area, - runtime->dma_addr, - runtime->dma_bytes); -} - -struct snd_pcm_ops at91_pcm_ops = { - .open = at91_pcm_open, - .close = at91_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = at91_pcm_hw_params, - .hw_free = at91_pcm_hw_free, - .prepare = at91_pcm_prepare, - .trigger = at91_pcm_trigger, - .pointer = at91_pcm_pointer, - .mmap = at91_pcm_mmap, -}; - -static int at91_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 = at91_pcm_hardware.buffer_bytes_max; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = pcm->card->dev; - buf->private_data = NULL; - buf->area = dma_alloc_writecombine(pcm->card->dev, size, - &buf->addr, GFP_KERNEL); - - DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, - (void *) buf->addr, - size); - - if (!buf->area) - return -ENOMEM; - - buf->bytes = size; - return 0; -} - -static u64 at91_pcm_dmamask = 0xffffffff; - -static int at91_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, struct snd_pcm *pcm) -{ - int ret = 0; - - if (!card->dev->dma_mask) - card->dev->dma_mask = &at91_pcm_dmamask; - if (!card->dev->coherent_dma_mask) - card->dev->coherent_dma_mask = 0xffffffff; - - if (dai->playback.channels_min) { - ret = at91_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret) - goto out; - } - - if (dai->capture.channels_min) { - ret = at91_pcm_preallocate_dma_buffer(pcm, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) - goto out; - } - out: - return ret; -} - -static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm) -{ - struct snd_pcm_substream *substream; - struct snd_dma_buffer *buf; - int stream; - - for (stream = 0; stream < 2; stream++) { - substream = pcm->streams[stream].substream; - if (!substream) - continue; - - buf = &substream->dma_buffer; - if (!buf->area) - continue; - - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } -} - -#ifdef CONFIG_PM -static int at91_pcm_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at91_runtime_data *prtd; - struct at91_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* disable the PDC and save the PDC registers */ - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable); - - prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr); - prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr); - prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr); - prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr); - - return 0; -} - -static int at91_pcm_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) -{ - struct snd_pcm_runtime *runtime = dai->runtime; - struct at91_runtime_data *prtd; - struct at91_pcm_dma_params *params; - - if (!runtime) - return 0; - - prtd = runtime->private_data; - params = prtd->params; - - /* restore the PDC registers and enable the PDC */ - at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save); - at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save); - at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save); - at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save); - - at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable); - return 0; -} -#else -#define at91_pcm_suspend NULL -#define at91_pcm_resume NULL -#endif - -struct snd_soc_platform at91_soc_platform = { - .name = "at91-audio", - .pcm_ops = &at91_pcm_ops, - .pcm_new = at91_pcm_new, - .pcm_free = at91_pcm_free_dma_buffers, - .suspend = at91_pcm_suspend, - .resume = at91_pcm_resume, -}; - -EXPORT_SYMBOL_GPL(at91_soc_platform); - -MODULE_AUTHOR("Frank Mandarino "); -MODULE_DESCRIPTION("Atmel AT91 PCM module"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h deleted file mode 100644 index e5aada2cb102..000000000000 --- a/sound/soc/at91/at91-pcm.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * Created: Mar 3, 2006 - * - * Based on pxa2xx-pcm.h by: - * - * Author: Nicolas Pitre - * Created: Nov 30, 2004 - * Copyright: 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 version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _AT91_PCM_H -#define _AT91_PCM_H - -#include - -struct at91_ssc_periph { - void __iomem *base; - u32 pid; -}; - -/* - * Registers and status bits that are required by the PCM driver. - */ -struct at91_pdc_regs { - unsigned int xpr; /* PDC recv/trans pointer */ - unsigned int xcr; /* PDC recv/trans counter */ - unsigned int xnpr; /* PDC next recv/trans pointer */ - unsigned int xncr; /* PDC next recv/trans counter */ - unsigned int ptcr; /* PDC transfer control */ -}; - -struct at91_ssc_mask { - u32 ssc_enable; /* SSC recv/trans enable */ - u32 ssc_disable; /* SSC recv/trans disable */ - u32 ssc_endx; /* SSC ENDTX or ENDRX */ - u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ - u32 pdc_enable; /* PDC recv/trans enable */ - u32 pdc_disable; /* PDC recv/trans disable */ -}; - -/* - * This structure, shared between the PCM driver and the interface, - * contains all information required by the PCM driver to perform the - * PDC DMA operation. All fields except dma_intr_handler() are initialized - * by the interface. The dms_intr_handler() pointer is set by the PCM - * driver and called by the interface SSC interrupt handler if it is - * non-NULL. - */ -struct at91_pcm_dma_params { - char *name; /* stream identifier */ - int pdc_xfer_size; /* PDC counter increment in bytes */ - void __iomem *ssc_base; /* SSC base address */ - struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */ - struct at91_ssc_mask *mask;/* SSC & PDC status bits */ - struct snd_pcm_substream *substream; - void (*dma_intr_handler)(u32, struct snd_pcm_substream *); -}; - -extern struct snd_soc_platform at91_soc_platform; - -#define at91_ssc_read(a) ((unsigned long) __raw_readl(a)) -#define at91_ssc_write(a,v) __raw_writel((v),(a)) - -#endif /* _AT91_PCM_H */ diff --git a/sound/soc/at91/at91-ssc.c b/sound/soc/at91/at91-ssc.c deleted file mode 100644 index 1b61cc461261..000000000000 --- a/sound/soc/at91/at91-ssc.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * at91-ssc.c -- ALSA SoC AT91 SSC Audio Layer Platform driver - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * - * Based on pxa2xx Platform drivers by - * Liam Girdwood - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "at91-pcm.h" -#include "at91-ssc.h" - -#if 0 -#define DBG(x...) printk(KERN_DEBUG "at91-ssc:" x) -#else -#define DBG(x...) -#endif - -#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. - */ -static struct at91_pdc_regs pdc_tx_reg = { - .xpr = ATMEL_PDC_TPR, - .xcr = ATMEL_PDC_TCR, - .xnpr = ATMEL_PDC_TNPR, - .xncr = ATMEL_PDC_TNCR, -}; - -static struct at91_pdc_regs pdc_rx_reg = { - .xpr = ATMEL_PDC_RPR, - .xcr = ATMEL_PDC_RCR, - .xnpr = ATMEL_PDC_RNPR, - .xncr = ATMEL_PDC_RNCR, -}; - -/* - * SSC & PDC status bits for transmit and receive. - */ -static struct at91_ssc_mask ssc_tx_mask = { - .ssc_enable = AT91_SSC_TXEN, - .ssc_disable = AT91_SSC_TXDIS, - .ssc_endx = AT91_SSC_ENDTX, - .ssc_endbuf = AT91_SSC_TXBUFE, - .pdc_enable = ATMEL_PDC_TXTEN, - .pdc_disable = ATMEL_PDC_TXTDIS, -}; - -static struct at91_ssc_mask ssc_rx_mask = { - .ssc_enable = AT91_SSC_RXEN, - .ssc_disable = AT91_SSC_RXDIS, - .ssc_endx = AT91_SSC_ENDRX, - .ssc_endbuf = AT91_SSC_RXBUFF, - .pdc_enable = ATMEL_PDC_RXTEN, - .pdc_disable = ATMEL_PDC_RXTDIS, -}; - - -/* - * DMA parameters. - */ -static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { - {{ - .name = "SSC0 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC0 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }}, -#if NUM_SSC_DEVICES == 3 - {{ - .name = "SSC1 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC1 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }}, - {{ - .name = "SSC2 PCM out", - .pdc = &pdc_tx_reg, - .mask = &ssc_tx_mask, - }, - { - .name = "SSC2 PCM in", - .pdc = &pdc_rx_reg, - .mask = &ssc_rx_mask, - }}, -#endif -}; - -struct at91_ssc_state { - u32 ssc_cmr; - u32 ssc_rcmr; - u32 ssc_rfmr; - u32 ssc_tcmr; - u32 ssc_tfmr; - u32 ssc_sr; - u32 ssc_imr; -}; - -static struct at91_ssc_info { - char *name; - struct at91_ssc_periph ssc; - spinlock_t lock; /* lock for dir_mask */ - unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ - unsigned short initialized; /* 1=SSC has been initialized */ - unsigned short daifmt; - unsigned short cmr_div; - unsigned short tcmr_period; - unsigned short rcmr_period; - struct at91_pcm_dma_params *dma_params[2]; - struct at91_ssc_state ssc_state; - -} ssc_info[NUM_SSC_DEVICES] = { - { - .name = "ssc0", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), - .dir_mask = 0, - .initialized = 0, - }, -#if NUM_SSC_DEVICES == 3 - { - .name = "ssc1", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), - .dir_mask = 0, - .initialized = 0, - }, - { - .name = "ssc2", - .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), - .dir_mask = 0, - .initialized = 0, - }, -#endif -}; - -static unsigned int at91_ssc_sysclk; - -/* - * SSC interrupt handler. Passes PDC interrupts to the DMA - * interrupt handler in the PCM driver. - */ -static irqreturn_t at91_ssc_interrupt(int irq, void *dev_id) -{ - struct at91_ssc_info *ssc_p = dev_id; - struct at91_pcm_dma_params *dma_params; - u32 ssc_sr; - int i; - - ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR) - & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); - - /* - * Loop through the substreams attached to this SSC. If - * a DMA-related interrupt occurred on that substream, call - * the DMA interrupt handler function, if one has been - * registered in the dma_params structure by the PCM driver. - */ - for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { - dma_params = ssc_p->dma_params[i]; - - if (dma_params != NULL && dma_params->dma_intr_handler != NULL && - (ssc_sr & - (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf))) - - dma_params->dma_intr_handler(ssc_sr, dma_params->substream); - } - - return IRQ_HANDLED; -} - -/* - * Startup. Only that one substream allowed in each direction. - */ -static int at91_ssc_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - int dir_mask; - - DBG("ssc_startup: SSC_SR=0x%08lx\n", - at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); - dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2; - - spin_lock_irq(&ssc_p->lock); - if (ssc_p->dir_mask & dir_mask) { - spin_unlock_irq(&ssc_p->lock); - return -EBUSY; - } - ssc_p->dir_mask |= dir_mask; - spin_unlock_irq(&ssc_p->lock); - - return 0; -} - -/* - * Shutdown. Clear DMA parameters and shutdown the SSC if there - * are no other substreams open. - */ -static void at91_ssc_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at91_pcm_dma_params *dma_params; - int dir, dir_mask; - - dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - dma_params = ssc_p->dma_params[dir]; - - if (dma_params != NULL) { - at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, - dma_params->mask->ssc_disable); - DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"), - at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)); - - dma_params->ssc_base = NULL; - dma_params->substream = NULL; - ssc_p->dma_params[dir] = NULL; - } - - dir_mask = 1 << dir; - - spin_lock_irq(&ssc_p->lock); - ssc_p->dir_mask &= ~dir_mask; - if (!ssc_p->dir_mask) { - /* Shutdown the SSC clock. */ - DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); - at91_sys_write(AT91_PMC_PCDR, 1<ssc.pid); - - if (ssc_p->initialized) { - free_irq(ssc_p->ssc.pid, ssc_p); - ssc_p->initialized = 0; - } - - /* Reset the SSC */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); - - /* Clear the SSC dividers */ - ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; - } - spin_unlock_irq(&ssc_p->lock); -} - -/* - * Record the SSC system clock rate. - */ -static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) -{ - /* - * The only clock supplied to the SSC is the AT91 master clock, - * which is only used if the SSC is generating BCLK and/or - * LRC clocks. - */ - switch (clk_id) { - case AT91_SYSCLK_MCK: - at91_ssc_sysclk = freq; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* - * Record the DAI format for use in hw_params(). - */ -static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) -{ - struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - ssc_p->daifmt = fmt; - return 0; -} - -/* - * Record SSC clock dividers for use in hw_params(). - */ -static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) -{ - struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; - - switch (div_id) { - case AT91SSC_CMR_DIV: - /* - * The same master clock divider is used for both - * transmit and receive, so if a value has already - * been set, it must match this value. - */ - if (ssc_p->cmr_div == 0) - ssc_p->cmr_div = div; - else - if (div != ssc_p->cmr_div) - return -EBUSY; - break; - - case AT91SSC_TCMR_PERIOD: - ssc_p->tcmr_period = div; - break; - - case AT91SSC_RCMR_PERIOD: - ssc_p->rcmr_period = div; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * Configure the SSC. - */ -static int at91_ssc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - int id = rtd->dai->cpu_dai->id; - struct at91_ssc_info *ssc_p = &ssc_info[id]; - struct at91_pcm_dma_params *dma_params; - int dir, channels, bits; - u32 tfmr, rfmr, tcmr, rcmr; - int start_event; - int ret; - - /* - * Currently, there is only one set of dma params for - * each direction. If more are added, this code will - * have to be changed to select the proper set. - */ - dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - - dma_params = &ssc_dma_params[id][dir]; - dma_params->ssc_base = ssc_p->ssc.base; - dma_params->substream = substream; - - ssc_p->dma_params[dir] = dma_params; - - /* - * The cpu_dai->dma_data field is only used to communicate the - * appropriate DMA parameters to the pcm driver hw_params() - * function. It should not be used for other purposes - * as it is common to all substreams. - */ - rtd->dai->cpu_dai->dma_data = dma_params; - - channels = params_channels(params); - - /* - * Determine sample size in bits and the PDC increment. - */ - switch(params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - bits = 8; - dma_params->pdc_xfer_size = 1; - break; - case SNDRV_PCM_FORMAT_S16_LE: - bits = 16; - dma_params->pdc_xfer_size = 2; - break; - case SNDRV_PCM_FORMAT_S24_LE: - bits = 24; - dma_params->pdc_xfer_size = 4; - break; - case SNDRV_PCM_FORMAT_S32_LE: - bits = 32; - dma_params->pdc_xfer_size = 4; - break; - default: - printk(KERN_WARNING "at91-ssc: unsupported PCM format\n"); - return -EINVAL; - } - - /* - * The SSC only supports up to 16-bit samples in I2S format, due - * to the size of the Frame Mode Register FSLEN field. - */ - if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S - && bits > 16) { - printk(KERN_WARNING - "at91-ssc: sample size %d is too large for I2S\n", bits); - return -EINVAL; - } - - /* - * Compute SSC register settings. - */ - switch (ssc_p->daifmt - & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: - /* - * I2S format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line. - */ - rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) - | (((bits - 1) << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_LOOP) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( 0 << 23) & AT91_SSC_FSDEN) - | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS) - | (((bits - 1) << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_DATDEF) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - break; - - case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: - /* - * I2S format, CODEC supplies BCLK and LRC clocks. - * - * The SSC transmit clock is obtained from the BCLK signal on - * on the TK line, and the SSC receive clock is generated from the - * transmit clock. - * - * For single channel data, one sample is transferred on the falling - * edge of the LRC clock. For two channel data, one sample is - * transferred on both edges of the LRC clock. - */ - start_event = channels == 1 - ? AT91_SSC_START_FALLING_RF - : AT91_SSC_START_EDGE_RF; - - rcmr = (( 0 << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( start_event ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS); - - rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (( 0 << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_LOOP) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - tcmr = (( 0 << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( start_event ) & AT91_SSC_START) - | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS); - - tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( 0 << 23) & AT91_SSC_FSDEN) - | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (( 0 << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_DATDEF) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - break; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: - /* - * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. - * - * The SSC transmit and receive clocks are generated from the - * MCK divider, and the BCLK signal is output on the SSC TK line. - */ - rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_LOOP) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD) - | (( 1 << 16) & AT91_SSC_STTDLY) - | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START) - | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI) - | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO) - | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS); - - tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE) - | (( 0 << 23) & AT91_SSC_FSDEN) - | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS) - | (( 0 << 16) & AT91_SSC_FSLEN) - | (((channels - 1) << 8) & AT91_SSC_DATNB) - | (( 1 << 7) & AT91_SSC_MSBF) - | (( 0 << 5) & AT91_SSC_DATDEF) - | (((bits - 1) << 0) & AT91_SSC_DATALEN); - - - - break; - - case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: - default: - printk(KERN_WARNING "at91-ssc: unsupported DAI format 0x%x.\n", - ssc_p->daifmt); - return -EINVAL; - break; - } - DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr); - - if (!ssc_p->initialized) { - - /* Enable PMC peripheral clock for this SSC */ - DBG("Starting pid %d clock\n", ssc_p->ssc.pid); - at91_sys_write(AT91_PMC_PCER, 1<ssc.pid); - - /* Reset the SSC and its PDC registers */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST); - - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0); - at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0); - - if ((ret = request_irq(ssc_p->ssc.pid, at91_ssc_interrupt, - 0, ssc_p->name, ssc_p)) < 0) { - printk(KERN_WARNING "at91-ssc: request_irq failure\n"); - - DBG("Stopping pid %d clock\n", ssc_p->ssc.pid); - at91_sys_write(AT91_PMC_PCDR, 1<ssc.pid); - return ret; - } - - ssc_p->initialized = 1; - } - - /* set SSC clock mode register */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div); - - /* set receive clock mode and format */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr); - - /* set transmit clock mode and format */ - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr); - - DBG("hw_params: SSC initialized\n"); - return 0; -} - - -static int at91_ssc_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; - struct at91_pcm_dma_params *dma_params; - int dir; - - dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; - dma_params = ssc_p->dma_params[dir]; - - at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR, - dma_params->mask->ssc_enable); - - DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit", - at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR)); - return 0; -} - - -#ifdef CONFIG_PM -static int at91_ssc_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at91_ssc_info *ssc_p; - - if(!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - /* Save the status register before disabling transmit and receive. */ - ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, - AT91_SSC_TXDIS | AT91_SSC_RXDIS); - - /* Save the current interrupt mask, then disable unmasked interrupts. */ - ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr); - - ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR); - ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR); - ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR); - ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR); - ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR); - - return 0; -} - -static int at91_ssc_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) -{ - struct at91_ssc_info *ssc_p; - - if(!cpu_dai->active) - return 0; - - ssc_p = &ssc_info[cpu_dai->id]; - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr); - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr); - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr); - - at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, - ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) | - ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0)); - - return 0; -} - -#else -#define at91_ssc_suspend NULL -#define at91_ssc_resume NULL -#endif - -#define AT91_SSC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ - 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) - -#define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) - -struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = { - { .name = "at91-ssc0", - .id = 0, - .type = SND_SOC_DAI_PCM, - .suspend = at91_ssc_suspend, - .resume = at91_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .ops = { - .startup = at91_ssc_startup, - .shutdown = at91_ssc_shutdown, - .prepare = at91_ssc_prepare, - .hw_params = at91_ssc_hw_params,}, - .dai_ops = { - .set_sysclk = at91_ssc_set_dai_sysclk, - .set_fmt = at91_ssc_set_dai_fmt, - .set_clkdiv = at91_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[0].ssc, - }, -#if NUM_SSC_DEVICES == 3 - { .name = "at91-ssc1", - .id = 1, - .type = SND_SOC_DAI_PCM, - .suspend = at91_ssc_suspend, - .resume = at91_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .ops = { - .startup = at91_ssc_startup, - .shutdown = at91_ssc_shutdown, - .prepare = at91_ssc_prepare, - .hw_params = at91_ssc_hw_params,}, - .dai_ops = { - .set_sysclk = at91_ssc_set_dai_sysclk, - .set_fmt = at91_ssc_set_dai_fmt, - .set_clkdiv = at91_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[1].ssc, - }, - { .name = "at91-ssc2", - .id = 2, - .type = SND_SOC_DAI_PCM, - .suspend = at91_ssc_suspend, - .resume = at91_ssc_resume, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = AT91_SSC_RATES, - .formats = AT91_SSC_FORMATS,}, - .ops = { - .startup = at91_ssc_startup, - .shutdown = at91_ssc_shutdown, - .prepare = at91_ssc_prepare, - .hw_params = at91_ssc_hw_params,}, - .dai_ops = { - .set_sysclk = at91_ssc_set_dai_sysclk, - .set_fmt = at91_ssc_set_dai_fmt, - .set_clkdiv = at91_ssc_set_dai_clkdiv,}, - .private_data = &ssc_info[2].ssc, - }, -#endif -}; - -EXPORT_SYMBOL_GPL(at91_ssc_dai); - -/* Module information */ -MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com"); -MODULE_DESCRIPTION("AT91 SSC ASoC Interface"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/at91/at91-ssc.h b/sound/soc/at91/at91-ssc.h deleted file mode 100644 index 6b7bf382d06f..000000000000 --- a/sound/soc/at91/at91-ssc.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * at91-ssc.h - ALSA SSC interface for the Atmel AT91 SoC - * - * Author: Frank Mandarino - * Endrelia Technologies Inc. - * Created: Jan 9, 2007 - * - * 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 _AT91_SSC_H -#define _AT91_SSC_H - -/* SSC system clock ids */ -#define AT91_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ - -/* SSC divider ids */ -#define AT91SSC_CMR_DIV 0 /* MCK divider for BCLK */ -#define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ -#define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ - -extern struct snd_soc_dai at91_ssc_dai[]; - -#endif /* _AT91_SSC_H */ - diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig new file mode 100644 index 000000000000..a608d7009dbd --- /dev/null +++ b/sound/soc/atmel/Kconfig @@ -0,0 +1,43 @@ +config SND_ATMEL_SOC + tristate "SoC Audio for the Atmel System-on-Chip" + depends on ARCH_AT91 || AVR32 + help + Say Y or M if you want to add support for codecs attached to + the ATMEL SSC interface. You will also need + to select the audio interfaces to support below. + +config SND_ATMEL_SOC_SSC + tristate + depends on SND_ATMEL_SOC + help + Say Y or M if you want to add support for codecs the + ATMEL SSC interface. You will also needs to select the individual + machine drivers to support below. + +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 + select SND_ATMEL_SOC_SSC + select SND_SOC_WM8731 + help + Say Y if you want to add support for SoC audio on WM8731-based + AT91sam9g20 evaluation board. + +config SND_AT32_SOC_PLAYPAQ + tristate "SoC Audio support for PlayPaq with WM8510" + depends on SND_ATMEL_SOC && BOARD_PLAYPAQ + select SND_ATMEL_SOC_SSC + select SND_SOC_WM8510 + help + Say Y or M here if you want to add support for SoC audio + on the LRS PlayPaq. + +config SND_AT32_SOC_PLAYPAQ_SLAVE + bool "Run CODEC on PlayPaq in slave mode" + depends on SND_AT32_SOC_PLAYPAQ + default n + help + Say Y if you want to run with the AT32 SSC generating the BCLK + and FRAME signals on the PlayPaq. Unless you want to play + with the AT32 as the SSC master, you probably want to say N here, + as this will give you better sound quality. diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile new file mode 100644 index 000000000000..f54a7cc68e66 --- /dev/null +++ b/sound/soc/atmel/Makefile @@ -0,0 +1,15 @@ +# AT91 Platform Support +snd-soc-atmel-pcm-objs := atmel-pcm.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_SSC) += snd-soc-atmel_ssc_dai.o + +# AT91 Machine Support +snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o + +# AT32 Machine Support +snd-soc-playpaq-objs := playpaq_wm8510.o + +obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o +obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o diff --git a/sound/soc/at32/at32-pcm.c b/sound/soc/atmel/atmel-pcm.c similarity index 50% rename from sound/soc/at32/at32-pcm.c rename to sound/soc/atmel/atmel-pcm.c index c83584f989a9..394412fb396f 100644 --- a/sound/soc/at32/at32-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -1,15 +1,34 @@ -/* sound/soc/at32/at32-pcm.c - * ASoC PCM interface for Atmel AT32 SoC +/* + * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. * - * Copyright (C) 2008 Long Range Systems - * Geoffrey Wossum + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Authors: Sedji Gaouaou + * + * Based on at91-pcm. by: + * Frank Mandarino + * 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 version 2 as - * published by the Free Software Foundation. + * 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. * - * Note that this is basically a port of the sound/soc/at91-pcm.c to - * the AVR32 kernel. Thanks to Frank Mandarino for that code. + * 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 @@ -18,14 +37,16 @@ #include #include #include +#include #include #include #include #include -#include "at32-pcm.h" +#include +#include "atmel-pcm.h" /*--------------------------------------------------------------------------*\ @@ -34,36 +55,33 @@ /* TODO: These values were taken from the AT91 platform driver, check * them against real values for AT32 */ -static const struct snd_pcm_hardware at32_pcm_hardware = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_PAUSE), - - .formats = SNDRV_PCM_FMTBIT_S16, - .period_bytes_min = 32, - .period_bytes_max = 8192, /* 512 frames * 16 bytes / frame */ - .periods_min = 2, - .periods_max = 1024, - .buffer_bytes_max = 32 * 1024, +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 at32_runtime_data { - struct at32_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 */ +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 */ - int periods; /* period index of period_ptr */ + dma_addr_t period_ptr; /* physical address of next period */ + int periods; /* period index of period_ptr */ - /* Save PDC registers (for power management) */ + /* PDC register save */ u32 pdc_xpr_save; u32 pdc_xcr_save; u32 pdc_xnpr_save; @@ -71,49 +89,51 @@ struct at32_runtime_data { }; - /*--------------------------------------------------------------------------*\ * Helper functions \*--------------------------------------------------------------------------*/ -static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +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 *dmabuf = &substream->dma_buffer; - size_t size = at32_pcm_hardware.buffer_bytes_max; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = atmel_pcm_hardware.buffer_bytes_max; - dmabuf->dev.type = SNDRV_DMA_TYPE_DEV; - dmabuf->dev.dev = pcm->card->dev; - dmabuf->private_data = NULL; - dmabuf->area = dma_alloc_coherent(pcm->card->dev, size, - &dmabuf->addr, GFP_KERNEL); - pr_debug("at32_pcm: preallocate_dma_buffer: " - "area=%p, addr=%p, size=%ld\n", - (void *)dmabuf->area, (void *)dmabuf->addr, 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); - if (!dmabuf->area) + if (!buf->area) return -ENOMEM; - dmabuf->bytes = size; + buf->bytes = size; return 0; } - - - /*--------------------------------------------------------------------------*\ * ISR \*--------------------------------------------------------------------------*/ -static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) +static void atmel_pcm_dma_irq(u32 ssc_sr, + struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *rtd = substream->runtime; - struct at32_runtime_data *prtd = rtd->private_data; - struct at32_pcm_dma_params *params = prtd->params; + 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("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", - substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? - "underrun" : "overrun", params->name, ssc_sr, count); + 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, @@ -122,7 +142,6 @@ static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) 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, @@ -131,60 +150,58 @@ static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) 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 at32_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +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 at32_runtime_data *prtd = runtime->private_data; + 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 - */ + * with different params */ + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = params_buffer_bytes(params); prtd->params = rtd->dai->cpu_dai->dma_data; - prtd->params->dma_intr_handler = at32_pcm_dma_irq; + 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("hw_params: DMA for %s initialized " - "(dma_bytes=%ld, period_size=%ld)\n", - prtd->params->name, runtime->dma_bytes, prtd->period_size); - + 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 at32_pcm_hw_free(struct snd_pcm_substream *substream) +static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) { - struct at32_runtime_data *prtd = substream->runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; + 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, @@ -195,32 +212,29 @@ static int at32_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } - - -static int at32_pcm_prepare(struct snd_pcm_substream *substream) +static int atmel_pcm_prepare(struct snd_pcm_substream *substream) { - struct at32_runtime_data *prtd = substream->runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; + 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 at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +static int atmel_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) { struct snd_pcm_runtime *rtd = substream->runtime; - struct at32_runtime_data *prtd = rtd->private_data; - struct at32_pcm_dma_params *params = prtd->params; + struct atmel_runtime_data *prtd = rtd->private_data; + struct atmel_pcm_dma_params *params = prtd->params; int ret = 0; - pr_debug("at32_pcm_trigger: buffer_size = %ld, " - "dma_area = %p, dma_bytes = %ld\n", - rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); + 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: @@ -237,26 +251,25 @@ static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->period_size / params->pdc_xfer_size); - pr_debug("trigger: period_ptr=%lx, xpr=%x, " - "xcr=%d, xnpr=%x, xncr=%d\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)); + 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=%x, imr=%x\n", - ssc_readx(params->ssc->regs, SSC_SR), - ssc_readx(params->ssc->regs, SSC_IER)); + 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: @@ -264,7 +277,6 @@ static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) params->mask->pdc_disable); break; - case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, @@ -278,13 +290,12 @@ static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } - - -static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream) +static snd_pcm_uframes_t atmel_pcm_pointer( + struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct at32_runtime_data *prtd = runtime->private_data; - struct at32_pcm_dma_params *params = prtd->params; + 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; @@ -297,108 +308,95 @@ static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream) return x; } - - -static int at32_pcm_open(struct snd_pcm_substream *substream) +static int atmel_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct at32_runtime_data *prtd; + struct atmel_runtime_data *prtd; int ret = 0; - snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware); + 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); + SNDRV_PCM_HW_PARAM_PERIODS); if (ret < 0) goto out; - prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); + prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); if (prtd == NULL) { ret = -ENOMEM; goto out; } runtime->private_data = prtd; - -out: + out: return ret; } - - -static int at32_pcm_close(struct snd_pcm_substream *substream) +static int atmel_pcm_close(struct snd_pcm_substream *substream) { - struct at32_runtime_data *prtd = substream->runtime->private_data; + struct atmel_runtime_data *prtd = substream->runtime->private_data; kfree(prtd); return 0; } - -static int at32_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *vma) +static 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); + substream->dma_buffer.addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); } - - -static struct snd_pcm_ops at32_pcm_ops = { - .open = at32_pcm_open, - .close = at32_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = at32_pcm_hw_params, - .hw_free = at32_pcm_hw_free, - .prepare = at32_pcm_prepare, - .trigger = at32_pcm_trigger, - .pointer = at32_pcm_pointer, - .mmap = at32_pcm_mmap, +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 at32_pcm_dmamask = 0xffffffff; +static u64 atmel_pcm_dmamask = 0xffffffff; -static int at32_pcm_new(struct snd_card *card, - struct snd_soc_dai *dai, - struct snd_pcm *pcm) +static int atmel_pcm_new(struct snd_card *card, + struct snd_soc_dai *dai, struct snd_pcm *pcm) { int ret = 0; if (!card->dev->dma_mask) - card->dev->dma_mask = &at32_pcm_dmamask; + card->dev->dma_mask = &atmel_pcm_dmamask; if (!card->dev->coherent_dma_mask) card->dev->coherent_dma_mask = 0xffffffff; if (dai->playback.channels_min) { - ret = at32_pcm_preallocate_dma_buffer( - pcm, SNDRV_PCM_STREAM_PLAYBACK); + ret = atmel_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); if (ret) goto out; } if (dai->capture.channels_min) { - pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n"); - ret = at32_pcm_preallocate_dma_buffer( - pcm, SNDRV_PCM_STREAM_CAPTURE); + pr_debug("at32-pcm:" + "Allocating PCM capture DMA buffer\n"); + ret = atmel_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); if (ret) goto out; } - - -out: + out: return ret; } - - -static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) +static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; @@ -406,7 +404,7 @@ static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) for (stream = 0; stream < 2; stream++) { substream = pcm->streams[stream].substream; - if (substream == NULL) + if (!substream) continue; buf = &substream->dma_buffer; @@ -418,24 +416,23 @@ static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm) } } - - #ifdef CONFIG_PM -static int at32_pcm_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int atmel_pcm_suspend(struct platform_device *pdev, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = dai->runtime; - struct at32_runtime_data *prtd; - struct at32_pcm_dma_params *params; + struct atmel_runtime_data *prtd; + struct atmel_pcm_dma_params *params; - if (runtime == NULL) + if (!runtime) return 0; + prtd = runtime->private_data; params = prtd->params; - /* Disable the PDC and save the PDC registers */ - ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, - params->mask->pdc_disable); + /* 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); @@ -445,48 +442,43 @@ static int at32_pcm_suspend(struct platform_device *pdev, return 0; } - - -static int at32_pcm_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int atmel_pcm_resume(struct platform_device *pdev, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = dai->runtime; - struct at32_runtime_data *prtd; - struct at32_pcm_dma_params *params; + struct atmel_runtime_data *prtd; + struct atmel_pcm_dma_params *params; - if (runtime == NULL) + if (!runtime) return 0; + prtd = runtime->private_data; params = prtd->params; - /* Restore the PDC registers and enable the PDC */ + /* 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_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable); + ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); return 0; } -#else /* CONFIG_PM */ -# define at32_pcm_suspend NULL -# define at32_pcm_resume NULL -#endif /* CONFIG_PM */ +#else +#define atmel_pcm_suspend NULL +#define atmel_pcm_resume NULL +#endif - - -struct snd_soc_platform at32_soc_platform = { - .name = "at32-audio", - .pcm_ops = &at32_pcm_ops, - .pcm_new = at32_pcm_new, - .pcm_free = at32_pcm_free_dma_buffers, - .suspend = at32_pcm_suspend, - .resume = at32_pcm_resume, +struct snd_soc_platform atmel_soc_platform = { + .name = "atmel-audio", + .pcm_ops = &atmel_pcm_ops, + .pcm_new = atmel_pcm_new, + .pcm_free = atmel_pcm_free_dma_buffers, + .suspend = atmel_pcm_suspend, + .resume = atmel_pcm_resume, }; -EXPORT_SYMBOL_GPL(at32_soc_platform); +EXPORT_SYMBOL_GPL(atmel_soc_platform); - - -MODULE_AUTHOR("Geoffrey Wossum "); -MODULE_DESCRIPTION("Atmel AT32 PCM module"); +MODULE_AUTHOR("Sedji Gaouaou "); +MODULE_DESCRIPTION("Atmel PCM module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h new file mode 100644 index 000000000000..ec9b2824b663 --- /dev/null +++ b/sound/soc/atmel/atmel-pcm.h @@ -0,0 +1,86 @@ +/* + * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC. + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Authors: Sedji Gaouaou + * + * Based on at91-pcm. by: + * Frank Mandarino + * 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 + */ + +#ifndef _ATMEL_PCM_H +#define _ATMEL_PCM_H + +#include + +/* + * Registers and status bits that are required by the PCM driver. + */ +struct atmel_pdc_regs { + unsigned int xpr; /* PDC recv/trans pointer */ + unsigned int xcr; /* PDC recv/trans counter */ + unsigned int xnpr; /* PDC next recv/trans pointer */ + unsigned int xncr; /* PDC next recv/trans counter */ + unsigned int ptcr; /* PDC transfer control */ +}; + +struct atmel_ssc_mask { + u32 ssc_enable; /* SSC recv/trans enable */ + u32 ssc_disable; /* SSC recv/trans disable */ + u32 ssc_endx; /* SSC ENDTX or ENDRX */ + u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */ + u32 pdc_enable; /* PDC recv/trans enable */ + u32 pdc_disable; /* PDC recv/trans disable */ +}; + +/* + * This structure, shared between the PCM driver and the interface, + * contains all information required by the PCM driver to perform the + * PDC DMA operation. All fields except dma_intr_handler() are initialized + * by the interface. The dms_intr_handler() pointer is set by the PCM + * driver and called by the interface SSC interrupt handler if it is + * non-NULL. + */ +struct atmel_pcm_dma_params { + char *name; /* stream identifier */ + int pdc_xfer_size; /* PDC counter increment in bytes */ + struct ssc_device *ssc; /* SSC device for stream */ + struct atmel_pdc_regs *pdc; /* PDC receive or transmit registers */ + struct atmel_ssc_mask *mask; /* SSC & PDC status bits */ + struct snd_pcm_substream *substream; + void (*dma_intr_handler)(u32, struct snd_pcm_substream *); +}; + +extern struct snd_soc_platform atmel_soc_platform; + + +/* + * SSC register access (since ssc_writel() / ssc_readl() require literal name) + */ +#define ssc_readx(base, reg) (__raw_readl((base) + (reg))) +#define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) + +#endif /* _ATMEL_PCM_H */ diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c new file mode 100644 index 000000000000..d290b7894917 --- /dev/null +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -0,0 +1,782 @@ +/* + * atmel_ssc_dai.c -- ALSA SoC ATMEL SSC Audio Layer Platform driver + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Author: Sedji Gaouaou + * ATMEL CORP. + * + * Based on at91-ssc.c by + * Frank Mandarino + * Based on pxa2xx Platform drivers by + * Liam Girdwood + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "atmel-pcm.h" +#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. + */ +static struct atmel_pdc_regs pdc_tx_reg = { + .xpr = ATMEL_PDC_TPR, + .xcr = ATMEL_PDC_TCR, + .xnpr = ATMEL_PDC_TNPR, + .xncr = ATMEL_PDC_TNCR, +}; + +static struct atmel_pdc_regs pdc_rx_reg = { + .xpr = ATMEL_PDC_RPR, + .xcr = ATMEL_PDC_RCR, + .xnpr = ATMEL_PDC_RNPR, + .xncr = ATMEL_PDC_RNCR, +}; + +/* + * SSC & PDC status bits for transmit and receive. + */ +static struct atmel_ssc_mask ssc_tx_mask = { + .ssc_enable = SSC_BIT(CR_TXEN), + .ssc_disable = SSC_BIT(CR_TXDIS), + .ssc_endx = SSC_BIT(SR_ENDTX), + .ssc_endbuf = SSC_BIT(SR_TXBUFE), + .pdc_enable = ATMEL_PDC_TXTEN, + .pdc_disable = ATMEL_PDC_TXTDIS, +}; + +static struct atmel_ssc_mask ssc_rx_mask = { + .ssc_enable = SSC_BIT(CR_RXEN), + .ssc_disable = SSC_BIT(CR_RXDIS), + .ssc_endx = SSC_BIT(SR_ENDRX), + .ssc_endbuf = SSC_BIT(SR_RXBUFF), + .pdc_enable = ATMEL_PDC_RXTEN, + .pdc_disable = ATMEL_PDC_RXTDIS, +}; + + +/* + * DMA parameters. + */ +static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = { + {{ + .name = "SSC0 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC0 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + } }, +#if NUM_SSC_DEVICES == 3 + {{ + .name = "SSC1 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC1 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + } }, + {{ + .name = "SSC2 PCM out", + .pdc = &pdc_tx_reg, + .mask = &ssc_tx_mask, + }, + { + .name = "SSC2 PCM in", + .pdc = &pdc_rx_reg, + .mask = &ssc_rx_mask, + } }, +#endif +}; + + +static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = { + { + .name = "ssc0", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, +#if NUM_SSC_DEVICES == 3 + { + .name = "ssc1", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, + { + .name = "ssc2", + .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock), + .dir_mask = SSC_DIR_MASK_UNUSED, + .initialized = 0, + }, +#endif +}; + + +/* + * SSC interrupt handler. Passes PDC interrupts to the DMA + * interrupt handler in the PCM driver. + */ +static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) +{ + struct atmel_ssc_info *ssc_p = dev_id; + struct atmel_pcm_dma_params *dma_params; + u32 ssc_sr; + u32 ssc_substream_mask; + int i; + + ssc_sr = (unsigned long)ssc_readl(ssc_p->ssc->regs, SR) + & (unsigned long)ssc_readl(ssc_p->ssc->regs, IMR); + + /* + * Loop through the substreams attached to this SSC. If + * a DMA-related interrupt occurred on that substream, call + * the DMA interrupt handler function, if one has been + * registered in the dma_params structure by the PCM driver. + */ + for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) { + dma_params = ssc_p->dma_params[i]; + + if ((dma_params != NULL) && + (dma_params->dma_intr_handler != NULL)) { + ssc_substream_mask = (dma_params->mask->ssc_endx | + dma_params->mask->ssc_endbuf); + if (ssc_sr & ssc_substream_mask) { + dma_params->dma_intr_handler(ssc_sr, + dma_params-> + substream); + } + } + } + + return IRQ_HANDLED; +} + + +/*-------------------------------------------------------------------------*\ + * DAI functions +\*-------------------------------------------------------------------------*/ +/* + * Startup. Only that one substream allowed in each direction. + */ +static int atmel_ssc_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + int dir_mask; + + pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n", + ssc_readl(ssc_p->ssc->regs, SR)); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir_mask = SSC_DIR_MASK_PLAYBACK; + else + dir_mask = SSC_DIR_MASK_CAPTURE; + + spin_lock_irq(&ssc_p->lock); + if (ssc_p->dir_mask & dir_mask) { + spin_unlock_irq(&ssc_p->lock); + return -EBUSY; + } + ssc_p->dir_mask |= dir_mask; + spin_unlock_irq(&ssc_p->lock); + + return 0; +} + +/* + * Shutdown. Clear DMA parameters and shutdown the SSC if there + * are no other substreams open. + */ +static void atmel_ssc_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct atmel_pcm_dma_params *dma_params; + int dir, dir_mask; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir = 0; + else + dir = 1; + + dma_params = ssc_p->dma_params[dir]; + + if (dma_params != NULL) { + ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable); + pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n", + (dir ? "receive" : "transmit"), + ssc_readl(ssc_p->ssc->regs, SR)); + + dma_params->ssc = NULL; + dma_params->substream = NULL; + ssc_p->dma_params[dir] = NULL; + } + + dir_mask = 1 << dir; + + spin_lock_irq(&ssc_p->lock); + ssc_p->dir_mask &= ~dir_mask; + if (!ssc_p->dir_mask) { + if (ssc_p->initialized) { + /* Shutdown the SSC clock. */ + pr_debug("atmel_ssc_dau: Stopping clock\n"); + clk_disable(ssc_p->ssc->clk); + + free_irq(ssc_p->ssc->irq, ssc_p); + ssc_p->initialized = 0; + } + + /* Reset the SSC */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + /* Clear the SSC dividers */ + ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; + } + spin_unlock_irq(&ssc_p->lock); +} + + +/* + * Record the DAI format for use in hw_params(). + */ +static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + ssc_p->daifmt = fmt; + return 0; +} + +/* + * Record SSC clock dividers for use in hw_params(). + */ +static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id]; + + switch (div_id) { + case ATMEL_SSC_CMR_DIV: + /* + * The same master clock divider is used for both + * transmit and receive, so if a value has already + * been set, it must match this value. + */ + if (ssc_p->cmr_div == 0) + ssc_p->cmr_div = div; + else + if (div != ssc_p->cmr_div) + return -EBUSY; + break; + + case ATMEL_SSC_TCMR_PERIOD: + ssc_p->tcmr_period = div; + break; + + case ATMEL_SSC_RCMR_PERIOD: + ssc_p->rcmr_period = div; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Configure the SSC. + */ +static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + int id = rtd->dai->cpu_dai->id; + struct atmel_ssc_info *ssc_p = &ssc_info[id]; + struct atmel_pcm_dma_params *dma_params; + int dir, channels, bits; + u32 tfmr, rfmr, tcmr, rcmr; + int start_event; + int ret; + + /* + * Currently, there is only one set of dma params for + * each direction. If more are added, this code will + * have to be changed to select the proper set. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir = 0; + else + dir = 1; + + dma_params = &ssc_dma_params[id][dir]; + dma_params->ssc = ssc_p->ssc; + dma_params->substream = substream; + + ssc_p->dma_params[dir] = dma_params; + + /* + * The cpu_dai->dma_data field is only used to communicate the + * appropriate DMA parameters to the pcm driver hw_params() + * function. It should not be used for other purposes + * as it is common to all substreams. + */ + rtd->dai->cpu_dai->dma_data = dma_params; + + channels = params_channels(params); + + /* + * Determine sample size in bits and the PDC increment. + */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + bits = 8; + dma_params->pdc_xfer_size = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + bits = 16; + dma_params->pdc_xfer_size = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + bits = 24; + dma_params->pdc_xfer_size = 4; + break; + case SNDRV_PCM_FORMAT_S32_LE: + bits = 32; + dma_params->pdc_xfer_size = 4; + break; + default: + printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format"); + return -EINVAL; + } + + /* + * The SSC only supports up to 16-bit samples in I2S format, due + * to the size of the Frame Mode Register FSLEN field. + */ + if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S + && bits > 16) { + printk(KERN_WARNING + "atmel_ssc_dai: sample size %d" + "is too large for I2S\n", bits); + return -EINVAL; + } + + /* + * Compute SSC register settings. + */ + switch (ssc_p->daifmt + & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) { + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS: + /* + * I2S format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated + * from the MCK divider, and the BCLK signal + * is output on the SSC TK line. + */ + rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + | SSC_BF(RCMR_STTDLY, START_DELAY) + | SSC_BF(RCMR_START, SSC_START_FALLING_RF) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_DIV); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE) + | SSC_BF(RFMR_FSLEN, (bits - 1)) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + | SSC_BF(TCMR_STTDLY, START_DELAY) + | SSC_BF(TCMR_START, SSC_START_FALLING_RF) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) + | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) + | SSC_BF(TCMR_CKS, SSC_CKS_DIV); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE) + | SSC_BF(TFMR_FSLEN, (bits - 1)) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + + case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM: + /* + * I2S format, CODEC supplies BCLK and LRC clocks. + * + * The SSC transmit clock is obtained from the BCLK signal on + * on the TK line, and the SSC receive clock is + * generated from the transmit clock. + * + * For single channel data, one sample is transferred + * on the falling edge of the LRC clock. + * For two channel data, one sample is + * transferred on both edges of the LRC clock. + */ + start_event = ((channels == 1) + ? SSC_START_FALLING_RF + : SSC_START_EDGE_RF); + + rcmr = SSC_BF(RCMR_PERIOD, 0) + | SSC_BF(RCMR_STTDLY, START_DELAY) + | SSC_BF(RCMR_START, start_event) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(RFMR_FSLEN, 0) + | SSC_BF(RFMR_DATNB, 0) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, 0) + | SSC_BF(TCMR_STTDLY, START_DELAY) + | SSC_BF(TCMR_START, start_event) + | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) + | SSC_BF(TCMR_CKO, SSC_CKO_NONE) + | SSC_BF(TCMR_CKS, SSC_CKS_PIN); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE) + | SSC_BF(TFMR_FSLEN, 0) + | SSC_BF(TFMR_DATNB, 0) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS: + /* + * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks. + * + * The SSC transmit and receive clocks are generated from the + * MCK divider, and the BCLK signal is output + * on the SSC TK line. + */ + rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + | SSC_BF(RCMR_STTDLY, 1) + | SSC_BF(RCMR_START, SSC_START_RISING_RF) + | SSC_BF(RCMR_CKI, SSC_CKI_RISING) + | SSC_BF(RCMR_CKO, SSC_CKO_NONE) + | SSC_BF(RCMR_CKS, SSC_CKS_DIV); + + rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE) + | SSC_BF(RFMR_FSLEN, 0) + | SSC_BF(RFMR_DATNB, (channels - 1)) + | SSC_BIT(RFMR_MSBF) + | SSC_BF(RFMR_LOOP, 0) + | SSC_BF(RFMR_DATLEN, (bits - 1)); + + tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + | SSC_BF(TCMR_STTDLY, 1) + | SSC_BF(TCMR_START, SSC_START_RISING_RF) + | SSC_BF(TCMR_CKI, SSC_CKI_RISING) + | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS) + | SSC_BF(TCMR_CKS, SSC_CKS_DIV); + + tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) + | SSC_BF(TFMR_FSDEN, 0) + | SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE) + | SSC_BF(TFMR_FSLEN, 0) + | SSC_BF(TFMR_DATNB, (channels - 1)) + | SSC_BIT(TFMR_MSBF) + | SSC_BF(TFMR_DATDEF, 0) + | SSC_BF(TFMR_DATLEN, (bits - 1)); + break; + + case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM: + default: + printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", + ssc_p->daifmt); + return -EINVAL; + break; + } + pr_debug("atmel_ssc_hw_params: " + "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", + rcmr, rfmr, tcmr, tfmr); + + if (!ssc_p->initialized) { + + /* Enable PMC peripheral clock for this SSC */ + pr_debug("atmel_ssc_dai: Starting clock\n"); + clk_enable(ssc_p->ssc->clk); + + /* Reset the SSC and its PDC registers */ + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); + + ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0); + + ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0); + ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0); + + ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0, + ssc_p->name, ssc_p); + if (ret < 0) { + printk(KERN_WARNING + "atmel_ssc_dai: request_irq failure\n"); + pr_debug("Atmel_ssc_dai: Stoping clock\n"); + clk_disable(ssc_p->ssc->clk); + return ret; + } + + ssc_p->initialized = 1; + } + + /* set SSC clock mode register */ + ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); + + /* set receive clock mode and format */ + ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); + ssc_writel(ssc_p->ssc->regs, RFMR, rfmr); + + /* set transmit clock mode and format */ + ssc_writel(ssc_p->ssc->regs, TCMR, tcmr); + ssc_writel(ssc_p->ssc->regs, TFMR, tfmr); + + pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n"); + return 0; +} + + +static int atmel_ssc_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; + struct atmel_pcm_dma_params *dma_params; + int dir; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir = 0; + else + dir = 1; + + dma_params = ssc_p->dma_params[dir]; + + ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable); + + pr_debug("%s enabled SSC_SR=0x%08x\n", + dir ? "receive" : "transmit", + ssc_readl(ssc_p->ssc->regs, SR)); + return 0; +} + + +#ifdef CONFIG_PM +static int atmel_ssc_suspend(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct atmel_ssc_info *ssc_p; + + if (!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* Save the status register before disabling transmit and receive */ + ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR); + ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS)); + + /* Save the current interrupt mask, then disable unmasked interrupts */ + ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR); + ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr); + + ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR); + ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR); + ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR); + ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR); + ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR); + + return 0; +} + + + +static int atmel_ssc_resume(struct platform_device *pdev, + struct snd_soc_dai *cpu_dai) +{ + struct atmel_ssc_info *ssc_p; + u32 cr; + + if (!cpu_dai->active) + return 0; + + ssc_p = &ssc_info[cpu_dai->id]; + + /* restore SSC register settings */ + ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr); + ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr); + ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr); + ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr); + ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr); + + /* re-enable interrupts */ + ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr); + + /* Re-enable recieve and transmit as appropriate */ + cr = 0; + cr |= + (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0; + cr |= + (ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0; + ssc_writel(ssc_p->ssc->regs, CR, cr); + + return 0; +} +#else /* CONFIG_PM */ +# define atmel_ssc_suspend NULL +# define atmel_ssc_resume NULL +#endif /* CONFIG_PM */ + + +#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000) + +#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { + { .name = "atmel-ssc0", + .id = 0, + .type = SND_SOC_DAI_PCM, + .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 = { + .startup = atmel_ssc_startup, + .shutdown = atmel_ssc_shutdown, + .prepare = atmel_ssc_prepare, + .hw_params = atmel_ssc_hw_params,}, + .dai_ops = { + .set_fmt = atmel_ssc_set_dai_fmt, + .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[0], + }, +#if NUM_SSC_DEVICES == 3 + { .name = "atmel-ssc1", + .id = 1, + .type = SND_SOC_DAI_PCM, + .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 = { + .startup = atmel_ssc_startup, + .shutdown = atmel_ssc_shutdown, + .prepare = atmel_ssc_prepare, + .hw_params = atmel_ssc_hw_params,}, + .dai_ops = { + .set_fmt = atmel_ssc_set_dai_fmt, + .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[1], + }, + { .name = "atmel-ssc2", + .id = 2, + .type = SND_SOC_DAI_PCM, + .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 = { + .startup = atmel_ssc_startup, + .shutdown = atmel_ssc_shutdown, + .prepare = atmel_ssc_prepare, + .hw_params = atmel_ssc_hw_params,}, + .dai_ops = { + .set_fmt = atmel_ssc_set_dai_fmt, + .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, + .private_data = &ssc_info[2], + }, +#endif +}; +EXPORT_SYMBOL_GPL(atmel_ssc_dai); + +/* Module information */ +MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); +MODULE_DESCRIPTION("ATMEL SSC ASoC Interface"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h new file mode 100644 index 000000000000..a828746e8a2f --- /dev/null +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -0,0 +1,121 @@ +/* + * atmel_ssc_dai.h - ALSA SSC interface for the Atmel SoC + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Author: Sedji Gaouaou + * ATMEL CORP. + * + * Based on at91-ssc.c by + * Frank Mandarino + * Based on pxa2xx Platform drivers by + * Liam Girdwood + * + * 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 + */ + +#ifndef _ATMEL_SSC_DAI_H +#define _ATMEL_SSC_DAI_H + +#include +#include + +#include "atmel-pcm.h" + +/* SSC system clock ids */ +#define ATMEL_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */ + +/* SSC divider ids */ +#define ATMEL_SSC_CMR_DIV 0 /* MCK divider for BCLK */ +#define ATMEL_SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */ +#define ATMEL_SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */ +/* + * SSC direction masks + */ +#define SSC_DIR_MASK_UNUSED 0 +#define SSC_DIR_MASK_PLAYBACK 1 +#define SSC_DIR_MASK_CAPTURE 2 + +/* + * SSC register values that Atmel left out of . These + * are expected to be used with SSC_BF + */ +/* START bit field values */ +#define SSC_START_CONTINUOUS 0 +#define SSC_START_TX_RX 1 +#define SSC_START_LOW_RF 2 +#define SSC_START_HIGH_RF 3 +#define SSC_START_FALLING_RF 4 +#define SSC_START_RISING_RF 5 +#define SSC_START_LEVEL_RF 6 +#define SSC_START_EDGE_RF 7 +#define SSS_START_COMPARE_0 8 + +/* CKI bit field values */ +#define SSC_CKI_FALLING 0 +#define SSC_CKI_RISING 1 + +/* CKO bit field values */ +#define SSC_CKO_NONE 0 +#define SSC_CKO_CONTINUOUS 1 +#define SSC_CKO_TRANSFER 2 + +/* CKS bit field values */ +#define SSC_CKS_DIV 0 +#define SSC_CKS_CLOCK 1 +#define SSC_CKS_PIN 2 + +/* FSEDGE bit field values */ +#define SSC_FSEDGE_POSITIVE 0 +#define SSC_FSEDGE_NEGATIVE 1 + +/* FSOS bit field values */ +#define SSC_FSOS_NONE 0 +#define SSC_FSOS_NEGATIVE 1 +#define SSC_FSOS_POSITIVE 2 +#define SSC_FSOS_LOW 3 +#define SSC_FSOS_HIGH 4 +#define SSC_FSOS_TOGGLE 5 + +#define START_DELAY 1 + +struct atmel_ssc_state { + u32 ssc_cmr; + u32 ssc_rcmr; + u32 ssc_rfmr; + u32 ssc_tcmr; + u32 ssc_tfmr; + u32 ssc_sr; + u32 ssc_imr; +}; + + +struct atmel_ssc_info { + char *name; + struct ssc_device *ssc; + spinlock_t lock; /* lock for dir_mask */ + unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */ + unsigned short initialized; /* true if SSC has been initialized */ + unsigned short daifmt; + unsigned short cmr_div; + unsigned short tcmr_period; + unsigned short rcmr_period; + struct atmel_pcm_dma_params *dma_params[2]; + struct atmel_ssc_state ssc_state; +}; +extern struct snd_soc_dai atmel_ssc_dai[]; + +#endif /* _AT91_SSC_DAI_H */ diff --git a/sound/soc/at32/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c similarity index 99% rename from sound/soc/at32/playpaq_wm8510.c rename to sound/soc/atmel/playpaq_wm8510.c index b1966e4dfcd3..5b07cf7ea4e7 100644 --- a/sound/soc/at32/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -40,8 +40,8 @@ #include #include "../codecs/wm8510.h" -#include "at32-pcm.h" -#include "at32-ssc.h" +#include "atmel-pcm.h" +#include "atmel_ssc_dai.h" /*-------------------------------------------------------------------------*\ From 5b99e6ccf964e733f0afe2b7bd09559a51a540ca Mon Sep 17 00:00:00 2001 From: Sedji Gaouaou Date: Fri, 3 Oct 2008 16:58:58 +0200 Subject: [PATCH 046/367] ASoC: Add audio support for the Atmel AT91SAM9G20ek board(uing wolfson 8731). Add audio support for the Atmel AT91SAM9G20ek board(uing wolfson 8731). It is based on the former eti_b1_wm8731.c file, using the atmel scc API. Signed-off-by: Sedji Gaouaou Signed-off-by: Mark Brown --- sound/soc/atmel/sam9g20_wm8731.c | 329 +++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 sound/soc/atmel/sam9g20_wm8731.c diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c new file mode 100644 index 000000000000..4e191df4e2b7 --- /dev/null +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -0,0 +1,329 @@ +/* + * sam9g20_wm8731 -- SoC audio for AT91SAM9G20-based + * ATMEL AT91SAM9G20ek board. + * + * Copyright (C) 2005 SAN People + * Copyright (C) 2008 Atmel + * + * Authors: Sedji Gaouaou + * + * Based on ati_b1_wm8731.c by: + * Frank Mandarino + * Copyright 2006 Endrelia Technologies Inc. + * Based on corgi.c by: + * Copyright 2005 Wolfson Microelectronics PLC. + * Copyright 2005 Openedhand Ltd. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "../codecs/wm8731.h" +#include "atmel-pcm.h" +#include "atmel_ssc_dai.h" + + +static int at91sam9g20ek_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + int ret; + + /* codec system clock is supplied by PCK0, set to 12MHz */ + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, + 12000000, SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + return 0; +} + +static void at91sam9g20ek_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + + dev_dbg(rtd->socdev->dev, "shutdown"); +} + +static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + struct atmel_ssc_info *ssc_p = cpu_dai->private_data; + struct ssc_device *ssc = ssc_p->ssc; + int ret; + + unsigned int rate; + int cmr_div, period; + + if (ssc == NULL) { + printk(KERN_INFO "at91sam9g20ek_hw_params: ssc is NULL!\n"); + return -EINVAL; + } + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + /* + * The SSC clock dividers depend on the sample rate. The CMR.DIV + * field divides the system master clock MCK to drive the SSC TK + * signal which provides the codec BCLK. The TCMR.PERIOD and + * RCMR.PERIOD fields further divide the BCLK signal to drive + * the SSC TF and RF signals which provide the codec DACLRC and + * ADCLRC clocks. + * + * The dividers were determined through trial and error, where a + * CMR.DIV value is chosen such that the resulting BCLK value is + * divisible, or almost divisible, by (2 * sample rate), and then + * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1. + */ + rate = params_rate(params); + + switch (rate) { + case 8000: + cmr_div = 55; /* BCLK = 133MHz/(2*55) = 1.209MHz */ + period = 74; /* LRC = BCLK/(2*(74+1)) ~= 8060,6Hz */ + break; + case 11025: + cmr_div = 67; /* BCLK = 133MHz/(2*60) = 1.108MHz */ + period = 45; /* LRC = BCLK/(2*(49+1)) = 11083,3Hz */ + break; + case 16000: + cmr_div = 63; /* BCLK = 133MHz/(2*63) = 1.055MHz */ + period = 32; /* LRC = BCLK/(2*(32+1)) = 15993,2Hz */ + break; + case 22050: + cmr_div = 52; /* BCLK = 133MHz/(2*52) = 1.278MHz */ + period = 28; /* LRC = BCLK/(2*(28+1)) = 22049Hz */ + break; + case 32000: + cmr_div = 66; /* BCLK = 133MHz/(2*66) = 1.007MHz */ + period = 15; /* LRC = BCLK/(2*(15+1)) = 31486,742Hz */ + break; + case 44100: + cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ + period = 25; /* LRC = BCLK/(2*(25+1)) = 44098Hz */ + break; + case 48000: + cmr_div = 33; /* BCLK = 133MHz/(2*33) = 2.015MHz */ + period = 20; /* LRC = BCLK/(2*(20+1)) = 47979,79Hz */ + break; + case 88200: + cmr_div = 29; /* BCLK = 133MHz/(2*29) = 2.293MHz */ + period = 12; /* LRC = BCLK/(2*(12+1)) = 88196Hz */ + break; + case 96000: + cmr_div = 23; /* BCLK = 133MHz/(2*23) = 2.891MHz */ + period = 14; /* LRC = BCLK/(2*(14+1)) = 96376Hz */ + break; + default: + printk(KERN_WARNING "unsupported rate %d" + " on at91sam9g20ek board\n", rate); + return -EINVAL; + } + + /* set the MCK divider for BCLK */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cmr_div); + if (ret < 0) + return ret; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* set the BCLK divider for DACLRC */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, + ATMEL_SSC_TCMR_PERIOD, period); + } else { + /* set the BCLK divider for ADCLRC */ + ret = snd_soc_dai_set_clkdiv(cpu_dai, + ATMEL_SSC_RCMR_PERIOD, period); + } + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops at91sam9g20ek_ops = { + .startup = at91sam9g20ek_startup, + .hw_params = at91sam9g20ek_hw_params, + .shutdown = at91sam9g20ek_shutdown, +}; + + +static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static const struct snd_soc_dapm_route intercon[] = { + + /* speaker connected to LHPOUT */ + {"Ext Spk", NULL, "LHPOUT"}, + + /* mic is connected to Mic Jack, with WM8731 Mic Bias */ + {"MICIN", NULL, "Mic Bias"}, + {"Mic Bias", NULL, "Int Mic"}, +}; + +/* + * Logic for a wm8731 as connected on a at91sam9g20ek board. + */ +static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec) +{ + printk(KERN_DEBUG + "at91sam9g20ek_wm8731 " + ": at91sam9g20ek_wm8731_init() called\n"); + + /* Add specific widgets */ + snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets, + ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); + /* Set up specific audio path interconnects */ + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + /* not connected */ + snd_soc_dapm_disable_pin(codec, "RLINEIN"); + snd_soc_dapm_disable_pin(codec, "LLINEIN"); + + /* always connected */ + snd_soc_dapm_enable_pin(codec, "Int Mic"); + snd_soc_dapm_enable_pin(codec, "Ext Spk"); + + snd_soc_dapm_sync(codec); + + return 0; +} + +static struct snd_soc_dai_link at91sam9g20ek_dai = { + .name = "WM8731", + .stream_name = "WM8731 PCM", + .cpu_dai = &atmel_ssc_dai[0], + .codec_dai = &wm8731_dai, + .init = at91sam9g20ek_wm8731_init, + .ops = &at91sam9g20ek_ops, +}; + +static struct snd_soc_machine snd_soc_machine_at91sam9g20ek = { + .name = "WM8731", + .dai_link = &at91sam9g20ek_dai, + .num_links = 1, +}; + +static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { + .i2c_bus = 0, + .i2c_address = 0x1b, +}; + +static struct snd_soc_device at91sam9g20ek_snd_devdata = { + .machine = &snd_soc_machine_at91sam9g20ek, + .platform = &atmel_soc_platform, + .codec_dev = &soc_codec_dev_wm8731, + .codec_data = &at91sam9g20ek_wm8731_setup, +}; + +static struct platform_device *at91sam9g20ek_snd_device; + +static int __init at91sam9g20ek_init(void) +{ + struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; + struct ssc_device *ssc = NULL; + int ret; + + /* + * Request SSC device + */ + ssc = ssc_request(0); + if (IS_ERR(ssc)) { + ret = PTR_ERR(ssc); + ssc = NULL; + goto err_ssc; + } + ssc_p->ssc = ssc; + + at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); + if (!at91sam9g20ek_snd_device) { + printk(KERN_DEBUG + "platform device allocation failed\n"); + ret = -ENOMEM; + } + + platform_set_drvdata(at91sam9g20ek_snd_device, + &at91sam9g20ek_snd_devdata); + at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev; + + ret = platform_device_add(at91sam9g20ek_snd_device); + if (ret) { + printk(KERN_DEBUG + "platform device allocation failed\n"); + platform_device_put(at91sam9g20ek_snd_device); + } + + return ret; + +err_ssc: + return ret; +} + +static void __exit at91sam9g20ek_exit(void) +{ + struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data; + struct ssc_device *ssc; + + if (ssc_p != NULL) { + ssc = ssc_p->ssc; + if (ssc != NULL) + ssc_free(ssc); + ssc_p->ssc = NULL; + } + + platform_device_unregister(at91sam9g20ek_snd_device); + at91sam9g20ek_snd_device = NULL; +} + +module_init(at91sam9g20ek_init); +module_exit(at91sam9g20ek_exit); + +/* Module information */ +MODULE_AUTHOR("Sedji Gaouaou "); +MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); +MODULE_LICENSE("GPL"); From d88897eaea53f0fae62d528a24e76b8643082db3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2008 15:01:37 +0100 Subject: [PATCH 047/367] ALSA: hda - Use macros to check array overflow Use macro to add mixer and verb elements to check the possible array overflow. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 113 ++++++++++++++++------------------ 1 file changed, 53 insertions(+), 60 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d300fc49f7e1..51479fba960e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -715,6 +715,22 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, .private_value = nid | (mask<<16) } #endif /* CONFIG_SND_DEBUG */ +/* + */ +static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix) +{ + if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers))) + return; + spec->mixers[spec->num_mixers++] = mix; +} + +static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) +{ + if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs))) + return; + spec->init_verbs[spec->num_init_verbs++] = verb; +} + /* * set up from the preset table */ @@ -724,11 +740,10 @@ static void setup_preset(struct alc_spec *spec, int i; for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) - spec->mixers[spec->num_mixers++] = preset->mixers[i]; + add_mixer(spec, preset->mixers[i]); for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++) - spec->init_verbs[spec->num_init_verbs++] = - preset->init_verbs[i]; + add_verb(spec, preset->init_verbs[i]); spec->channel_mode = preset->channel_mode; spec->num_channel_mode = preset->num_channel_mode; @@ -1244,7 +1259,6 @@ static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { .get = alc_mux_enum_get, .put = alc_mux_enum_put, }, - { } /* end */ }; @@ -3893,9 +3907,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->dig_in_nid = ALC880_DIGIN_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] = alc880_volume_init_verbs; + add_verb(spec, alc880_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -3974,14 +3988,11 @@ static int patch_alc880(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN) { spec->adc_nids = alc880_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); - spec->mixers[spec->num_mixers] = - alc880_capture_alt_mixer; - spec->num_mixers++; + add_mixer(spec, alc880_capture_alt_mixer); } else { spec->adc_nids = alc880_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); - spec->mixers[spec->num_mixers] = alc880_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc880_capture_mixer); } } @@ -5298,9 +5309,9 @@ static int alc260_parse_auto_config(struct hda_codec *codec) if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = ALC260_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] = alc260_volume_init_verbs; + add_verb(spec, alc260_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -5311,13 +5322,12 @@ static int alc260_parse_auto_config(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { spec->adc_nids = alc260_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); - spec->mixers[spec->num_mixers] = alc260_capture_alt_mixer; + add_mixer(spec, alc260_capture_alt_mixer); } else { spec->adc_nids = alc260_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); - spec->mixers[spec->num_mixers] = alc260_capture_mixer; + add_mixer(spec, alc260_capture_mixer); } - spec->num_mixers++; store_pin_configs(codec); return 1; @@ -6834,15 +6844,12 @@ static int patch_alc882(struct hda_codec *codec) spec->adc_nids = alc882_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); spec->capsrc_nids = alc882_capsrc_nids_alt; - spec->mixers[spec->num_mixers] = - alc882_capture_alt_mixer; - spec->num_mixers++; + add_mixer(spec, alc882_capture_alt_mixer); } else { spec->adc_nids = alc882_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); spec->capsrc_nids = alc882_capsrc_nids; - spec->mixers[spec->num_mixers] = alc882_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc882_capture_mixer); } } @@ -8854,8 +8861,7 @@ static int alc883_parse_auto_config(struct hda_codec *codec) /* hack - override the init verbs */ spec->init_verbs[0] = alc883_auto_init_verbs; - spec->mixers[spec->num_mixers] = alc883_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc883_capture_mixer); return 1; /* config found */ } @@ -10373,9 +10379,9 @@ static int alc262_parse_auto_config(struct hda_codec *codec) spec->dig_in_nid = ALC262_DIGIN_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] = alc262_volume_init_verbs; + add_verb(spec, alc262_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -10752,15 +10758,12 @@ static int patch_alc262(struct hda_codec *codec) spec->adc_nids = alc262_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); spec->capsrc_nids = alc262_capsrc_nids_alt; - spec->mixers[spec->num_mixers] = - alc262_capture_alt_mixer; - spec->num_mixers++; + add_mixer(spec, alc262_capture_alt_mixer); } else { spec->adc_nids = alc262_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); spec->capsrc_nids = alc262_capsrc_nids; - spec->mixers[spec->num_mixers] = alc262_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc262_capture_mixer); } } @@ -11505,12 +11508,12 @@ static int alc268_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC268_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); if (spec->autocfg.speaker_pins[0] != 0x1d) - spec->mixers[spec->num_mixers++] = alc268_beep_mixer; + add_mixer(spec, alc268_beep_mixer); - spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs; + add_verb(spec, alc268_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -11779,15 +11782,11 @@ static int patch_alc268(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { spec->adc_nids = alc268_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); - spec->mixers[spec->num_mixers] = - alc268_capture_alt_mixer; - spec->num_mixers++; + add_mixer(spec, alc268_capture_alt_mixer); } else { spec->adc_nids = alc268_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); - spec->mixers[spec->num_mixers] = - alc268_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc268_capture_mixer); } spec->capsrc_nids = alc268_capsrc_nids; /* set default input source */ @@ -12296,16 +12295,16 @@ static int alc269_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); /* create a beep mixer control if the pin 0x1d isn't assigned */ for (i = 0; i < ARRAY_SIZE(spec->autocfg.input_pins); i++) if (spec->autocfg.input_pins[i] == 0x1d) break; if (i >= ARRAY_SIZE(spec->autocfg.input_pins)) - spec->mixers[spec->num_mixers++] = alc269_beep_mixer; + add_mixer(spec, alc269_beep_mixer); - spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs; + add_verb(spec, alc269_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; /* set default input source */ @@ -12317,8 +12316,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - spec->mixers[spec->num_mixers] = alc269_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc269_capture_mixer); store_pin_configs(codec); return 1; @@ -13395,17 +13393,16 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC861_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] = alc861_auto_init_verbs; + add_verb(spec, alc861_auto_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; spec->adc_nids = alc861_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); - spec->mixers[spec->num_mixers] = alc861_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc861_capture_mixer); store_pin_configs(codec); return 1; @@ -14507,10 +14504,9 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC861VD_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); - spec->init_verbs[spec->num_init_verbs++] - = alc861vd_volume_init_verbs; + add_verb(spec, alc861vd_volume_init_verbs); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; @@ -14577,7 +14573,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->stream_name_analog = "ALC660-VD Analog"; spec->stream_name_digital = "ALC660-VD Digital"; /* always turn on EAPD */ - spec->init_verbs[spec->num_init_verbs++] = alc660vd_eapd_verbs; + add_verb(spec, alc660vd_eapd_verbs); } else { spec->stream_name_analog = "ALC861VD Analog"; spec->stream_name_digital = "ALC861VD Digital"; @@ -14593,8 +14589,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); spec->capsrc_nids = alc861vd_capsrc_nids; - spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc861vd_capture_mixer); spec->vmaster_nid = 0x02; @@ -16335,22 +16330,20 @@ static int alc662_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = ALC880_DIGOUT_NID; if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; + add_mixer(spec, spec->kctls.list); spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; - spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs; + add_verb(spec, alc662_auto_init_verbs); if (codec->vendor_id == 0x10ec0663) - spec->init_verbs[spec->num_init_verbs++] = - alc663_auto_init_verbs; + add_verb(spec, alc663_auto_init_verbs); err = alc_auto_add_mic_boost(codec); if (err < 0) return err; - spec->mixers[spec->num_mixers] = alc662_capture_mixer; - spec->num_mixers++; + add_mixer(spec, alc662_capture_mixer); store_pin_configs(codec); return 1; From 54cbc9abe57cf0a36619f394802448c62402599a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2008 15:24:04 +0100 Subject: [PATCH 048/367] ALSA: hda - Unify capture callbacks in realtek codes Unify the capture callbacks in patch_realtek.c. The difference of matrix or mux style is checked via spec->is_mix_capture flag. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 276 ++++++++++++---------------------- 1 file changed, 100 insertions(+), 176 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 51479fba960e..8477d6d46880 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -268,6 +268,7 @@ struct alc_spec { hda_nid_t *adc_nids; hda_nid_t *capsrc_nids; hda_nid_t dig_in_nid; /* digital-in NID; optional */ + unsigned char is_mix_capture; /* matrix-style capture (non-mux) */ /* capture source */ unsigned int num_mux_defs; @@ -374,14 +375,38 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; + const struct hda_input_mux *imux = spec->input_mux; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned int mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; hda_nid_t nid = spec->capsrc_nids ? spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; - return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], ucontrol, - nid, &spec->cur_mux[adc_idx]); -} + if (spec->is_mix_capture) { + /* Matrix-mixer style (e.g. ALC882) */ + unsigned int *cur_val = &spec->cur_mux[adc_idx]; + unsigned int i, idx; + + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (*cur_val == idx) + return 0; + for (i = 0; i < imux->num_items; i++) { + unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; + snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, + imux->items[i].index, + HDA_AMP_MUTE, v); + } + *cur_val = idx; + return 1; + } else { + /* MUX style (e.g. ALC880) */ + unsigned int mux_idx; + mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; + return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], + ucontrol, nid, + &spec->cur_mux[adc_idx]); + } +} /* * channel mode setting @@ -5629,36 +5654,6 @@ static struct hda_input_mux alc882_capture_source = { { "CD", 0x4 }, }, }; -#define alc882_mux_enum_info alc_mux_enum_info -#define alc882_mux_enum_get alc_mux_enum_get - -static int alc882_mux_enum_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; - const struct hda_input_mux *imux = spec->input_mux; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - hda_nid_t nid = spec->capsrc_nids ? - spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; - unsigned int *cur_val = &spec->cur_mux[adc_idx]; - unsigned int i, idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (*cur_val == idx) - return 0; - for (i = 0; i < imux->num_items; i++) { - unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, - imux->items[i].index, - HDA_AMP_MUTE, v); - } - *cur_val = idx; - return 1; -} - /* * 2ch mode */ @@ -6341,48 +6336,8 @@ static struct hda_verb alc882_auto_init_verbs[] = { { } }; -/* capture mixer elements */ -static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc882_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; +#define alc882_capture_alt_mixer alc880_capture_alt_mixer +#define alc882_capture_mixer alc880_capture_mixer #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc882_loopbacks alc880_loopbacks @@ -6835,6 +6790,7 @@ static int patch_alc882(struct hda_codec *codec) spec->stream_digital_playback = &alc882_pcm_digital_playback; spec->stream_digital_capture = &alc882_pcm_digital_capture; + spec->is_mix_capture = 1; /* matrix-style capture */ if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -6958,11 +6914,6 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = { }, }; -#define alc883_mux_enum_info alc_mux_enum_info -#define alc883_mux_enum_get alc_mux_enum_get -/* ALC883 has the ALC882-type input selection */ -#define alc883_mux_enum_put alc882_mux_enum_put - /* * 2ch mode */ @@ -7125,9 +7076,9 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7155,9 +7106,9 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7182,9 +7133,9 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7209,9 +7160,9 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7241,9 +7192,9 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7277,9 +7228,9 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7316,9 +7267,9 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7353,9 +7304,9 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7386,9 +7337,9 @@ static struct snd_kcontrol_new alc883_tagra_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7414,9 +7365,9 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7437,9 +7388,9 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7463,9 +7414,9 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7489,9 +7440,9 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7514,9 +7465,9 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7554,9 +7505,9 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -7595,9 +7546,9 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc883_mux_enum_info, - .get = alc883_mux_enum_get, - .put = alc883_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -8253,25 +8204,7 @@ static struct hda_verb alc883_auto_init_verbs[] = { }; /* capture mixer elements */ -static struct snd_kcontrol_new alc883_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, - .put = alc882_mux_enum_put, - }, - { } /* end */ -}; +#define alc883_capture_mixer alc880_capture_alt_mixer /* 2 ADC ver */ static struct hda_verb alc888_asus_m90v_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8947,6 +8880,7 @@ static int patch_alc883(struct hda_codec *codec) spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); spec->adc_nids = alc883_adc_nids; spec->capsrc_nids = alc883_capsrc_nids; + spec->is_mix_capture = 1; /* matrix-style capture */ spec->vmaster_nid = 0x0c; @@ -9967,7 +9901,7 @@ static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol, struct alc_spec *spec = codec->spec; int ret; - ret = alc882_mux_enum_put(kcontrol, ucontrol); + ret = alc_mux_enum_put(kcontrol, ucontrol); if (!ret) return 0; /* reprogram the HP pin as mic or HP according to the input source */ @@ -9984,8 +9918,8 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", - .info = alc882_mux_enum_info, - .get = alc882_mux_enum_get, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, .put = alc262_ultra_mux_enum_put, }, { } /* end */ @@ -10748,6 +10682,7 @@ static int patch_alc262(struct hda_codec *codec) spec->stream_digital_playback = &alc262_pcm_digital_playback; spec->stream_digital_capture = &alc262_pcm_digital_capture; + spec->is_mix_capture = 1; if (!spec->adc_nids && spec->input_mux) { /* check whether NID 0x07 is valid */ unsigned int wcap = get_wcaps(codec, 0x07); @@ -11213,10 +11148,6 @@ static struct hda_verb alc268_volume_init_verbs[] = { { } }; -#define alc268_mux_enum_info alc_mux_enum_info -#define alc268_mux_enum_get alc_mux_enum_get -#define alc268_mux_enum_put alc_mux_enum_put - static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT), @@ -11228,9 +11159,9 @@ static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc268_mux_enum_info, - .get = alc268_mux_enum_get, - .put = alc268_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -11248,9 +11179,9 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 2, - .info = alc268_mux_enum_info, - .get = alc268_mux_enum_get, - .put = alc268_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -13698,11 +13629,6 @@ static struct hda_input_mux alc861vd_hp_capture_source = { }, }; -#define alc861vd_mux_enum_info alc_mux_enum_info -#define alc861vd_mux_enum_get alc_mux_enum_get -/* ALC861VD has the ALC882-type input selection (but has only one ADC) */ -#define alc861vd_mux_enum_put alc882_mux_enum_put - /* * 2ch mode */ @@ -13760,9 +13686,9 @@ static struct snd_kcontrol_new alc861vd_capture_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc861vd_mux_enum_info, - .get = alc861vd_mux_enum_get, - .put = alc861vd_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -14588,6 +14514,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->adc_nids = alc861vd_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids); spec->capsrc_nids = alc861vd_capsrc_nids; + spec->is_mix_capture = 1; add_mixer(spec, alc861vd_capture_mixer); @@ -14676,10 +14603,6 @@ static struct hda_input_mux alc663_m51va_capture_source = { }, }; -#define alc662_mux_enum_info alc_mux_enum_info -#define alc662_mux_enum_get alc_mux_enum_get -#define alc662_mux_enum_put alc882_mux_enum_put - /* * 2ch mode */ @@ -15277,9 +15200,9 @@ static struct snd_kcontrol_new alc662_capture_mixer[] = { /* .name = "Capture Source", */ .name = "Input Source", .count = 1, - .info = alc662_mux_enum_info, - .get = alc662_mux_enum_get, - .put = alc662_mux_enum_put, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, }, { } /* end */ }; @@ -16420,6 +16343,7 @@ static int patch_alc662(struct hda_codec *codec) spec->adc_nids = alc662_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); spec->capsrc_nids = alc662_capsrc_nids; + spec->is_mix_capture = 1; spec->vmaster_nid = 0x02; From f9e336f65b666b8f1764d17e9b7c21c90748a37e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2008 16:37:07 +0100 Subject: [PATCH 049/367] ALSA: hda - Unify capture mixer creation in realtek codes Unified the capture mixer creation in patch_realtek.c. ALC268 is still an exception since it has no AMP in ADC but in MUX widget. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 744 ++++++++++------------------------ 1 file changed, 218 insertions(+), 526 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8477d6d46880..d511ce4b11ad 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -239,6 +239,7 @@ struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; + struct snd_kcontrol_new *cap_mixer; /* capture mixer */ const struct hda_verb *init_verbs[5]; /* initialization verbs * don't forget NULL @@ -323,6 +324,7 @@ struct alc_config_preset { struct snd_kcontrol_new *mixers[5]; /* should be identical size * with spec */ + struct snd_kcontrol_new *cap_mixer; /* capture mixer */ const struct hda_verb *init_verbs[5]; unsigned int num_dacs; hda_nid_t *dac_nids; @@ -766,6 +768,7 @@ static void setup_preset(struct alc_spec *spec, for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++) add_mixer(spec, preset->mixers[i]); + spec->cap_mixer = preset->cap_mixer; for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i]; i++) add_verb(spec, preset->init_verbs[i]); @@ -1244,48 +1247,117 @@ static struct snd_kcontrol_new alc880_three_stack_mixer[] = { }; /* capture mixer elements */ -static struct snd_kcontrol_new alc880_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; +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; + int err; -/* capture mixer elements (in case NID 0x07 not available) */ -static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, -}; + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, + HDA_INPUT); + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + mutex_unlock(&codec->spdif_mutex); /* reuse spdif_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; + int err; + + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, + HDA_INPUT); + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + mutex_unlock(&codec->spdif_mutex); /* reuse spdif_mutex */ + return err; +} + +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) +{ + 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); + int err; + + mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */ + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx], + 3, 0, HDA_INPUT); + err = func(kcontrol, ucontrol); + mutex_unlock(&codec->spdif_mutex); /* reuse spdif_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); +} + +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); +} + +/* 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); +} + +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); +} + +#define DEFINE_CAPMIX(num) \ +static struct snd_kcontrol_new alc_capture_mixer ## 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 }, \ + }, \ + { } /* end */ \ +} + +/* up to three ADCs */ +DEFINE_CAPMIX(1); +DEFINE_CAPMIX(2); +DEFINE_CAPMIX(3); /* @@ -1571,18 +1643,6 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -1690,7 +1750,11 @@ static int alc_build_controls(struct hda_codec *codec) 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); @@ -3318,6 +3382,8 @@ static struct alc_config_preset alc880_presets[] = { alc880_gpio2_init_verbs }, .num_dacs = ARRAY_SIZE(alc880_dac_nids), .dac_nids = alc880_dac_nids, + .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */ + .num_adc_nids = 1, /* single ADC */ .hp_nid = 0x03, .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes), .channel_mode = alc880_2_jack_modes, @@ -3958,6 +4024,17 @@ static void alc880_auto_init(struct hda_codec *codec) * OK, here we have finally the patch for ALC880 */ +static void set_capture_mixer(struct alc_spec *spec) +{ + static struct snd_kcontrol_new *caps[3] = { + alc_capture_mixer1, + alc_capture_mixer2, + alc_capture_mixer3, + }; + if (spec->num_adc_nids > 0 && spec->num_adc_nids < 3) + spec->cap_mixer = caps[spec->num_adc_nids - 1]; +} + static int patch_alc880(struct hda_codec *codec) { struct alc_spec *spec; @@ -4013,13 +4090,12 @@ static int patch_alc880(struct hda_codec *codec) if (wcap != AC_WID_AUD_IN) { spec->adc_nids = alc880_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt); - add_mixer(spec, alc880_capture_alt_mixer); } else { spec->adc_nids = alc880_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids); - add_mixer(spec, alc880_capture_mixer); } } + set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -4054,11 +4130,6 @@ static hda_nid_t alc260_adc_nids_alt[1] = { 0x05, }; -static hda_nid_t alc260_hp_adc_nids[2] = { - /* ADC1, 0 */ - 0x05, 0x04 -}; - /* NIDs used when simultaneous access to both ADCs makes sense. Note that * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC. */ @@ -4457,45 +4528,6 @@ static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = { { } /* end */ }; -/* capture mixer elements */ -static struct snd_kcontrol_new alc260_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x04, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x05, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x05, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc260_capture_alt_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x05, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x05, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - /* * initialization verbs */ @@ -5312,7 +5344,6 @@ static struct hda_verb alc260_volume_init_verbs[] = { static int alc260_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int wcap; int err; static hda_nid_t alc260_ignore[] = { 0x17, 0 }; @@ -5341,19 +5372,6 @@ static int alc260_parse_auto_config(struct hda_codec *codec) spec->num_mux_defs = 1; spec->input_mux = &spec->private_imux; - /* check whether NID 0x04 is valid */ - wcap = get_wcaps(codec, 0x04); - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; /* get type */ - if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { - spec->adc_nids = alc260_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); - add_mixer(spec, alc260_capture_alt_mixer); - } else { - spec->adc_nids = alc260_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); - add_mixer(spec, alc260_capture_mixer); - } - store_pin_configs(codec); return 1; } @@ -5423,12 +5441,11 @@ static struct alc_config_preset alc260_presets[] = { [ALC260_BASIC] = { .mixers = { alc260_base_output_mixer, alc260_input_mixer, - alc260_pc_beep_mixer, - alc260_capture_mixer }, + alc260_pc_beep_mixer }, .init_verbs = { alc260_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_adc_nids), + .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), .adc_nids = alc260_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, @@ -5436,14 +5453,13 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP] = { .mixers = { alc260_hp_output_mixer, - alc260_input_mixer, - alc260_capture_alt_mixer }, + alc260_input_mixer }, .init_verbs = { alc260_init_verbs, alc260_hp_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), - .adc_nids = alc260_hp_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5452,14 +5468,13 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP_DC7600] = { .mixers = { alc260_hp_dc7600_mixer, - alc260_input_mixer, - alc260_capture_alt_mixer }, + alc260_input_mixer }, .init_verbs = { alc260_init_verbs, alc260_hp_dc7600_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), - .adc_nids = alc260_hp_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5468,14 +5483,13 @@ static struct alc_config_preset alc260_presets[] = { }, [ALC260_HP_3013] = { .mixers = { alc260_hp_3013_mixer, - alc260_input_mixer, - alc260_capture_alt_mixer }, + alc260_input_mixer }, .init_verbs = { alc260_hp_3013_init_verbs, alc260_hp_3013_unsol_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, - .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), - .adc_nids = alc260_hp_adc_nids, + .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt), + .adc_nids = alc260_adc_nids_alt, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -5483,8 +5497,7 @@ static struct alc_config_preset alc260_presets[] = { .init_hook = alc260_hp_3013_automute, }, [ALC260_FUJITSU_S702X] = { - .mixers = { alc260_fujitsu_mixer, - alc260_capture_mixer }, + .mixers = { alc260_fujitsu_mixer }, .init_verbs = { alc260_fujitsu_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5496,8 +5509,7 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = alc260_fujitsu_capture_sources, }, [ALC260_ACER] = { - .mixers = { alc260_acer_mixer, - alc260_capture_mixer }, + .mixers = { alc260_acer_mixer }, .init_verbs = { alc260_acer_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5509,8 +5521,7 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = alc260_acer_capture_sources, }, [ALC260_WILL] = { - .mixers = { alc260_will_mixer, - alc260_capture_mixer }, + .mixers = { alc260_will_mixer }, .init_verbs = { alc260_init_verbs, alc260_will_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5522,8 +5533,7 @@ static struct alc_config_preset alc260_presets[] = { .input_mux = &alc260_capture_source, }, [ALC260_REPLACER_672V] = { - .mixers = { alc260_replacer_672v_mixer, - alc260_capture_mixer }, + .mixers = { alc260_replacer_672v_mixer }, .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs }, .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, @@ -5538,8 +5548,7 @@ static struct alc_config_preset alc260_presets[] = { }, #ifdef CONFIG_SND_DEBUG [ALC260_TEST] = { - .mixers = { alc260_test_mixer, - alc260_capture_mixer }, + .mixers = { alc260_test_mixer }, .init_verbs = { alc260_test_init_verbs }, .num_dacs = ARRAY_SIZE(alc260_test_dac_nids), .dac_nids = alc260_test_dac_nids, @@ -5598,6 +5607,8 @@ static int patch_alc260(struct hda_codec *codec) spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; + set_capture_mixer(spec); + spec->vmaster_nid = 0x08; codec->patch_ops = alc_patch_ops; @@ -6336,9 +6347,6 @@ static struct hda_verb alc882_auto_init_verbs[] = { { } }; -#define alc882_capture_alt_mixer alc880_capture_alt_mixer -#define alc882_capture_mixer alc880_capture_mixer - #ifdef CONFIG_SND_HDA_POWER_SAVE #define alc882_loopbacks alc880_loopbacks #endif @@ -6467,8 +6475,7 @@ static struct alc_config_preset alc882_presets[] = { .init_hook = alc885_imac24_init_hook, }, [ALC882_TARGA] = { - .mixers = { alc882_targa_mixer, alc882_chmode_mixer, - alc882_capture_mixer }, + .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, .init_verbs = { alc882_init_verbs, alc882_targa_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, @@ -6484,8 +6491,7 @@ static struct alc_config_preset alc882_presets[] = { .init_hook = alc882_targa_automute, }, [ALC882_ASUS_A7J] = { - .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer, - alc882_capture_mixer }, + .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs}, .num_dacs = ARRAY_SIZE(alc882_dac_nids), .dac_nids = alc882_dac_nids, @@ -6800,14 +6806,13 @@ static int patch_alc882(struct hda_codec *codec) spec->adc_nids = alc882_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); spec->capsrc_nids = alc882_capsrc_nids_alt; - add_mixer(spec, alc882_capture_alt_mixer); } else { spec->adc_nids = alc882_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); spec->capsrc_nids = alc882_capsrc_nids; - add_mixer(spec, alc882_capture_mixer); } } + set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -6846,6 +6851,11 @@ static hda_nid_t alc883_adc_nids[2] = { 0x08, 0x09, }; +static hda_nid_t alc883_adc_nids_alt[1] = { + /* ADC1 */ + 0x08, +}; + static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 }; /* input MUX */ @@ -7067,19 +7077,6 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7097,19 +7094,6 @@ static struct snd_kcontrol_new alc883_mitac_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7124,19 +7108,6 @@ static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7151,19 +7122,6 @@ static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7183,19 +7141,6 @@ static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7221,17 +7166,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7258,19 +7192,6 @@ static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7296,18 +7217,6 @@ static struct snd_kcontrol_new alc883_fivestack_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7328,19 +7237,6 @@ static struct snd_kcontrol_new alc883_tagra_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7356,19 +7252,6 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7381,17 +7264,6 @@ static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7405,19 +7277,6 @@ static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("iMic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_MUTE("iMic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7431,19 +7290,6 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = { HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7456,19 +7302,6 @@ static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7496,19 +7329,6 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -7539,6 +7359,10 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), { @@ -8203,9 +8027,6 @@ static struct hda_verb alc883_auto_init_verbs[] = { { } }; -/* capture mixer elements */ -#define alc883_capture_mixer alc880_capture_alt_mixer /* 2 ADC ver */ - static struct hda_verb alc888_asus_m90v_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -8485,6 +8306,8 @@ static struct alc_config_preset alc883_presets[] = { .init_verbs = { alc883_init_verbs, alc883_tagra_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .dig_out_nid = ALC883_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, @@ -8525,6 +8348,8 @@ static struct alc_config_preset alc883_presets[] = { alc883_medion_eapd_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, @@ -8567,6 +8392,8 @@ static struct alc_config_preset alc883_presets[] = { .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, + .adc_nids = alc883_adc_nids_alt, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_lenovo_101e_capture_source, @@ -8663,8 +8490,6 @@ static struct alc_config_preset alc883_presets[] = { .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .dig_out_nid = ALC883_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), - .adc_nids = alc883_adc_nids, .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .need_dac_fix = 1, @@ -8688,6 +8513,7 @@ static struct alc_config_preset alc883_presets[] = { }, [ALC888_ASUS_EEE1601] = { .mixers = { alc883_asus_eee1601_mixer }, + .cap_mixer = alc883_asus_eee1601_cap_mixer, .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs }, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, @@ -8794,7 +8620,6 @@ static int alc883_parse_auto_config(struct hda_codec *codec) /* hack - override the init verbs */ spec->init_verbs[0] = alc883_auto_init_verbs; - add_mixer(spec, alc883_capture_mixer); return 1; /* config found */ } @@ -8877,10 +8702,15 @@ static int patch_alc883(struct hda_codec *codec) spec->stream_digital_playback = &alc883_pcm_digital_playback; spec->stream_digital_capture = &alc883_pcm_digital_capture; - spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); - spec->adc_nids = alc883_adc_nids; - spec->capsrc_nids = alc883_capsrc_nids; + if (!spec->num_adc_nids) { + spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); + spec->adc_nids = alc883_adc_nids; + } + if (!spec->capsrc_nids) + spec->capsrc_nids = alc883_capsrc_nids; spec->is_mix_capture = 1; /* matrix-style capture */ + if (!spec->cap_mixer) + set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -9371,20 +9201,6 @@ static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = { HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -10556,7 +10372,8 @@ static struct alc_config_preset alc262_presets[] = { .init_hook = alc262_hippo_automute, }, [ALC262_ULTRA] = { - .mixers = { alc262_ultra_mixer, alc262_ultra_capture_mixer }, + .mixers = { alc262_ultra_mixer }, + .cap_mixer = alc262_ultra_capture_mixer, .init_verbs = { alc262_ultra_verbs }, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, @@ -10693,14 +10510,14 @@ static int patch_alc262(struct hda_codec *codec) spec->adc_nids = alc262_adc_nids_alt; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids_alt); spec->capsrc_nids = alc262_capsrc_nids_alt; - add_mixer(spec, alc262_capture_alt_mixer); } else { spec->adc_nids = alc262_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc262_adc_nids); spec->capsrc_nids = alc262_capsrc_nids; - add_mixer(spec, alc262_capture_mixer); } } + if (!spec->cap_mixer) + set_capture_mixer(spec); spec->vmaster_nid = 0x0c; @@ -11832,25 +11649,6 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = { { } /* end */ }; -/* capture mixer elements */ -static struct snd_kcontrol_new alc269_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - /* capture mixer elements */ static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), @@ -12247,7 +12045,8 @@ static int alc269_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - add_mixer(spec, alc269_capture_mixer); + if (!spec->cap_mixer) + set_capture_mixer(spec); store_pin_configs(codec); return 1; @@ -12292,7 +12091,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { static struct alc_config_preset alc269_presets[] = { [ALC269_BASIC] = { - .mixers = { alc269_base_mixer, alc269_capture_mixer }, + .mixers = { alc269_base_mixer }, .init_verbs = { alc269_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), .dac_nids = alc269_dac_nids, @@ -12314,7 +12113,8 @@ static struct alc_config_preset alc269_presets[] = { .init_hook = alc269_quanta_fl1_init_hook, }, [ALC269_ASUS_EEEPC_P703] = { - .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer }, + .mixers = { alc269_eeepc_mixer }, + .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs, alc269_eeepc_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), @@ -12327,7 +12127,8 @@ static struct alc_config_preset alc269_presets[] = { .init_hook = alc269_eeepc_amic_inithook, }, [ALC269_ASUS_EEEPC_P901] = { - .mixers = { alc269_eeepc_mixer, alc269_epc_capture_mixer}, + .mixers = { alc269_eeepc_mixer }, + .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs, alc269_eeepc_dmic_init_verbs }, .num_dacs = ARRAY_SIZE(alc269_dac_nids), @@ -12393,6 +12194,8 @@ static int patch_alc269(struct hda_codec *codec) spec->adc_nids = alc269_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); spec->capsrc_nids = alc269_capsrc_nids; + if (!spec->cap_mixer) + set_capture_mixer(spec); codec->patch_ops = alc_patch_ops; if (board_config == ALC269_AUTO) @@ -12533,17 +12336,6 @@ static struct snd_kcontrol_new alc861_base_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { } /* end */ }; @@ -12567,17 +12359,6 @@ static struct snd_kcontrol_new alc861_3ST_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -12595,18 +12376,6 @@ static struct snd_kcontrol_new alc861_toshiba_mixer[] = { HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT), - /*Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ }; @@ -12630,17 +12399,6 @@ static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT), - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -12672,17 +12430,6 @@ static struct snd_kcontrol_new alc861_asus_mixer[] = { HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT), HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT), - /* Capture mixer control */ - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Channel Mode", @@ -13214,25 +12961,6 @@ static int alc861_auto_create_analog_input_ctls(struct alc_spec *spec, return 0; } -static struct snd_kcontrol_new alc861_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - static void alc861_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, int dac_idx) @@ -13333,7 +13061,7 @@ static int alc861_parse_auto_config(struct hda_codec *codec) spec->adc_nids = alc861_adc_nids; spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); - add_mixer(spec, alc861_capture_mixer); + set_capture_mixer(spec); store_pin_configs(codec); return 1; @@ -13674,25 +13402,6 @@ static struct snd_kcontrol_new alc861vd_chmode_mixer[] = { { } /* end */ }; -static struct snd_kcontrol_new alc861vd_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ @@ -14516,7 +14225,7 @@ static int patch_alc861vd(struct hda_codec *codec) spec->capsrc_nids = alc861vd_capsrc_nids; spec->is_mix_capture = 1; - add_mixer(spec, alc861vd_capture_mixer); + set_capture_mixer(spec); spec->vmaster_nid = 0x02; @@ -15188,25 +14897,6 @@ static struct hda_verb alc662_ecs_init_verbs[] = { {} }; -/* capture mixer elements */ -static struct snd_kcontrol_new alc662_capture_mixer[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - static struct snd_kcontrol_new alc662_auto_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), @@ -15778,7 +15468,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { static struct alc_config_preset alc662_presets[] = { [ALC662_3ST_2ch_DIG] = { - .mixers = { alc662_3ST_2ch_mixer, alc662_capture_mixer }, + .mixers = { alc662_3ST_2ch_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15789,8 +15479,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch_DIG] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, - alc662_capture_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15802,8 +15491,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_3ST_6ch] = { - .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer, - alc662_capture_mixer }, + .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15813,8 +15501,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_5ST_DIG] = { - .mixers = { alc662_base_mixer, alc662_chmode_mixer, - alc662_capture_mixer }, + .mixers = { alc662_base_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15825,7 +15512,7 @@ static struct alc_config_preset alc662_presets[] = { .input_mux = &alc662_capture_source, }, [ALC662_LENOVO_101E] = { - .mixers = { alc662_lenovo_101e_mixer, alc662_capture_mixer }, + .mixers = { alc662_lenovo_101e_mixer }, .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15836,7 +15523,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_lenovo_101e_all_automute, }, [ALC662_ASUS_EEEPC_P701] = { - .mixers = { alc662_eeepc_p701_mixer, alc662_capture_mixer }, + .mixers = { alc662_eeepc_p701_mixer }, .init_verbs = { alc662_init_verbs, alc662_eeepc_sue_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15848,7 +15535,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_inithook, }, [ALC662_ASUS_EEEPC_EP20] = { - .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer, + .mixers = { alc662_eeepc_ep20_mixer, alc662_chmode_mixer }, .init_verbs = { alc662_init_verbs, alc662_eeepc_ep20_sue_init_verbs }, @@ -15861,7 +15548,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_ep20_inithook, }, [ALC662_ECS] = { - .mixers = { alc662_ecs_mixer, alc662_capture_mixer }, + .mixers = { alc662_ecs_mixer }, .init_verbs = { alc662_init_verbs, alc662_ecs_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15873,7 +15560,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_eeepc_inithook, }, [ALC663_ASUS_M51VA] = { - .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, + .mixers = { alc663_m51va_mixer }, .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15885,7 +15572,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_m51va_inithook, }, [ALC663_ASUS_G71V] = { - .mixers = { alc663_g71v_mixer, alc662_capture_mixer}, + .mixers = { alc663_g71v_mixer }, .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15897,7 +15584,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_g71v_inithook, }, [ALC663_ASUS_H13] = { - .mixers = { alc663_m51va_mixer, alc662_capture_mixer}, + .mixers = { alc663_m51va_mixer }, .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15908,7 +15595,7 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_m51va_inithook, }, [ALC663_ASUS_G50V] = { - .mixers = { alc663_g50v_mixer, alc662_capture_mixer}, + .mixers = { alc663_g50v_mixer }, .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), .dac_nids = alc662_dac_nids, @@ -15920,7 +15607,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_g50v_inithook, }, [ALC663_ASUS_MODE1] = { - .mixers = { alc663_m51va_mixer, alc662_auto_capture_mixer }, + .mixers = { alc663_m51va_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_21jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15934,7 +15622,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode1_inithook, }, [ALC662_ASUS_MODE2] = { - .mixers = { alc662_1bjd_mixer, alc662_auto_capture_mixer }, + .mixers = { alc662_1bjd_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc662_1bjd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15947,7 +15636,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc662_mode2_inithook, }, [ALC663_ASUS_MODE3] = { - .mixers = { alc663_two_hp_m1_mixer, alc662_auto_capture_mixer }, + .mixers = { alc663_two_hp_m1_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_two_hp_amic_m1_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15961,8 +15651,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode3_inithook, }, [ALC663_ASUS_MODE4] = { - .mixers = { alc663_asus_21jd_clfe_mixer, - alc662_auto_capture_mixer}, + .mixers = { alc663_asus_21jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_21jd_amic_init_verbs}, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15976,8 +15666,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode4_inithook, }, [ALC663_ASUS_MODE5] = { - .mixers = { alc663_asus_15jd_clfe_mixer, - alc662_auto_capture_mixer }, + .mixers = { alc663_asus_15jd_clfe_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_15jd_amic_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -15991,7 +15681,8 @@ static struct alc_config_preset alc662_presets[] = { .init_hook = alc663_mode5_inithook, }, [ALC663_ASUS_MODE6] = { - .mixers = { alc663_two_hp_m2_mixer, alc662_auto_capture_mixer }, + .mixers = { alc663_two_hp_m2_mixer }, + .cap_mixer = alc662_auto_capture_mixer, .init_verbs = { alc662_init_verbs, alc663_two_hp_amic_m2_init_verbs }, .num_dacs = ARRAY_SIZE(alc662_dac_nids), @@ -16266,8 +15957,6 @@ static int alc662_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; - add_mixer(spec, alc662_capture_mixer); - store_pin_configs(codec); return 1; } @@ -16345,6 +16034,9 @@ static int patch_alc662(struct hda_codec *codec) spec->capsrc_nids = alc662_capsrc_nids; spec->is_mix_capture = 1; + if (!spec->cap_mixer) + set_capture_mixer(spec); + spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; From 3c3e9892a1dacca2ba9e05c196ab1ea99c544360 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 31 Oct 2008 17:48:56 +0100 Subject: [PATCH 050/367] ALSA: hda - Re-add input-source control for Realtek Re-added again "Input Source" control that was removed mistakenly in the previous patchset. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d511ce4b11ad..88e54db0582c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1351,6 +1351,15 @@ static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ .put = alc_cap_vol_put, \ .tlv = { .c = alc_cap_vol_tlv }, \ }, \ + { \ + .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, \ + }, \ { } /* end */ \ } From 4074ea21493fe668501bfc7548d10657ca6f14c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 1 Nov 2008 11:01:50 +0100 Subject: [PATCH 051/367] ALSA: ice1724 - Fix IRQ register initialization The IRQMASK register has to be set to zero expclitily at the initialization otherwise you'll get no interrupts properly at later operations. Also, removed the old commented out codes. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 79a9cd0881f7..40725dfdc864 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -2353,7 +2353,6 @@ static int __devinit snd_vt1724_create(struct snd_card *card, { struct snd_ice1712 *ice; int err; - /* unsigned char mask; */ static struct snd_device_ops ops = { .dev_free = snd_vt1724_dev_free, }; @@ -2414,11 +2413,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card, return -EIO; } - /* unmask used interrupts */ -#if 0 /* these are enabled/disabled dynamically */ - mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX; - outb(mask, ICEREG1724(ice, IRQMASK)); -#endif + /* clear interrupts -- otherwise you'll get irq problems later */ + outb(0, ICEREG1724(ice, IRQMASK)); + /* don't handle FIFO overrun/underruns (just yet), * since they cause machine lockups */ From 26f5df265f06b8c8fe9f5d0942b7d8df00e5edec Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Nov 2008 17:39:46 +0100 Subject: [PATCH 052/367] ALSA: hda - Add ALC299 fujitsu preset model Added a preset model for FSC Amilo with ALC269 codec chip. Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 2 ++ sound/pci/hda/patch_realtek.c | 29 ++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index e0e54a27fc10..fa8e9fadfaf4 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -857,6 +857,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. quanta Quanta FL1 eeepc-p703 ASUS Eeepc P703 P900A eeepc-p901 ASUS Eeepc P901 S101 + fujitsu FSC Amilo + auto auto-config reading BIOS (default) ALC662/663 3stack-dig 3-stack (2-channel) with SPDIF diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 88e54db0582c..700fc8632c66 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -130,6 +130,7 @@ enum { ALC269_QUANTA_FL1, ALC269_ASUS_EEEPC_P703, ALC269_ASUS_EEEPC_P901, + ALC269_FUJITSU, ALC269_AUTO, ALC269_MODEL_LAST /* last tag */ }; @@ -1726,6 +1727,7 @@ static const char *alc_slave_vols[] = { "Speaker Playback Volume", "Mono Playback Volume", "Line-Out Playback Volume", + "PCM Playback Volume", NULL, }; @@ -11662,6 +11664,15 @@ static struct snd_kcontrol_new alc269_eeepc_mixer[] = { static struct snd_kcontrol_new alc269_epc_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + { } /* end */ +}; + +/* FSC amilo */ +static struct snd_kcontrol_new alc269_fujitsu_mixer[] = { + HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_BIND_VOL("PCM Playback Volume", &alc269_epc_bind_vol), { } /* end */ }; @@ -12084,7 +12095,8 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { [ALC269_BASIC] = "basic", [ALC269_QUANTA_FL1] = "quanta", [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", - [ALC269_ASUS_EEEPC_P901] = "eeepc-p901" + [ALC269_ASUS_EEEPC_P901] = "eeepc-p901", + [ALC269_FUJITSU] = "fujitsu" }; static struct snd_pci_quirk alc269_cfg_tbl[] = { @@ -12095,6 +12107,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { ALC269_ASUS_EEEPC_P901), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", ALC269_ASUS_EEEPC_P901), + SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), {} }; @@ -12149,6 +12162,20 @@ static struct alc_config_preset alc269_presets[] = { .unsol_event = alc269_eeepc_dmic_unsol_event, .init_hook = alc269_eeepc_dmic_inithook, }, + [ALC269_FUJITSU] = { + .mixers = { alc269_fujitsu_mixer, alc269_beep_mixer }, + .cap_mixer = alc269_epc_capture_mixer, + .init_verbs = { alc269_init_verbs, + alc269_eeepc_dmic_init_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_eeepc_dmic_capture_source, + .unsol_event = alc269_eeepc_dmic_unsol_event, + .init_hook = alc269_eeepc_dmic_inithook, + }, }; static int patch_alc269(struct hda_codec *codec) From 4ef0ef1966dae9e9e29762e4e719af3cfd146ca0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Nov 2008 17:47:49 +0100 Subject: [PATCH 053/367] ALSA: hda - Fix missing ADC list in ALC260 auto-probe mode The commit f9e336f65b666b8f1764d17e9b7c21c90748a37e ALSA: hda - Unify capture mixer creation in realtek codes removed the ADC check for ALC260 auto-probe mode accidentally. Re-added to patch_alc260() again. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 700fc8632c66..e727e48a48e3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5618,6 +5618,19 @@ static int patch_alc260(struct hda_codec *codec) spec->stream_digital_playback = &alc260_pcm_digital_playback; spec->stream_digital_capture = &alc260_pcm_digital_capture; + if (!spec->adc_nids && spec->input_mux) { + /* check whether NID 0x04 is valid */ + unsigned int wcap = get_wcaps(codec, 0x04); + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + /* get type */ + if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) { + spec->adc_nids = alc260_adc_nids_alt; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt); + } else { + spec->adc_nids = alc260_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids); + } + } set_capture_mixer(spec); spec->vmaster_nid = 0x08; From dce908e26fa0ea7d504d3f294c7411ed1eba5077 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Mon, 3 Nov 2008 12:22:07 -0700 Subject: [PATCH 054/367] ALSA: SOC: Fix setting codec register with debugfs filesystem merge error Call device_create_file only once in snd_soc_dapm_sys_add function. Signed-off-by: Troy Kisky Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/soc-dapm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7bf3c4094592..0fecbb44726b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -822,14 +822,8 @@ static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); int snd_soc_dapm_sys_add(struct device *dev) { - int ret; - if (!dapm_status) return 0; - - ret = device_create_file(dev, &dev_attr_dapm_widget); - if (ret != 0) - return ret; return device_create_file(dev, &dev_attr_dapm_widget); } From b91f080f517cf9dd52023c11127a0ca33190e31a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2008 08:43:08 +0100 Subject: [PATCH 055/367] ALSA: hda - Fix possible NULL dereference Add NULL-check of the return value of snd_kctl_new1() before accessing it. Also, make a sanity NULL check to snd_BUG_ON() for debugging only. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8991db78fb67..aa9cd142c30a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1697,6 +1697,8 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) } for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); + if (!kctl) + return -ENOMEM; kctl->id.index = idx; kctl->private_value = nid; err = snd_hda_ctl_add(codec, kctl); @@ -2412,7 +2414,7 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) struct hda_pcm_stream *info; int stream, err; - if (!pcm->name) + if (snd_BUG_ON(!pcm->name)) return -EINVAL; for (stream = 0; stream < 2; stream++) { info = &pcm->stream[stream]; From bfc5c26fb692fa7a196108c3b23d9c747d105c00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2008 17:48:39 +0100 Subject: [PATCH 056/367] ALSA: hda - Don't create empty PCM streams Due to the hda-reconfiguration patches, the check of empty stream is gone, and this results in an error with the codec setup with empty streams. This patch adds the check again to avoid the error at probing. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index aa9cd142c30a..3e7cda9c3de5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2485,6 +2485,11 @@ int snd_hda_build_pcms(struct hda_bus *bus) struct hda_pcm *cpcm = &codec->pcm_info[pcm]; int type = cpcm->pcm_type; int dev; + + if (!cpcm->stream[0].substreams && + !cpcm->stream[1].substreams) + continue; /* no substreams assigned */ + switch (type) { case HDA_PCM_TYPE_AUDIO: if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { From 3865675c60aec3e81d72d484680b544afc6fc51d Mon Sep 17 00:00:00 2001 From: Huang Weiyi Date: Fri, 31 Oct 2008 22:50:00 +0800 Subject: [PATCH 057/367] ALSA: ASoC codec: remove unused #include The file(s) below do not use LINUX_VERSION_CODE nor KERNEL_VERSION. sound/soc/codecs/ad73311.c This patch removes the said #include . Signed-off-by: Huang Weiyi Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/ad73311.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 37af8607b00a..59c4c8f18cbb 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include From 0ee4663617fb0f78cec4cc6558a096ccbd8c3ffc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 4 Nov 2008 18:06:23 +0100 Subject: [PATCH 058/367] ALSA: ASoC - Remove unnecessary inclusion of linux/version.h Signed-off-by: Takashi Iwai --- sound/soc/atmel/playpaq_wm8510.c | 1 - sound/soc/atmel/sam9g20_wm8731.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index 5b07cf7ea4e7..ea7935d2a66d 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 4e191df4e2b7..710addcc66b3 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include From 91504877c50a792412e2043a1c2099f054d7254a Mon Sep 17 00:00:00 2001 From: "Wu, Fengguang" Date: Wed, 5 Nov 2008 11:16:56 +0800 Subject: [PATCH 059/367] ALSA: hda - Intel HDMI audio support Add support for Intel G45 integrated HDMI audio codecs. This initial release supports: - 2 channel stereo sound output - report monitor's ELD information Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 8 + sound/pci/hda/Makefile | 1 + sound/pci/hda/hda_codec.c | 3 + sound/pci/hda/hda_patch.h | 2 + sound/pci/hda/patch_intelhdmi.c | 926 ++++++++++++++++++++++++++++++++ 5 files changed, 940 insertions(+) create mode 100644 sound/pci/hda/patch_intelhdmi.c diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7e408908b755..21e9327a0ef4 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -574,6 +574,14 @@ config SND_HDA_CODEC_NVHDMI Say Y here to include NVIDIA HDMI HD-audio codec support in snd-hda-intel driver, such as NVIDIA MCP78 HDMI. +config SND_HDA_CODEC_INTELHDMI + bool "Build INTEL HDMI HD-audio codec support" + depends on SND_HDA_INTEL + default y + help + Say Y here to include INTEL HDMI HD-audio codec support in + snd-hda-intel driver, such as Eaglelake integrated HDMI. + config SND_HDA_CODEC_CONEXANT bool "Build Conexant HD-audio codec support" depends on SND_HDA_INTEL diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 1980c6d207e7..6fb5add1e39a 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -16,5 +16,6 @@ snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o +snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3e7cda9c3de5..45695d608c76 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -97,6 +97,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = { #endif #ifdef CONFIG_SND_HDA_CODEC_NVHDMI snd_hda_preset_nvhdmi, +#endif +#ifdef CONFIG_SND_HDA_CODEC_INTELHDMI + snd_hda_preset_intelhdmi, #endif NULL }; diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index dfbcfa88da44..38212c1020a6 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h @@ -20,3 +20,5 @@ extern struct hda_codec_preset snd_hda_preset_conexant[]; extern struct hda_codec_preset snd_hda_preset_via[]; /* NVIDIA HDMI codecs */ extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; +/* INTEL HDMI codecs */ +extern struct hda_codec_preset snd_hda_preset_intelhdmi[]; diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c new file mode 100644 index 000000000000..8059102dd862 --- /dev/null +++ b/sound/pci/hda/patch_intelhdmi.c @@ -0,0 +1,926 @@ +/* + * + * patch_intelhdmi.c - Patch for Intel HDMI codecs + * + * Copyright(c) 2008 Intel Corporation. All rights reserved. + * + * Authors: + * Jiang Zhe + * Wu Fengguang + * + * Maintained by: + * Wu Fengguang + * + * 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 +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" +#include "hda_patch.h" + +#define CVT_NID 0x02 /* audio converter */ +#define PIN_NID 0x03 /* HDMI output pin */ + +#define INTEL_HDMI_EVENT_TAG 0x08 + +/* + * CEA Short Audio Descriptor data + */ +struct cea_sad { + int channels; + int format; /* (format == 0) indicates invalid SAD */ + int rates; + int sample_bits; /* for LPCM */ + int max_bitrate; /* for AC3...ATRAC */ + int profile; /* for WMAPRO */ +}; + +#define ELD_FIXED_BYTES 20 +#define ELD_MAX_MNL 16 +#define ELD_MAX_SAD 16 + +/* + * ELD: EDID Like Data + */ +struct sink_eld { + int eld_size; + int baseline_len; + int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ + int cea_edid_ver; + char monitor_name[ELD_MAX_MNL + 1]; + int manufacture_id; + int product_id; + u64 port_id; + int support_hdcp; + int support_ai; + int conn_type; + int aud_synch_delay; + int spk_alloc; + int sad_count; + struct cea_sad sad[ELD_MAX_SAD]; +}; + +struct intel_hdmi_spec { + struct hda_multi_out multiout; + struct hda_pcm pcm_rec; + struct sink_eld sink; +}; + +static struct hda_verb pinout_enable_verb[] = { + {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {} /* terminator */ +}; + +static struct hda_verb pinout_disable_verb[] = { + {PIN_NID, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00}, + {} +}; + +static struct hda_verb unsolicited_response_verb[] = { + {PIN_NID, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | + INTEL_HDMI_EVENT_TAG}, + {} +}; + +static struct hda_verb def_chan_map[] = { + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x00}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x11}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x22}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x33}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x44}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x55}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x66}, + {CVT_NID, AC_VERB_SET_HDMI_CHAN_SLOT, 0x77}, + {} +}; + + +struct hdmi_audio_infoframe { + u8 type; /* 0x84 */ + u8 ver; /* 0x01 */ + u8 len; /* 0x0a */ + + u8 checksum; /* PB0 */ + u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; + u8 reserved[5]; /* PB6 - PB10 */ +}; + +/* + * SS1:SS0 index => sample size + */ +static int cea_sample_sizes[4] = { + 0, /* 0: Refer to Stream Header */ + AC_SUPPCM_BITS_16, /* 1: 16 bits */ + AC_SUPPCM_BITS_20, /* 2: 20 bits */ + AC_SUPPCM_BITS_24, /* 3: 24 bits */ +}; + +/* + * SF2:SF1:SF0 index => sampling frequency + */ +static int cea_sampling_frequencies[8] = { + 0, /* 0: Refer to Stream Header */ + SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ + SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ + SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ + SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ + SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ + SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ + SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ +}; + +enum eld_versions { + ELD_VER_CEA_861D = 2, + ELD_VER_PARTIAL = 31, +}; + +static char *eld_versoin_names[32] = { + "0-reserved", + "1-reserved", + "CEA-861D or below", + "3-reserved", + [4 ... 30] = "reserved", + [31] = "partial" +}; + +enum cea_edid_versions { + CEA_EDID_VER_NONE = 0, + CEA_EDID_VER_CEA861 = 1, + CEA_EDID_VER_CEA861A = 2, + CEA_EDID_VER_CEA861BCD = 3, + CEA_EDID_VER_RESERVED = 4, +}; + +static char *cea_edid_version_names[8] = { + "no CEA EDID Timing Extension block present", + "CEA-861", + "CEA-861-A", + "CEA-861-B, C or D", + "4-reserved", + [5 ... 7] = "reserved" +}; + +/* + * CEA Speaker Allocation data block bits + */ +#define CEA_SA_FLR (0 << 0) +#define CEA_SA_LFE (1 << 1) +#define CEA_SA_FC (1 << 2) +#define CEA_SA_RLR (1 << 3) +#define CEA_SA_RC (1 << 4) +#define CEA_SA_FLRC (1 << 5) +#define CEA_SA_RLRC (1 << 6) +/* the following are not defined in ELD yet */ +#define CEA_SA_FLRW (1 << 7) +#define CEA_SA_FLRH (1 << 8) +#define CEA_SA_TC (1 << 9) +#define CEA_SA_FCH (1 << 10) + +static char *cea_speaker_allocation_names[] = { + /* 0 */ "FL/FR", + /* 1 */ "LFE", + /* 2 */ "FC", + /* 3 */ "RL/RR", + /* 4 */ "RC", + /* 5 */ "FLC/FRC", + /* 6 */ "RLC/RRC", + /* 7 */ "FLW/FRW", + /* 8 */ "FLH/FRH", + /* 9 */ "TC", + /* 10 */ "FCH", +}; + +static char *eld_connection_type_names[4] = { + "HDMI", + "Display Port", + "2-reserved", + "3-reserved" +}; + +enum cea_audio_coding_types { + AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, + AUDIO_CODING_TYPE_LPCM = 1, + AUDIO_CODING_TYPE_AC3 = 2, + AUDIO_CODING_TYPE_MPEG1 = 3, + AUDIO_CODING_TYPE_MP3 = 4, + AUDIO_CODING_TYPE_MPEG2 = 5, + AUDIO_CODING_TYPE_AACLC = 6, + AUDIO_CODING_TYPE_DTS = 7, + AUDIO_CODING_TYPE_ATRAC = 8, + AUDIO_CODING_TYPE_SACD = 9, + AUDIO_CODING_TYPE_EAC3 = 10, + AUDIO_CODING_TYPE_DTS_HD = 11, + AUDIO_CODING_TYPE_MLP = 12, + AUDIO_CODING_TYPE_DST = 13, + AUDIO_CODING_TYPE_WMAPRO = 14, + AUDIO_CODING_TYPE_REF_CXT = 15, + /* also include valid xtypes below */ + AUDIO_CODING_TYPE_HE_AAC = 15, + AUDIO_CODING_TYPE_HE_AAC2 = 16, + AUDIO_CODING_TYPE_MPEG_SURROUND = 17, +}; + +enum cea_audio_coding_xtypes { + AUDIO_CODING_XTYPE_HE_REF_CT = 0, + AUDIO_CODING_XTYPE_HE_AAC = 1, + AUDIO_CODING_XTYPE_HE_AAC2 = 2, + AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, + AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, +}; + +static char *cea_audio_coding_type_names[] = { + /* 0 */ "undefined", + /* 1 */ "LPCM", + /* 2 */ "AC-3", + /* 3 */ "MPEG1", + /* 4 */ "MP3", + /* 5 */ "MPEG2", + /* 6 */ "AAC-LC", + /* 7 */ "DTS", + /* 8 */ "ATRAC", + /* 9 */ "DSD(1-bit audio)", + /* 10 */ "Dolby Digital Plus(E-AC-3/DD+)", + /* 11 */ "DTS-HD", + /* 12 */ "Dolby TrueHD(MLP)", + /* 13 */ "DST", + /* 14 */ "WMAPro", + /* 15 */ "HE-AAC", + /* 16 */ "HE-AACv2", + /* 17 */ "MPEG Surround", +}; + + +/* + * HDMI routines + */ + +static int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, + AC_DIPSIZE_ELD_BUF); +} + +static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, + int *packet_index, int *byte_index) +{ + int val; + + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); + + *packet_index = val >> 5; + *byte_index = val & 0x1f; +} + +static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, + int packet_index, int byte_index) +{ + int val; + + val = (packet_index << 5) | (byte_index & 0x1f); + + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); +} + +static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, + unsigned char val) +{ + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); +} + +static void hdmi_enable_output(struct hda_codec *codec) +{ + /* Enable pin out and unmute */ + snd_hda_sequence_write(codec, pinout_enable_verb); + 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); + + /* Enable Audio InfoFrame Transmission */ + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, + AC_DIPXMIT_BEST); +} + +static void hdmi_disable_output(struct hda_codec *codec) +{ + snd_hda_sequence_write(codec, pinout_disable_verb); + 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_MUTE); + + /* + * FIXME: noises may arise when playing music after reloading the + * kernel module, until the next X restart or monitor repower. + */ +} + +static int hdmi_get_channel_count(struct hda_codec *codec) +{ + return 1 + snd_hda_codec_read(codec, CVT_NID, 0, + AC_VERB_GET_CVT_CHAN_COUNT, 0); +} + +static void hdmi_set_channel_count(struct hda_codec *codec, int chs) +{ + snd_hda_codec_write(codec, CVT_NID, 0, + AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); + + if (chs != hdmi_get_channel_count(codec)) + snd_printd(KERN_INFO "Channel count expect=%d, real=%d\n", + chs, hdmi_get_channel_count(codec)); +} + +static void hdmi_debug_slot_mapping(struct hda_codec *codec) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int i; + int slot; + + for (i = 0; i < 8; i++) { + slot = snd_hda_codec_read(codec, CVT_NID, 0, + AC_VERB_GET_HDMI_CHAN_SLOT, i); + printk(KERN_DEBUG "ASP channel %d => slot %d\n", + slot >> 4, slot & 0x7); + } +#endif +} + +static void hdmi_setup_channel_mapping(struct hda_codec *codec) +{ + snd_hda_sequence_write(codec, def_chan_map); + hdmi_debug_slot_mapping(codec); +} + + +/* + * ELD(EDID Like Data) routines + */ + +static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); +} + +static void hdmi_debug_present_sense(struct hda_codec *codec) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int eldv; + int present; + + present = hdmi_present_sense(codec, PIN_NID); + eldv = (present & AC_PINSENSE_ELDV); + present = (present & AC_PINSENSE_PRESENCE); + + printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); +#endif +} + +static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, int byte_index) +{ + unsigned int val; + + val = snd_hda_codec_read(codec, PIN_NID, 0, + AC_VERB_GET_HDMI_ELDD, byte_index); + +#ifdef BE_PARANOID + printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); +#endif + + if ((val & AC_ELDD_ELD_VALID) == 0) { + snd_printd(KERN_INFO "Invalid ELD data byte %d\n", + byte_index); + val = 0; + } + + return val & AC_ELDD_ELD_DATA; +} + +static inline unsigned char grab_bits(const unsigned char *buf, + int byte, int lowbit, int bits) +{ + BUG_ON(lowbit > 7); + BUG_ON(bits > 8); + BUG_ON(bits <= 0); + + return (buf[byte] >> lowbit) & ((1 << bits) - 1); +} + +static void hdmi_update_short_audio_desc(struct cea_sad *a, + const unsigned char *buf) +{ + int i; + int val; + + val = grab_bits(buf, 1, 0, 7); + a->rates = 0; + for (i = 0; i < 7; i++) + if (val & (1 << i)) + a->rates |= cea_sampling_frequencies[i + 1]; + + a->channels = grab_bits(buf, 0, 0, 3); + a->channels++; + + a->format = grab_bits(buf, 0, 3, 4); + switch (a->format) { + case AUDIO_CODING_TYPE_REF_STREAM_HEADER: + snd_printd(KERN_INFO + "audio coding type 0 not expected in ELD\n"); + break; + + case AUDIO_CODING_TYPE_LPCM: + val = grab_bits(buf, 2, 0, 3); + a->sample_bits = 0; + for (i = 0; i < 3; i++) + if (val & (1 << i)) + a->sample_bits |= cea_sample_sizes[i + 1]; + break; + + case AUDIO_CODING_TYPE_AC3: + case AUDIO_CODING_TYPE_MPEG1: + case AUDIO_CODING_TYPE_MP3: + case AUDIO_CODING_TYPE_MPEG2: + case AUDIO_CODING_TYPE_AACLC: + case AUDIO_CODING_TYPE_DTS: + case AUDIO_CODING_TYPE_ATRAC: + a->max_bitrate = grab_bits(buf, 2, 0, 8); + a->max_bitrate *= 8000; + break; + + case AUDIO_CODING_TYPE_SACD: + break; + + case AUDIO_CODING_TYPE_EAC3: + break; + + case AUDIO_CODING_TYPE_DTS_HD: + break; + + case AUDIO_CODING_TYPE_MLP: + break; + + case AUDIO_CODING_TYPE_DST: + break; + + case AUDIO_CODING_TYPE_WMAPRO: + a->profile = grab_bits(buf, 2, 0, 3); + break; + + case AUDIO_CODING_TYPE_REF_CXT: + a->format = grab_bits(buf, 2, 3, 5); + if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || + a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { + snd_printd(KERN_INFO + "audio coding xtype %d not expected in ELD\n", + a->format); + a->format = 0; + } else + a->format += AUDIO_CODING_TYPE_HE_AAC - + AUDIO_CODING_XTYPE_HE_AAC; + break; + } +} + +static int hdmi_update_sink_eld(struct hda_codec *codec, + const unsigned char *buf, int size) +{ + struct intel_hdmi_spec *spec = codec->spec; + struct sink_eld *e = &spec->sink; + int mnl; + int i; + + e->eld_ver = grab_bits(buf, 0, 3, 5); + if (e->eld_ver != ELD_VER_CEA_861D && + e->eld_ver != ELD_VER_PARTIAL) { + snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); + goto out_fail; + } + + e->eld_size = size; + e->baseline_len = grab_bits(buf, 2, 0, 8); + mnl = grab_bits(buf, 4, 0, 5); + e->cea_edid_ver = grab_bits(buf, 4, 5, 3); + + e->support_hdcp = grab_bits(buf, 5, 0, 1); + e->support_ai = grab_bits(buf, 5, 1, 1); + e->conn_type = grab_bits(buf, 5, 2, 2); + e->sad_count = grab_bits(buf, 5, 4, 4); + + e->aud_synch_delay = grab_bits(buf, 6, 0, 8); + e->spk_alloc = grab_bits(buf, 7, 0, 7); + + e->port_id = get_unaligned_le64(buf + 8); + + /* not specified, but the spec's tendency is little endian */ + e->manufacture_id = get_unaligned_le16(buf + 16); + e->product_id = get_unaligned_le16(buf + 18); + + if (mnl > ELD_MAX_MNL) { + snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); + goto out_fail; + } else if (ELD_FIXED_BYTES + mnl > size) { + snd_printd(KERN_INFO "out of range MNL %d\n", mnl); + goto out_fail; + } else + strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); + + for (i = 0; i < e->sad_count; i++) { + if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { + snd_printd(KERN_INFO "out of range SAD %d\n", i); + goto out_fail; + } + hdmi_update_short_audio_desc(e->sad + i, + buf + ELD_FIXED_BYTES + mnl + 3 * i); + } + + return 0; + +out_fail: + e->eld_ver = 0; + return -EINVAL; +} + +static int hdmi_get_eld(struct hda_codec *codec) +{ + int i; + int ret; + int size; + unsigned char *buf; + + i = hdmi_present_sense(codec, PIN_NID) & AC_PINSENSE_ELDV; + if (!i) + return -ENOENT; + + size = hdmi_get_eld_size(codec, PIN_NID); + if (size == 0) { + /* wfg: workaround for ASUS P5E-VM HDMI board */ + snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); + size = 128; + } + if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { + snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); + return -ERANGE; + } + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < size; i++) + buf[i] = hdmi_get_eld_byte(codec, i); + + ret = hdmi_update_sink_eld(codec, buf, size); + + kfree(buf); + return ret; +} + +static void hdmi_show_short_audio_desc(struct cea_sad *a) +{ + printk(KERN_INFO "coding type: %s\n", + cea_audio_coding_type_names[a->format]); + printk(KERN_INFO "channels: %d\n", a->channels); + printk(KERN_INFO "sampling frequencies: 0x%x\n", a->rates); + + if (a->format == AUDIO_CODING_TYPE_LPCM) + printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); + + if (a->max_bitrate) + printk(KERN_INFO "max bitrate: %d HZ\n", a->max_bitrate); + + if (a->profile) + printk(KERN_INFO "profile: %d\n", a->profile); +} + +static void hdmi_show_eld(struct hda_codec *codec) +{ + int i; + int j; + struct intel_hdmi_spec *spec = codec->spec; + struct sink_eld *e = &spec->sink; + char buf[80]; + + printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); + printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); + printk(KERN_INFO "vendor block len is %d\n", + e->eld_size - e->baseline_len * 4 - 4); + printk(KERN_INFO "ELD version is %s\n", + eld_versoin_names[e->eld_ver]); + printk(KERN_INFO "CEA EDID version is %s\n", + cea_edid_version_names[e->cea_edid_ver]); + printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); + printk(KERN_INFO "product id is 0x%x\n", e->product_id); + printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); + printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); + printk(KERN_INFO "AI support is %d\n", e->support_ai); + printk(KERN_INFO "SAD count is %d\n", e->sad_count); + printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); + printk(KERN_INFO "connection type is %s\n", + eld_connection_type_names[e->conn_type]); + printk(KERN_INFO "monitor name is %s\n", e->monitor_name); + + j = 0; + for (i = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { + if (e->spk_alloc & (1 << i)) + j += snprintf(buf + j, sizeof(buf) - j, " %s", + cea_speaker_allocation_names[i]); + } + buf[j] = '\0'; /* necessary when j == 0 */ + printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); + + for (i = 0; i < e->sad_count; i++) + hdmi_show_short_audio_desc(e->sad + i); +} + +/* + * Be careful, ELD buf could be totally rubbish! + */ +static void hdmi_parse_eld(struct hda_codec *codec) +{ + hdmi_debug_present_sense(codec); + + if (!hdmi_get_eld(codec)) + hdmi_show_eld(codec); +} + + +/* + * Audio Infoframe routines + */ + +static void hdmi_debug_dip_size(struct hda_codec *codec) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int i; + int size; + + size = hdmi_get_eld_size(codec, PIN_NID); + printk(KERN_DEBUG "ELD buf size is %d\n", size); + + for (i = 0; i < 8; i++) { + size = snd_hda_codec_read(codec, PIN_NID, 0, + AC_VERB_GET_HDMI_DIP_SIZE, i); + printk(KERN_DEBUG "DIP GP[%d] buf size is %d\n", i, size); + } +#endif +} + +static void hdmi_clear_dip_buffers(struct hda_codec *codec) +{ +#ifdef BE_PARANOID + int i, j; + int size; + int pi, bi; + for (i = 0; i < 8; i++) { + size = snd_hda_codec_read(codec, PIN_NID, 0, + AC_VERB_GET_HDMI_DIP_SIZE, i); + if (size == 0) + continue; + + hdmi_set_dip_index(codec, PIN_NID, i, 0x0); + for (j = 1; j < 1000; j++) { + hdmi_write_dip_byte(codec, PIN_NID, 0x0); + hdmi_get_dip_index(codec, PIN_NID, &pi, &bi); + if (pi != i) + snd_printd(KERN_INFO "dip index %d: %d != %d\n", + bi, pi, i); + if (bi == 0) /* byte index wrapped around */ + break; + } + snd_printd(KERN_INFO + "DIP GP[%d] buf reported size=%d, written=%d\n", + i, size, j); + } +#endif +} + +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_audio_infoframe audio_infoframe = { + .type = 0x84, + .ver = 0x01, + .len = 0x0a, + .CC02_CT47 = substream->runtime->channels - 1, + }; + u8 *params = (u8 *)&audio_infoframe; + int i; + + hdmi_debug_dip_size(codec); + hdmi_clear_dip_buffers(codec); /* be paranoid */ + + hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); + for (i = 0; i < sizeof(audio_infoframe); i++) + hdmi_write_dip_byte(codec, PIN_NID, params[i]); +} + + +/* + * Unsolicited events + */ + +static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) +{ + int pind = !!(res & AC_UNSOL_RES_PD); + int eldv = !!(res & AC_UNSOL_RES_ELDV); + + printk(KERN_INFO "HDMI intrinsic event: PD=%d ELDV=%d\n", pind, eldv); + + if (pind && eldv) { + hdmi_parse_eld(codec); + /* TODO: do real things about ELD */ + } +} + +static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) +{ + int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); + int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); + + printk(KERN_INFO "HDMI non-intrinsic event: " + "SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", + subtag, + cp_state, + cp_ready); + + /* who cares? */ + if (cp_state) + ; + if (cp_ready) + ; +} + + +static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) +{ + int tag = res >> AC_UNSOL_RES_TAG_SHIFT; + int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; + + if (tag != INTEL_HDMI_EVENT_TAG) { + snd_printd(KERN_INFO + "Unexpected HDMI unsolicited event tag 0x%x\n", + tag); + return; + } + + if (subtag == 0) + hdmi_intrinsic_event(codec, res); + else + hdmi_non_intrinsic_event(codec, res); +} + +/* + * Callbacks + */ + +static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct intel_hdmi_spec *spec = codec->spec; + + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct intel_hdmi_spec *spec = codec->spec; + + hdmi_disable_output(codec); + + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +static int intel_hdmi_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 intel_hdmi_spec *spec = codec->spec; + + snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, + format, substream); + + hdmi_set_channel_count(codec, substream->runtime->channels); + + /* wfg: channel mapping not supported by DEVCTG */ + hdmi_setup_channel_mapping(codec); + + hdmi_setup_audio_infoframe(codec, substream); + + hdmi_enable_output(codec); + + return 0; +} + +static struct hda_pcm_stream intel_hdmi_pcm_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .nid = CVT_NID, /* NID to query formats and rates and setup streams */ + .ops = { + .open = intel_hdmi_playback_pcm_open, + .close = intel_hdmi_playback_pcm_close, + .prepare = intel_hdmi_playback_pcm_prepare + }, +}; + +static int intel_hdmi_build_pcms(struct hda_codec *codec) +{ + struct intel_hdmi_spec *spec = codec->spec; + struct hda_pcm *info = &spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "INTEL HDMI"; + info->pcm_type = HDA_PCM_TYPE_HDMI; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; + + return 0; +} + +static int intel_hdmi_build_controls(struct hda_codec *codec) +{ + struct intel_hdmi_spec *spec = codec->spec; + int err; + + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + if (err < 0) + return err; + + return 0; +} + +static int intel_hdmi_init(struct hda_codec *codec) +{ + /* disable audio output as early as possible */ + hdmi_disable_output(codec); + + snd_hda_sequence_write(codec, unsolicited_response_verb); + + return 0; +} + +static void intel_hdmi_free(struct hda_codec *codec) +{ + kfree(codec->spec); +} + +static struct hda_codec_ops intel_hdmi_patch_ops = { + .init = intel_hdmi_init, + .free = intel_hdmi_free, + .build_pcms = intel_hdmi_build_pcms, + .build_controls = intel_hdmi_build_controls, + .unsol_event = intel_hdmi_unsol_event, +}; + +static int patch_intel_hdmi(struct hda_codec *codec) +{ + struct intel_hdmi_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + spec->multiout.num_dacs = 0; /* no analog */ + spec->multiout.max_channels = 8; + spec->multiout.dig_out_nid = CVT_NID; + + codec->spec = spec; + codec->patch_ops = intel_hdmi_patch_ops; + + return 0; +} + +struct hda_codec_preset snd_hda_preset_intelhdmi[] = { + { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi }, + { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, + { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, + { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi }, + {} /* terminator */ +}; From beb0b9cf78b56b0f30f5defe62b7b9712cd02a50 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Nov 2008 07:58:25 +0100 Subject: [PATCH 060/367] ALSA: hda - Fix unused function in patch_intelhdmi.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a proper ifdef to shut out a compile warning: CC [M] sound/pci/hda/patch_intelhdmi.o sound/pci/hda/patch_intelhdmi.c:286: warning: ‘hdmi_get_dip_index’ defined but \ not used Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 8059102dd862..3beaf9c1090c 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -281,6 +281,7 @@ static int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) AC_DIPSIZE_ELD_BUF); } +#ifdef BE_PARANOID static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, int *packet_index, int *byte_index) { @@ -291,6 +292,7 @@ static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, *packet_index = val >> 5; *byte_index = val & 0x1f; } +#endif static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, int packet_index, int byte_index) From 13c947444f4355293b49f83b809f178393a0a4d9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Nov 2008 08:06:08 +0100 Subject: [PATCH 061/367] ALSA: hda - Add ASUS V1Sn support Asus V1s series laptops have an ALC660VD with PCI id: 0x1043, 0x1633. 1.) remove the previous behaviour of mapping that to the ALC861VD_LENOVO device. 2.) add a new ALC660VD_V1S device based on ALC861VD_LENOVO, with an added digital out. Signed-off-by: Tristan Aston Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index fa8e9fadfaf4..f6594549bf5d 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -940,6 +940,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. lenovo Lenovo 3000 C200 dallas Dallas laptops hp HP TX1000 + asus-v1s ASUS V1Sn auto auto-config reading BIOS (default) CMI9880 diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e727e48a48e3..15779d8c7564 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -153,6 +153,7 @@ enum { enum { ALC660VD_3ST, ALC660VD_3ST_DIG, + ALC660VD_ASUS_V1S, ALC861VD_3ST, ALC861VD_3ST_DIG, ALC861VD_6ST_DIG, @@ -13842,6 +13843,7 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC660VD_3ST] = "3stack-660", [ALC660VD_3ST_DIG] = "3stack-660-digout", + [ALC660VD_ASUS_V1S] = "asus-v1s", [ALC861VD_3ST] = "3stack", [ALC861VD_3ST_DIG] = "3stack-digout", [ALC861VD_6ST_DIG] = "6stack-digout", @@ -13856,7 +13858,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), - SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC861VD_LENOVO), + SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), @@ -13963,6 +13965,21 @@ static struct alc_config_preset alc861vd_presets[] = { .unsol_event = alc861vd_dallas_unsol_event, .init_hook = alc861vd_dallas_automute, }, + [ALC660VD_ASUS_V1S] = { + .mixers = { alc861vd_lenovo_mixer }, + .init_verbs = { alc861vd_volume_init_verbs, + alc861vd_3stack_init_verbs, + alc861vd_eapd_verbs, + alc861vd_lenovo_unsol_verbs }, + .num_dacs = ARRAY_SIZE(alc660vd_dac_nids), + .dac_nids = alc660vd_dac_nids, + .dig_out_nid = ALC861VD_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), + .channel_mode = alc861vd_3stack_2ch_modes, + .input_mux = &alc861vd_capture_source, + .unsol_event = alc861vd_lenovo_unsol_event, + .init_hook = alc861vd_lenovo_automute, + }, }; /* From c238b4f4038e0e49bb241640610584a088b268b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Nov 2008 14:57:20 +0100 Subject: [PATCH 062/367] ALSA: hda - Split ALC268 acer model There are actually two variants of ALC268 Acer implementation, one with an analog built-in mic (pin 0x19) and another with a digital mic (pin 0x12). Created a new model, acer-dmic, for the latter case now. So far, all known models are assigned to be analog-mic, according to the BIOS setup. If this doesn't match with the actual case, one needs to try model=acer-dmic, and fix the entry to point ALC268_ACER_DMIC if it works. Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index f6594549bf5d..3ab5fb1357a2 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -844,6 +844,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 3stack 3-stack model toshiba Toshiba A205 acer Acer laptops + acer-dmic Acer laptops with digital-mic acer-aspire Acer Aspire One dell Dell OEM laptops (Vostro 1200) zepto Zepto laptops diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 15779d8c7564..425b0fc86f7d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -114,6 +114,7 @@ enum { ALC268_3ST, ALC268_TOSHIBA, ALC268_ACER, + ALC268_ACER_DMIC, ALC268_ACER_ASPIRE_ONE, ALC268_DELL, ALC268_ZEPTO, @@ -10714,6 +10715,22 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { { } }; +static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), + { } +}; + static struct hda_verb alc268_acer_aspire_one_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, @@ -11039,6 +11056,15 @@ static struct hda_input_mux alc268_capture_source = { }; static struct hda_input_mux alc268_acer_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Internal Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static struct hda_input_mux alc268_acer_dmic_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, @@ -11322,6 +11348,7 @@ static const char *alc268_models[ALC268_MODEL_LAST] = { [ALC268_3ST] = "3stack", [ALC268_TOSHIBA] = "toshiba", [ALC268_ACER] = "acer", + [ALC268_ACER_DMIC] = "acer-dmic", [ALC268_ACER_ASPIRE_ONE] = "acer-aspire", [ALC268_DELL] = "dell", [ALC268_ZEPTO] = "zepto", @@ -11417,6 +11444,23 @@ static struct alc_config_preset alc268_presets[] = { .unsol_event = alc268_acer_unsol_event, .init_hook = alc268_acer_init_hook, }, + [ALC268_ACER_DMIC] = { + .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer, + alc268_beep_mixer }, + .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, + alc268_acer_verbs }, + .num_dacs = ARRAY_SIZE(alc268_dac_nids), + .dac_nids = alc268_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), + .adc_nids = alc268_adc_nids_alt, + .capsrc_nids = alc268_capsrc_nids, + .hp_nid = 0x02, + .num_channel_mode = ARRAY_SIZE(alc268_modes), + .channel_mode = alc268_modes, + .input_mux = &alc268_acer_dmic_capture_source, + .unsol_event = alc268_acer_unsol_event, + .init_hook = alc268_acer_init_hook, + }, [ALC268_ACER_ASPIRE_ONE] = { .mixers = { alc268_acer_aspire_one_mixer, alc268_capture_alt_mixer }, From 6834d7ce224a6f6a1dd05da3a867730c40943154 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 5 Nov 2008 17:41:23 +0100 Subject: [PATCH 063/367] ALSA: ice1724 - Re-fix IRQ mask initialization The previous IRQ mask initialization was wrong. It must set the bits to be masked. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 40725dfdc864..0dfa0540ce2c 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -395,8 +395,8 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) "status = 0x%x\n", status); if (status & VT1724_IRQ_MPU_TX) { printk(KERN_ERR "ice1724: Disabling MPU_TX\n"); - outb(inb(ICEREG1724(ice, IRQMASK)) & - ~VT1724_IRQ_MPU_TX, + outb(inb(ICEREG1724(ice, IRQMASK)) | + VT1724_IRQ_MPU_TX, ICEREG1724(ice, IRQMASK)); } break; @@ -2413,8 +2413,8 @@ static int __devinit snd_vt1724_create(struct snd_card *card, return -EIO; } - /* clear interrupts -- otherwise you'll get irq problems later */ - outb(0, ICEREG1724(ice, IRQMASK)); + /* MPU_RX and TX irq masks are cleared later dynamically */ + outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK)); /* don't handle FIFO overrun/underruns (just yet), * since they cause machine lockups From 74e722015fe47c8f0e7ef7c0b4cf32d3e4ae11a0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 3 Nov 2008 12:02:12 +0000 Subject: [PATCH 064/367] ASoC: Add Palm/PXA27x unified ASoC audio driver this patch adds asoc audio driver for pxa27x based Palm PDAs. I tested it for palmtx, t5 and ld, it should work with palmz72 as well (slapin, please test). I sent it here some time ago, but now I got to fixing bugs in it. It should be somehow mostly ok and ready for applying. [Converted to use snd_soc_dapm_nc_pin() and bool Kconfig -- broonie] Signed-off-by: Marek Vasut Signed-off-by: Mark Brown --- arch/arm/mach-pxa/include/mach/palmasoc.h | 13 ++ sound/soc/pxa/Kconfig | 9 + sound/soc/pxa/Makefile | 2 + sound/soc/pxa/palm27x.c | 269 ++++++++++++++++++++++ 4 files changed, 293 insertions(+) create mode 100644 arch/arm/mach-pxa/include/mach/palmasoc.h create mode 100644 sound/soc/pxa/palm27x.c diff --git a/arch/arm/mach-pxa/include/mach/palmasoc.h b/arch/arm/mach-pxa/include/mach/palmasoc.h new file mode 100644 index 000000000000..6c4b1f7de20a --- /dev/null +++ b/arch/arm/mach-pxa/include/mach/palmasoc.h @@ -0,0 +1,13 @@ +#ifndef _INCLUDE_PALMASOC_H_ +#define _INCLUDE_PALMASOC_H_ +struct palm27x_asoc_info { + int jack_gpio; +}; + +#ifdef CONFIG_SND_PXA2XX_SOC_PALM27X +void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data); +#else +static inline void palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) {} +#endif + +#endif diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index 4235524238f9..f82e10699471 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig @@ -79,6 +79,15 @@ config SND_PXA2XX_SOC_EM_X270 Say Y if you want to add support for SoC audio on CompuLab EM-x270. +config SND_PXA2XX_SOC_PALM27X + bool "SoC Audio support for Palm T|X, T5 and LifeDrive" + depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || MACH_PALMT5) + select SND_PXA2XX_SOC_AC97 + select SND_SOC_WM9712 + help + Say Y if you want to add support for SoC audio on + Palm T|X, T5 or LifeDrive handheld computer. + config SND_SOC_ZYLONITE tristate "SoC Audio support for Marvell Zylonite" depends on SND_PXA2XX_SOC && MACH_ZYLONITE diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 00258abb84a8..1a3a36e75bf0 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -16,6 +16,7 @@ snd-soc-tosa-objs := tosa.o snd-soc-e800-objs := e800_wm9712.o snd-soc-spitz-objs := spitz.o snd-soc-em-x270-objs := em-x270.o +snd-soc-palm27x-objs := palm27x.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -23,3 +24,4 @@ obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o +obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c new file mode 100644 index 000000000000..e364abc700db --- /dev/null +++ b/sound/soc/pxa/palm27x.c @@ -0,0 +1,269 @@ +/* + * linux/sound/soc/pxa/palm27x.c + * + * SoC Audio driver for Palm T|X, T5 and LifeDrive + * + * based on tosa.c + * + * Copyright (C) 2008 Marek Vasut + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "../codecs/wm9712.h" +#include "pxa2xx-pcm.h" +#include "pxa2xx-ac97.h" + +static int palm27x_jack_func = 1; +static int palm27x_spk_func = 1; +static int palm27x_ep_gpio = -1; + +static void palm27x_ext_control(struct snd_soc_codec *codec) +{ + if (!palm27x_spk_func) + snd_soc_dapm_enable_pin(codec, "Speaker"); + else + snd_soc_dapm_disable_pin(codec, "Speaker"); + + if (!palm27x_jack_func) + snd_soc_dapm_enable_pin(codec, "Headphone Jack"); + else + snd_soc_dapm_disable_pin(codec, "Headphone Jack"); + + snd_soc_dapm_sync(codec); +} + +static int palm27x_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->socdev->codec; + + /* check the jack status at stream startup */ + palm27x_ext_control(codec); + return 0; +} + +static struct snd_soc_ops palm27x_ops = { + .startup = palm27x_startup, +}; + +static irqreturn_t palm27x_interrupt(int irq, void *v) +{ + palm27x_spk_func = gpio_get_value(palm27x_ep_gpio); + palm27x_jack_func = !palm27x_spk_func; + return IRQ_HANDLED; +} + +static int palm27x_get_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = palm27x_jack_func; + return 0; +} + +static int palm27x_set_jack(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (palm27x_jack_func == ucontrol->value.integer.value[0]) + return 0; + + palm27x_jack_func = ucontrol->value.integer.value[0]; + palm27x_ext_control(codec); + return 1; +} + +static int palm27x_get_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = palm27x_spk_func; + return 0; +} + +static int palm27x_set_spk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + + if (palm27x_spk_func == ucontrol->value.integer.value[0]) + return 0; + + palm27x_spk_func = ucontrol->value.integer.value[0]; + palm27x_ext_control(codec); + return 1; +} + +/* PalmTX machine dapm widgets */ +static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +/* PalmTX audio map */ +static const struct snd_soc_dapm_route audio_map[] = { + /* headphone connected to HPOUTL, HPOUTR */ + {"Headphone Jack", NULL, "HPOUTL"}, + {"Headphone Jack", NULL, "HPOUTR"}, + + /* ext speaker connected to ROUT2, LOUT2 */ + {"Speaker", NULL, "LOUT2"}, + {"Speaker", NULL, "ROUT2"}, +}; + +static const char *jack_function[] = {"Headphone", "Off"}; +static const char *spk_function[] = {"On", "Off"}; +static const struct soc_enum palm27x_enum[] = { + SOC_ENUM_SINGLE_EXT(2, jack_function), + SOC_ENUM_SINGLE_EXT(2, spk_function), +}; + +static const struct snd_kcontrol_new palm27x_controls[] = { + SOC_ENUM_EXT("Jack Function", palm27x_enum[0], palm27x_get_jack, + palm27x_set_jack), + SOC_ENUM_EXT("Speaker Function", palm27x_enum[1], palm27x_get_spk, + palm27x_set_spk), +}; + +static int palm27x_ac97_init(struct snd_soc_codec *codec) +{ + int i, err; + + snd_soc_dapm_nc_pin(codec, "OUT3"); + snd_soc_dapm_nc_pin(codec, "MONOOUT"); + + /* add palm27x specific controls */ + for (i = 0; i < ARRAY_SIZE(palm27x_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&palm27x_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + /* add palm27x specific widgets */ + snd_soc_dapm_new_controls(codec, palm27x_dapm_widgets, + ARRAY_SIZE(palm27x_dapm_widgets)); + + /* set up palm27x specific audio path audio_map */ + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_sync(codec); + return 0; +} + +static struct snd_soc_dai_link palm27x_dai[] = { +{ + .name = "AC97 HiFi", + .stream_name = "AC97 HiFi", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], + .init = palm27x_ac97_init, + .ops = &palm27x_ops, +}, +{ + .name = "AC97 Aux", + .stream_name = "AC97 Aux", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], + .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], + .ops = &palm27x_ops, +}, +}; + +static struct snd_soc_machine palm27x_asoc = { + .name = "Palm/PXA27x", + .dai_link = palm27x_dai, + .num_links = ARRAY_SIZE(palm27x_dai), +}; + +static struct snd_soc_device palm27x_snd_devdata = { + .machine = &palm27x_asoc, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm9712, +}; + +static struct platform_device *palm27x_snd_device; + +static int __init palm27x_asoc_init(void) +{ + int ret; + + if (!(machine_is_palmtx() || machine_is_palmt5() || + machine_is_palmld())) + return -ENODEV; + + ret = gpio_request(palm27x_ep_gpio, "Headphone Jack"); + if (ret) + return ret; + ret = gpio_direction_input(palm27x_ep_gpio); + if (ret) + goto err_alloc; + + if (request_irq(gpio_to_irq(palm27x_ep_gpio), palm27x_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "Headphone jack", NULL)) + goto err_alloc; + + palm27x_snd_device = platform_device_alloc("soc-audio", -1); + if (!palm27x_snd_device) { + ret = -ENOMEM; + goto err_dev; + } + + platform_set_drvdata(palm27x_snd_device, &palm27x_snd_devdata); + palm27x_snd_devdata.dev = &palm27x_snd_device->dev; + ret = platform_device_add(palm27x_snd_device); + + if (ret != 0) + goto put_device; + + return 0; + +put_device: + platform_device_put(palm27x_snd_device); +err_dev: + free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); +err_alloc: + gpio_free(palm27x_ep_gpio); + + return ret; +} + +static void __exit palm27x_asoc_exit(void) +{ + free_irq(gpio_to_irq(palm27x_ep_gpio), NULL); + gpio_free(palm27x_ep_gpio); + platform_device_unregister(palm27x_snd_device); +} + +void __init palm27x_asoc_set_pdata(struct palm27x_asoc_info *data) +{ + palm27x_ep_gpio = data->jack_gpio; +} + +module_init(palm27x_asoc_init); +module_exit(palm27x_asoc_exit); + +/* Module information */ +MODULE_AUTHOR("Marek Vasut "); +MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); +MODULE_LICENSE("GPL"); From ea913940c39a61214c799cc7093d7b20fe11a94c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 5 Nov 2008 11:13:21 +0000 Subject: [PATCH 065/367] ASoC: Remove core version number Rather than try to remember to keep the core version number updated (which hasn't been happening) just remove it. It was much more useful when ASoC was out of tree. Signed-off-by: Mark brown --- include/sound/soc.h | 2 -- sound/soc/soc-core.c | 1 - 2 files changed, 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index da0040b69c2d..fa1b99b45893 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -21,8 +21,6 @@ #include #include -#define SND_SOC_VERSION "0.13.2" - /* * Convenience kcontrol builders */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1a173682965a..9feaa7b6dc34 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1965,7 +1965,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); static int __devinit snd_soc_init(void) { - printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION); return platform_driver_register(&soc_driver); } From 8dc840f88d9c9f75f46d5dbe489242f8a114fab6 Mon Sep 17 00:00:00 2001 From: David Anders Date: Wed, 5 Nov 2008 07:39:47 -0800 Subject: [PATCH 066/367] ASoC: Add new parameter to s3c24xx_pcm_enqueue The S3C24xx dma does not allow more than one buffer to be enqueue prior to the dma transfers starting. This patch adds an additional parameter to s3c24xx_pcm_enqueue() to allow for passing an initial dma maximum load value. Signed-off-by: David Anders Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx-pcm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index e13e614bada9..341198bb0c17 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -78,7 +78,8 @@ struct s3c24xx_runtime_data { * place a dma buffer onto the queue for the dma system * to handle. */ -static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) +static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream, + int dma_max) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; @@ -86,7 +87,10 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) DBG("Entered %s\n", __func__); - while (prtd->dma_loaded < prtd->dma_limit) { + if (!dma_max) + dma_max = prtd->dma_limit; + + while (prtd->dma_loaded < dma_max) { unsigned long len = prtd->dma_period; DBG("dma_loaded: %d\n", prtd->dma_loaded); @@ -132,7 +136,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING) { prtd->dma_loaded--; - s3c24xx_pcm_enqueue(substream); + s3c24xx_pcm_enqueue(substream, 0); } spin_unlock(&prtd->lock); @@ -249,7 +253,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ - s3c24xx_pcm_enqueue(substream); + s3c24xx_pcm_enqueue(substream, 1); return ret; } From e18c94d20224f3df584531a48d944d8cccfda46d Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Wed, 5 Nov 2008 23:51:05 +0200 Subject: [PATCH 067/367] ALSA: ASoC: TWL4030 codec - fix 256*Fs clock According to TRM, 256*Fs clock output should be enabled when TWL4030 is in slave mode, not master. This allows sound to work on OMAP3 Pandora, which uses 256*Fs clock. Signed-off-by: Grazvydas Ignotas Acked-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ee2f0d37765c..90f3b4decbab 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -469,11 +469,11 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: format &= ~(TWL4030_AIF_SLAVE_EN); - format |= TWL4030_CLK256FS_EN; + format &= ~(TWL4030_CLK256FS_EN); break; case SND_SOC_DAIFMT_CBS_CFS: - format &= ~(TWL4030_CLK256FS_EN); format |= TWL4030_AIF_SLAVE_EN; + format |= TWL4030_CLK256FS_EN; break; default: return -EINVAL; From 33fa35ed0d7e8996cc68cc2ffc21f12b38fa03c1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Nov 2008 16:50:40 +0100 Subject: [PATCH 068/367] ALSA: hda - simplify hda_bus ops callbacks The hda_bus ops callback take struct hda_bus pointer. Also, the command callback takes the composed command word, instead of each small bits in arguments. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 62 +++++++++++++++++++++++++++++---------- sound/pci/hda/hda_codec.h | 10 +++---- sound/pci/hda/hda_intel.c | 59 ++++++++++++++++--------------------- 3 files changed, 78 insertions(+), 53 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 45695d608c76..810465bac550 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -157,6 +157,23 @@ const char *snd_hda_get_jack_type(u32 cfg) >> AC_DEFCFG_DEVICE_SHIFT]; } +/* + * Compose a 32bit command word to be sent to the HD-audio controller + */ +static inline unsigned int +make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, + unsigned int verb, unsigned int parm) +{ + u32 val; + + val = (u32)(codec->addr & 0x0f) << 28; + val |= (u32)direct << 27; + val |= (u32)nid << 20; + val |= verb << 8; + val |= parm; + return val; +} + /** * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec @@ -173,14 +190,17 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { + struct hda_bus *bus = codec->bus; unsigned int res; + + res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&codec->bus->cmd_mutex); - if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) - res = codec->bus->ops.get_response(codec); + mutex_lock(&bus->cmd_mutex); + if (!bus->ops.command(bus, res)) + res = bus->ops.get_response(bus); else res = (unsigned int)-1; - mutex_unlock(&codec->bus->cmd_mutex); + mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); return res; } @@ -200,11 +220,15 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { + struct hda_bus *bus = codec->bus; + unsigned int res; int err; + + res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&codec->bus->cmd_mutex); - err = codec->bus->ops.command(codec, nid, direct, verb, parm); - mutex_unlock(&codec->bus->cmd_mutex); + mutex_lock(&bus->cmd_mutex); + err = bus->ops.command(bus, res); + mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); return err; } @@ -1886,10 +1910,14 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm) { + struct hda_bus *bus = codec->bus; + unsigned int res; int err; + + res = make_codec_cmd(codec, nid, direct, verb, parm); snd_hda_power_up(codec); - mutex_lock(&codec->bus->cmd_mutex); - err = codec->bus->ops.command(codec, nid, direct, verb, parm); + mutex_lock(&bus->cmd_mutex); + err = bus->ops.command(bus, res); if (!err) { struct hda_cache_head *c; u32 key = build_cmd_cache_key(nid, verb); @@ -1897,7 +1925,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, if (c) c->val = parm; } - mutex_unlock(&codec->bus->cmd_mutex); + mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); return err; } @@ -2414,6 +2442,7 @@ static int set_pcm_default_values(struct hda_codec *codec, static int __devinit snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) { + struct hda_bus *bus = codec->bus; struct hda_pcm_stream *info; int stream, err; @@ -2427,7 +2456,7 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) return err; } } - return codec->bus->ops.attach_pcm(codec, pcm); + return bus->ops.attach_pcm(bus, codec, pcm); } /** @@ -2628,6 +2657,7 @@ static void hda_power_work(struct work_struct *work) { struct hda_codec *codec = container_of(work, struct hda_codec, power_work.work); + struct hda_bus *bus = codec->bus; if (!codec->power_on || codec->power_count) { codec->power_transition = 0; @@ -2635,8 +2665,8 @@ static void hda_power_work(struct work_struct *work) } hda_call_codec_suspend(codec); - if (codec->bus->ops.pm_notify) - codec->bus->ops.pm_notify(codec); + if (bus->ops.pm_notify) + bus->ops.pm_notify(bus); } static void hda_keep_power_on(struct hda_codec *codec) @@ -2647,13 +2677,15 @@ static void hda_keep_power_on(struct hda_codec *codec) void snd_hda_power_up(struct hda_codec *codec) { + struct hda_bus *bus = codec->bus; + codec->power_count++; if (codec->power_on || codec->power_transition) return; codec->power_on = 1; - if (codec->bus->ops.pm_notify) - codec->bus->ops.pm_notify(codec); + if (bus->ops.pm_notify) + bus->ops.pm_notify(bus); hda_call_codec_resume(codec); cancel_delayed_work(&codec->power_work); codec->power_transition = 0; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index c5f91c918d19..a73f0eb99283 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -556,17 +556,17 @@ typedef u16 hda_nid_t; /* bus operators */ struct hda_bus_ops { /* send a single command */ - int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm); + int (*command)(struct hda_bus *bus, unsigned int cmd); /* get a response from the last command */ - unsigned int (*get_response)(struct hda_codec *codec); + unsigned int (*get_response)(struct hda_bus *bus); /* free the private data */ void (*private_free)(struct hda_bus *); /* attach a PCM stream */ - int (*attach_pcm)(struct hda_codec *codec, struct hda_pcm *pcm); + int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, + struct hda_pcm *pcm); #ifdef CONFIG_SND_HDA_POWER_SAVE /* notify power-up/down from codec to controller */ - void (*pm_notify)(struct hda_codec *codec); + void (*pm_notify)(struct hda_bus *bus); #endif }; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 614be2ec806f..bf8e6f94aebc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -527,9 +527,9 @@ static void azx_free_cmd_io(struct azx *chip) } /* send a command */ -static int azx_corb_send_cmd(struct hda_codec *codec, u32 val) +static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; unsigned int wp; /* add command to corb */ @@ -577,9 +577,9 @@ static void azx_update_rirb(struct azx *chip) } /* receive a response */ -static unsigned int azx_rirb_get_response(struct hda_codec *codec) +static unsigned int azx_rirb_get_response(struct hda_bus *bus) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; unsigned long timeout; again: @@ -596,7 +596,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) } if (time_after(jiffies, timeout)) break; - if (codec->bus->needs_damn_long_delay) + if (bus->needs_damn_long_delay) msleep(2); /* temporary workaround */ else { udelay(10); @@ -646,9 +646,9 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) */ /* send a command */ -static int azx_single_send_cmd(struct hda_codec *codec, u32 val) +static int azx_single_send_cmd(struct hda_bus *bus, u32 val) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; int timeout = 50; while (timeout--) { @@ -671,9 +671,9 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val) } /* receive a response */ -static unsigned int azx_single_get_response(struct hda_codec *codec) +static unsigned int azx_single_get_response(struct hda_bus *bus) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; int timeout = 50; while (timeout--) { @@ -696,38 +696,29 @@ static unsigned int azx_single_get_response(struct hda_codec *codec) */ /* send a command */ -static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, - unsigned int para) +static int azx_send_cmd(struct hda_bus *bus, unsigned int val) { - struct azx *chip = codec->bus->private_data; - u32 val; + struct azx *chip = bus->private_data; - val = (u32)(codec->addr & 0x0f) << 28; - val |= (u32)direct << 27; - val |= (u32)nid << 20; - val |= verb << 8; - val |= para; chip->last_cmd = val; - if (chip->single_cmd) - return azx_single_send_cmd(codec, val); + return azx_single_send_cmd(bus, val); else - return azx_corb_send_cmd(codec, val); + return azx_corb_send_cmd(bus, val); } /* get a response */ -static unsigned int azx_get_response(struct hda_codec *codec) +static unsigned int azx_get_response(struct hda_bus *bus) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; if (chip->single_cmd) - return azx_single_get_response(codec); + return azx_single_get_response(bus); else - return azx_rirb_get_response(codec); + return azx_rirb_get_response(bus); } #ifdef CONFIG_SND_HDA_POWER_SAVE -static void azx_power_notify(struct hda_codec *codec); +static void azx_power_notify(struct hda_bus *bus); #endif /* reset codec link */ @@ -1184,7 +1175,8 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) return 0; } -static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm); +static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, + struct hda_pcm *cpcm); /* * Codec initialization @@ -1707,9 +1699,10 @@ static void azx_pcm_free(struct snd_pcm *pcm) } static int -azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm) +azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, + struct hda_pcm *cpcm) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; struct snd_pcm *pcm; struct azx_pcm *apcm; int pcm_dev = cpcm->device; @@ -1827,13 +1820,13 @@ static void azx_stop_chip(struct azx *chip) #ifdef CONFIG_SND_HDA_POWER_SAVE /* power-up/down the controller */ -static void azx_power_notify(struct hda_codec *codec) +static void azx_power_notify(struct hda_bus *bus) { - struct azx *chip = codec->bus->private_data; + struct azx *chip = bus->private_data; struct hda_codec *c; int power_on = 0; - list_for_each_entry(c, &codec->bus->codec_list, list) { + list_for_each_entry(c, &bus->codec_list, list) { if (c->power_on) { power_on = 1; break; From 6ce4a3bc1b93e8ca50b142b00dd73bfdb5c4a172 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 6 Nov 2008 17:11:10 +0100 Subject: [PATCH 069/367] ALSA: hda - Make codec-probing more robust When an error occurs during the codec probing, typically accessing to an non-existing codec slot, the controller chip gets often screwed up and can no longer communicate with the codecs. This patch adds a preparation phase just to probe codec addresses before actually creating codec instances. If any error occurs during this probing phase, the driver resets the controller to recover. This will (hopefully) fix the famous "single_cmd" errors. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index bf8e6f94aebc..f3c447cf67f8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -392,6 +392,7 @@ struct azx { unsigned int msi :1; unsigned int irq_pending_warned :1; unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */ + unsigned int probing :1; /* codec probing phase */ /* for debugging */ unsigned int last_cmd; /* last issued command (to sync) */ @@ -624,6 +625,14 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) goto again; } + if (chip->probing) { + /* If this critical timeout happens during the codec probing + * phase, this is likely an access to a non-existing codec + * slot. Better to return an error and reset the system. + */ + return -1; + } + snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " "switching to single_cmd mode: last cmd=0x%08x\n", chip->last_cmd); @@ -1175,8 +1184,28 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) return 0; } +/* + * Probe the given codec address + */ +static int probe_codec(struct azx *chip, int addr) +{ + unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + unsigned int res; + + chip->probing = 1; + azx_send_cmd(chip->bus, cmd); + res = azx_get_response(chip->bus); + chip->probing = 0; + if (res == -1) + return -EIO; + snd_printdd("hda_intel: codec #%d probed OK\n", addr); + return 0; +} + static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, struct hda_pcm *cpcm); +static void azx_stop_chip(struct azx *chip); /* * Codec initialization @@ -1216,6 +1245,32 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, max_slots = azx_max_codecs[chip->driver_type]; if (!max_slots) max_slots = AZX_MAX_CODECS; + + /* First try to probe all given codec slots */ + for (c = 0; c < max_slots; c++) { + if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { + if (probe_codec(chip, c) < 0) { + /* Some BIOSen give you wrong codec addresses + * that don't exist + */ + snd_printk(KERN_WARNING + "hda_intel: Codec #%d probe error; " + "disabling it...\n", c); + chip->codec_mask &= ~(1 << c); + /* More badly, accessing to a non-existing + * codec often screws up the controller chip, + * and distrubs the further communications. + * Thus if an error occurs during probing, + * better to reset the controller chip to + * get back to the sanity state. + */ + azx_stop_chip(chip); + azx_init_chip(chip); + } + } + } + + /* Then create codec instances */ for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { struct hda_codec *codec; From 64154835c58a99370c3b7fbf85d2451d6906b3b4 Mon Sep 17 00:00:00 2001 From: Tony Vroon Date: Thu, 6 Nov 2008 15:08:49 +0000 Subject: [PATCH 070/367] ALSA: hda - Add lifebook model for Realtek ALC269 The widget layout of the Fujitsu Lifebook S6420 (which is ICH9M-based and uses an ALC269) is similar but not identical to the Lifebook S6410/E8410 (which are ICH8M-based and use an ALC262). It is named lifebook as fujitsu is in use for Amilo machines. This builds on the Quanta FL1 work and supports all analog inputs & outputs that I am aware of. Microphone autoswitch is implemented. The laptop mic port takes precedence over the dock mic port if both happen to have a jack plugged in. This made sense to me as a design decision (imagine a presentation environment with the dock fully wired in and the presenter quickly wanting to override the mic with a headset). There is mention of a digital audio path on the codec graph, so perhaps the headphone socket is dual-function analog/digital. I will follow up with another patch if I can acquire equipment to test this. Signed-off-by: Tony Vroon Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 125 +++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 425b0fc86f7d..98a02fd1097e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -132,6 +132,7 @@ enum { ALC269_ASUS_EEEPC_P703, ALC269_ASUS_EEEPC_P901, ALC269_FUJITSU, + ALC269_LIFEBOOK, ALC269_AUTO, ALC269_MODEL_LAST /* last tag */ }; @@ -11701,6 +11702,31 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { { } }; +static struct snd_kcontrol_new alc269_lifebook_mixer[] = { + /* output mixer control */ + HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = alc268_acer_master_sw_put, + .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + }, + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Dock Mic Boost", 0x1b, 0, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x04, HDA_INPUT), + { } +}; + /* bind volumes of both NID 0x0c and 0x0d */ static struct hda_bind_ctls alc269_epc_bind_vol = { .ops = &snd_hda_bind_vol, @@ -11751,6 +11777,20 @@ static struct hda_verb alc269_quanta_fl1_verbs[] = { { } }; +static struct hda_verb alc269_lifebook_verbs[] = { + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + { } +}; + /* toggle speaker-output according to the hp-jack state */ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) { @@ -11776,6 +11816,37 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) AC_VERB_SET_PROC_COEF, 0x480); } +/* toggle speaker-output according to the hp-jacks state */ +static void alc269_lifebook_speaker_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned char bits; + + /* Check laptop headphone socket */ + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + /* Check port replicator headphone socket */ + present |= snd_hda_codec_read(codec, 0x1a, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + bits = present ? AMP_IN_MUTE(0) : 0; + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, + AMP_IN_MUTE(0), bits); + snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1, + AMP_IN_MUTE(0), bits); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x680); + + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_COEF_INDEX, 0x0c); + snd_hda_codec_write(codec, 0x20, 0, + AC_VERB_SET_PROC_COEF, 0x480); +} + static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) { unsigned int present; @@ -11786,6 +11857,29 @@ static void alc269_quanta_fl1_mic_automute(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x1); } +static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) +{ + unsigned int present_laptop; + unsigned int present_dock; + + present_laptop = snd_hda_codec_read(codec, 0x18, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + present_dock = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + /* Laptop mic port overrides dock mic port, design decision */ + if (present_dock) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x3); + if (present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x0); + if (!present_dock && !present_laptop) + snd_hda_codec_write(codec, 0x23, 0, + AC_VERB_SET_CONNECT_SEL, 0x1); +} + static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -11795,12 +11889,27 @@ static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec, alc269_quanta_fl1_mic_automute(codec); } +static void alc269_lifebook_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if ((res >> 26) == ALC880_HP_EVENT) + alc269_lifebook_speaker_automute(codec); + if ((res >> 26) == ALC880_MIC_EVENT) + alc269_lifebook_mic_autoswitch(codec); +} + static void alc269_quanta_fl1_init_hook(struct hda_codec *codec) { alc269_quanta_fl1_speaker_automute(codec); alc269_quanta_fl1_mic_automute(codec); } +static void alc269_lifebook_init_hook(struct hda_codec *codec) +{ + alc269_lifebook_speaker_automute(codec); + alc269_lifebook_mic_autoswitch(codec); +} + static struct hda_verb alc269_eeepc_dmic_init_verbs[] = { {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, {0x23, AC_VERB_SET_CONNECT_SEL, 0x05}, @@ -12154,7 +12263,8 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { [ALC269_QUANTA_FL1] = "quanta", [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", [ALC269_ASUS_EEEPC_P901] = "eeepc-p901", - [ALC269_FUJITSU] = "fujitsu" + [ALC269_FUJITSU] = "fujitsu", + [ALC269_LIFEBOOK] = "lifebook" }; static struct snd_pci_quirk alc269_cfg_tbl[] = { @@ -12166,6 +12276,7 @@ static struct snd_pci_quirk alc269_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", ALC269_ASUS_EEEPC_P901), SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), + SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), {} }; @@ -12234,6 +12345,18 @@ static struct alc_config_preset alc269_presets[] = { .unsol_event = alc269_eeepc_dmic_unsol_event, .init_hook = alc269_eeepc_dmic_inithook, }, + [ALC269_LIFEBOOK] = { + .mixers = { alc269_lifebook_mixer }, + .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs }, + .num_dacs = ARRAY_SIZE(alc269_dac_nids), + .dac_nids = alc269_dac_nids, + .hp_nid = 0x03, + .num_channel_mode = ARRAY_SIZE(alc269_modes), + .channel_mode = alc269_modes, + .input_mux = &alc269_capture_source, + .unsol_event = alc269_lifebook_unsol_event, + .init_hook = alc269_lifebook_init_hook, + }, }; static int patch_alc269(struct hda_codec *codec) From c217429b14708999d6ac5de964c452600e8797d3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 00:23:30 +0100 Subject: [PATCH 071/367] ALSA: hda - Add missing NULL check in amp hash allocation Added the missing NULL check from allocator in get_alloc_hash(). Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 810465bac550..f13834ba6b1d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -899,6 +899,8 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, /* add a new hash entry */ info = snd_array_new(&cache->buf); + if (!info) + return NULL; info->key = key; info->val = 0; info->next = cache->hash[idx]; From b910d9ae5b370cf5bf9d6a71028119861b6ea8a4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 00:26:52 +0100 Subject: [PATCH 072/367] ALSA: hda - Add max allocation check in array allocator Added a check for max allocation size in snd_array_new() for a debugging purpose. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f13834ba6b1d..6f170b281e85 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3399,7 +3399,10 @@ void *snd_array_new(struct snd_array *array) { if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; - void *nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); + void *nlist; + if (snd_BUG_ON(num >= 4096)) + return NULL; + nlist = kcalloc(num + 1, array->elem_size, GFP_KERNEL); if (!nlist) return NULL; if (array->list) { From ea2da6e898033b9736a26cf588b9ce841a433337 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 00:49:48 +0100 Subject: [PATCH 073/367] ALSA: hda - Fix broken hash chain allocation The chaining for amp hash got broken due to the rewrite with snd_array. Fixed now. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6f170b281e85..06e99c785155 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -901,6 +901,7 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, info = snd_array_new(&cache->buf); if (!info) return NULL; + cur = cache->buf.used - 1; /* the last entry */ info->key = key; info->val = 0; info->next = cache->hash[idx]; From 945eed02cd619f525e097319cd3d18c58d01da87 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 09:08:15 +0100 Subject: [PATCH 074/367] ALSA: Evaluate condition in snd_BUG_ON() in non-debugging case Change snd_BUG_ON() to evaluate the given condition, at least, in syntax for avoiding compile warnings such as unused variables. The compiler should optimize out the condition evaluation in the real code, though. Signed-off-by: Takashi Iwai --- include/sound/core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index 7e5589472681..6fa4c7b1970a 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -390,11 +390,11 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) #define snd_printd(fmt, args...) do { } while (0) #define snd_BUG() do { } while (0) -static inline int __snd_bug_on(void) +static inline int __snd_bug_on(int cond) { return 0; } -#define snd_BUG_ON(cond) __snd_bug_on() /* always false */ +#define snd_BUG_ON(cond) __snd_bug_on(0 && (cond)) /* always false */ #endif /* CONFIG_SND_DEBUG */ From f66fcedc84dd06d42a0dba3894d238498509e8b7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 09:37:22 +0100 Subject: [PATCH 075/367] ALSA: Document debug macros Add descriptions of snd_BUG() and snd_BUG_ON(). Also fixed a typo in the comment of snd_printk(), too. Signed-off-by: Takashi Iwai --- include/sound/core.h | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/include/sound/core.h b/include/sound/core.h index 6fa4c7b1970a..b2f3bbe9e56d 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -356,7 +356,7 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) * snd_printk - printk wrapper * @fmt: format string * - * Works like print() but prints the file and the line of the caller + * Works like printk() but prints the file and the line of the caller * when configured with CONFIG_SND_VERBOSE_PRINTK. */ #define snd_printk(fmt, args...) \ @@ -383,7 +383,29 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) printk(fmt ,##args) #endif +/** + * snd_BUG - give a BUG warning message and stack trace + * + * Calls WARN() if CONFIG_SND_DEBUG is set. + * Ignored when CONFIG_SND_DEBUG is not set. + */ #define snd_BUG() WARN(1, "BUG?\n") + +/** + * snd_BUG_ON - debugging check macro + * @cond: condition to evaluate + * + * When CONFIG_SND_DEBUG is set, this macro evaluates the given condition, + * and call WARN() and returns the value if it's non-zero. + * + * When CONFIG_SND_DEBUG is not set, this just returns zero, and the given + * condition is ignored. + * + * NOTE: the argument won't be evaluated at all when CONFIG_SND_DEBUG=n. + * Thus, don't put any statement that influences on the code behavior, + * such as pre/post increment, to the argument of this macro. + * If you want to evaluate and give a warning, use standard WARN_ON(). + */ #define snd_BUG_ON(cond) WARN((cond), "BUG? (%s)\n", __stringify(cond)) #else /* !CONFIG_SND_DEBUG */ From 26df91c36fb976af9d08c20028b5cb1317eedcb3 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Wed, 5 Nov 2008 18:53:28 +0000 Subject: [PATCH 076/367] ASoC: TLV320AIC23B Support more sample rates Add support for more sample rates, different crystals and split playback/capture rates. Signed-off-by: Troy Kisky Acked-by: Arun KS Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 222 ++++++++++++++++++++++++++------- 1 file changed, 177 insertions(+), 45 deletions(-) diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 44308dac9e18..a95b538b8fe7 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -37,12 +37,6 @@ #define AIC23_VERSION "0.1" -struct tlv320aic23_srate_reg_info { - u32 sample_rate; - u8 control; /* SR3, SR2, SR1, SR0 and BOSR */ - u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */ -}; - /* * AIC23 register cache */ @@ -261,20 +255,151 @@ static const struct snd_soc_dapm_route intercon[] = { }; -/* tlv320aic23 related */ -static const struct tlv320aic23_srate_reg_info srate_reg_info[] = { - {4000, 0x06, 1}, /* 4000 */ - {8000, 0x06, 0}, /* 8000 */ - {16000, 0x0C, 1}, /* 16000 */ - {22050, 0x11, 1}, /* 22050 */ - {24000, 0x00, 1}, /* 24000 */ - {32000, 0x0C, 0}, /* 32000 */ - {44100, 0x11, 0}, /* 44100 */ - {48000, 0x00, 0}, /* 48000 */ - {88200, 0x1F, 0}, /* 88200 */ - {96000, 0x0E, 0}, /* 96000 */ +/* AIC23 driver data */ +struct aic23 { + struct snd_soc_codec codec; + int mclk; + int requested_adc; + int requested_dac; }; +/* + * Common Crystals used + * 11.2896 Mhz /128 = *88.2k /192 = 58.8k + * 12.0000 Mhz /125 = *96k /136 = 88.235K + * 12.2880 Mhz /128 = *96k /192 = 64k + * 16.9344 Mhz /128 = 132.3k /192 = *88.2k + * 18.4320 Mhz /128 = 144k /192 = *96k + */ + +/* + * Normal BOSR 0-256/2 = 128, 1-384/2 = 192 + * USB BOSR 0-250/2 = 125, 1-272/2 = 136 + */ +static const int bosr_usb_divisor_table[] = { + 128, 125, 192, 136 +}; +#define LOWER_GROUP ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<6) | (1<<7)) +#define UPPER_GROUP ((1<<8) | (1<<9) | (1<<10) | (1<<11) | (1<<15)) +static const unsigned short sr_valid_mask[] = { + LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 0*/ + LOWER_GROUP|UPPER_GROUP, /* Normal, bosr - 1*/ + LOWER_GROUP, /* Usb, bosr - 0*/ + UPPER_GROUP, /* Usb, bosr - 1*/ +}; +/* + * Every divisor is a factor of 11*12 + */ +#define SR_MULT (11*12) +#define A(x) (x) ? (SR_MULT/x) : 0 +static const unsigned char sr_adc_mult_table[] = { + A(2), A(2), A(12), A(12), A(0), A(0), A(3), A(1), + A(2), A(2), A(11), A(11), A(0), A(0), A(0), A(1) +}; +static const unsigned char sr_dac_mult_table[] = { + A(2), A(12), A(2), A(12), A(0), A(0), A(3), A(1), + A(2), A(11), A(2), A(11), A(0), A(0), A(0), A(1) +}; + +static unsigned get_score(int adc, int adc_l, int adc_h, int need_adc, + int dac, int dac_l, int dac_h, int need_dac) +{ + if ((adc >= adc_l) && (adc <= adc_h) && + (dac >= dac_l) && (dac <= dac_h)) { + int diff_adc = need_adc - adc; + int diff_dac = need_dac - dac; + return abs(diff_adc) + abs(diff_dac); + } + return UINT_MAX; +} + +static int find_rate(int mclk, u32 need_adc, u32 need_dac) +{ + int i, j; + int best_i = -1; + int best_j = -1; + int best_div = 0; + unsigned best_score = UINT_MAX; + int adc_l, adc_h, dac_l, dac_h; + + need_adc *= SR_MULT; + need_dac *= SR_MULT; + /* + * rates given are +/- 1/32 + */ + adc_l = need_adc - (need_adc >> 5); + adc_h = need_adc + (need_adc >> 5); + dac_l = need_dac - (need_dac >> 5); + dac_h = need_dac + (need_dac >> 5); + for (i = 0; i < 4; i++) { + int base = mclk / bosr_usb_divisor_table[i]; + int mask = sr_valid_mask[i]; + for (j = 0; j < 16; j++, mask >>= 1) { + int adc; + int dac; + int score; + if ((mask & 1) == 0) + continue; + adc = base * sr_adc_mult_table[j]; + dac = base * sr_dac_mult_table[j]; + score = get_score(adc, adc_l, adc_h, need_adc, + dac, dac_l, dac_h, need_dac); + if (best_score > score) { + best_score = score; + best_i = i; + best_j = j; + best_div = 0; + } + score = get_score((adc >> 1), adc_l, adc_h, need_adc, + (dac >> 1), dac_l, dac_h, need_dac); + /* prefer to have a /2 */ + if ((score != UINT_MAX) && (best_score >= score)) { + best_score = score; + best_i = i; + best_j = j; + best_div = 1; + } + } + } + return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT); +} + +static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, + u32 *sample_rate_adc, u32 *sample_rate_dac) +{ + int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE); + int sr = (src >> 2) & 0x0f; + int val = (mclk / bosr_usb_divisor_table[src & 3]); + int adc = (val * sr_adc_mult_table[sr]) / SR_MULT; + int dac = (val * sr_dac_mult_table[sr]) / SR_MULT; + if (src & TLV320AIC23_CLKIN_HALF) { + adc >>= 1; + dac >>= 1; + } + *sample_rate_adc = adc; + *sample_rate_dac = dac; +} + +static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, + u32 sample_rate_adc, u32 sample_rate_dac) +{ + /* Search for the right sample rate */ + int data = find_rate(mclk, sample_rate_adc, sample_rate_dac); + if (data < 0) { + printk(KERN_ERR "%s:Invalid rate %u,%u requested\n", + __func__, sample_rate_adc, sample_rate_dac); + return -EINVAL; + } + tlv320aic23_write(codec, TLV320AIC23_SRATE, data); + if (1) { + int adc, dac; + get_current_sample_rates(codec, mclk, &adc, &dac); + printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n", + adc, dac, data); + } + return 0; +} + static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) { snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, @@ -293,27 +418,30 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 iface_reg, data; - u8 count = 0; + u16 iface_reg; + int ret; + struct aic23 *aic23 = container_of(codec, struct aic23, codec); + u32 sample_rate_adc = aic23->requested_adc; + u32 sample_rate_dac = aic23->requested_dac; + u32 sample_rate = params_rate(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + aic23->requested_dac = sample_rate_dac = sample_rate; + if (!sample_rate_adc) + sample_rate_adc = sample_rate; + } else { + aic23->requested_adc = sample_rate_adc = sample_rate; + if (!sample_rate_dac) + sample_rate_dac = sample_rate; + } + ret = set_sample_rate_control(codec, aic23->mclk, sample_rate_adc, + sample_rate_dac); + if (ret < 0) + return ret; iface_reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2); - - /* Search for the right sample rate */ - /* Verify what happens if the rate is not supported - * now it goes to 96Khz */ - while ((srate_reg_info[count].sample_rate != params_rate(params)) && - (count < ARRAY_SIZE(srate_reg_info))) { - count++; - } - - data = (srate_reg_info[count].divider << TLV320AIC23_CLKIN_SHIFT) | - (srate_reg_info[count]. control << TLV320AIC23_BOSR_SHIFT) | - TLV320AIC23_USB_CLK_ON; - - tlv320aic23_write(codec, TLV320AIC23_SRATE, data); - switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: break; @@ -349,12 +477,17 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; + struct aic23 *aic23 = container_of(codec, struct aic23, codec); /* deactivate */ if (!codec->active) { udelay(50); tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); } + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + aic23->requested_dac = 0; + else + aic23->requested_adc = 0; } static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute) @@ -422,12 +555,9 @@ static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; - - switch (freq) { - case 12000000: - return 0; - } - return -EINVAL; + struct aic23 *aic23 = container_of(codec, struct aic23, codec); + aic23->mclk = freq; + return 0; } static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, @@ -659,14 +789,15 @@ static int tlv320aic23_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec; + struct aic23 *aic23; int ret = 0; printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) + aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL); + if (aic23 == NULL) return -ENOMEM; - + codec = &aic23->codec; socdev->codec = codec; mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); @@ -687,6 +818,7 @@ static int tlv320aic23_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; + struct aic23 *aic23 = container_of(codec, struct aic23, codec); if (codec->control_data) tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); @@ -697,7 +829,7 @@ static int tlv320aic23_remove(struct platform_device *pdev) i2c_del_driver(&tlv320aic23_i2c_driver); #endif kfree(codec->reg_cache); - kfree(codec); + kfree(aic23); return 0; } From 30cde0aacc5f6786b0c4d4fafaac95eac845b8d7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 14:49:28 +0100 Subject: [PATCH 077/367] ALSA: hda - Fix ALC260 hp3013 master switch The master switch doesn't influence on NID 0x15, the headphone jack on HP 3013 model because alc260_hp_master_update() ignores the passed arguments. Also, corrected the wrong arguments of hp3013 (0x10 and 0x15) although this doesn't change any behavior. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0f1fa1dac448..017abd01299d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4272,13 +4272,13 @@ static void alc260_hp_master_update(struct hda_codec *codec, struct alc_spec *spec = codec->spec; unsigned int val = spec->master_sw ? PIN_HP : 0; /* change HP and line-out pins */ - snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); - snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); /* mono (speaker) depending on the HP jack sense */ val = (val && !spec->jack_present) ? PIN_OUT : 0; - snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); } @@ -4357,7 +4357,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { .info = snd_ctl_boolean_mono_info, .get = alc260_hp_master_sw_get, .put = alc260_hp_master_sw_put, - .private_value = (0x10 << 16) | (0x15 << 8) | 0x11 + .private_value = (0x15 << 16) | (0x10 << 8) | 0x11 }, HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), @@ -4410,7 +4410,7 @@ static void alc260_hp_3013_automute(struct hda_codec *codec) present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; - alc260_hp_master_update(codec, 0x10, 0x15, 0x11); + alc260_hp_master_update(codec, 0x15, 0x10, 0x11); } static void alc260_hp_3013_unsol_event(struct hda_codec *codec, From 0edb94543092535a2c6ef33e7285004168ca73d7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Nov 2008 14:53:09 +0100 Subject: [PATCH 078/367] ALSA: hda - Fix probe errors on Dell Studio Desktop BIOS on Dell Studio Desktop tells wrong codec probe masks. This patch gives the preset mask value to avoid invalid access. Reference: Novell bug#440907 https://bugzilla.novell.com/show_bug.cgi?id=440907 Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f3c447cf67f8..3e112df1c0dc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2067,6 +2067,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { SND_PCI_QUIRK(0x1014, 0x05b7, "Thinkpad Z60", 0x01), SND_PCI_QUIRK(0x17aa, 0x2010, "Thinkpad X/T/R60", 0x01), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), + /* broken BIOS */ + SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), {} }; From 53599bbc30343f0cbfe750d2af19c9c45b841b82 Mon Sep 17 00:00:00 2001 From: Christian Pellegrin Date: Sat, 8 Nov 2008 08:44:16 +0100 Subject: [PATCH 079/367] ASoC: s3c24xx 8 bit sound fix fixes playing/recording of 8 bit audio files. Generated on 20081108 against v2.6.27 Signed-off-by: Christian Pellegrin Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx-i2s.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index ba4476b55fbc..c18977bceaf2 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -261,10 +261,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: + iismod &= ~S3C2410_IISMOD_16BIT; + ((struct s3c24xx_pcm_dma_params *) + rtd->dai->cpu_dai->dma_data)->dma_size = 1; break; case SNDRV_PCM_FORMAT_S16_LE: iismod |= S3C2410_IISMOD_16BIT; + ((struct s3c24xx_pcm_dma_params *) + rtd->dai->cpu_dai->dma_data)->dma_size = 2; break; + default: + return -EINVAL; } writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); From b402dff8739cd82c58b632ba472caf26ae8741ed Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Sat, 8 Nov 2008 13:26:09 -0500 Subject: [PATCH 080/367] ASoC: Add Right-Justified mode and Codec clock master to davinci-i2s The TI DVEVM board uses the SND_SOC_DAIFMT_CBM_CFM & I2S formats, but the Lyrtech SFFSDR board uses the SND_SOC_DAIFMT_CBM_CFS & RIGHT-JUSTIFIED formats. Signed-off-by: Hugo Villeneuve Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 40 +++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index abb5fedb0b1e..d814ec8947e5 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -59,6 +59,7 @@ #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) #define DAVINCI_MCBSP_PCR_FSRP (1 << 2) #define DAVINCI_MCBSP_PCR_FSXP (1 << 3) +#define DAVINCI_MCBSP_PCR_SCLKME (1 << 7) #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) @@ -171,6 +172,16 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, DAVINCI_MCBSP_SRGR_FSGM); break; + case SND_SOC_DAIFMT_CBM_CFS: + /* McBSP CLKR pin is the input for the Sample Rate Generator. + * McBSP FSR and FSX are driven by the Sample Rate Generator. */ + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, + DAVINCI_MCBSP_PCR_SCLKME | + DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, + DAVINCI_MCBSP_SRGR_FSGM); + break; case SND_SOC_DAIFMT_CBM_CFM: davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); break; @@ -205,6 +216,28 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, + DAVINCI_MCBSP_RCR_RFRLEN1(1) | + DAVINCI_MCBSP_RCR_RDATDLY(0)); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, + DAVINCI_MCBSP_XCR_XFRLEN1(1) | + DAVINCI_MCBSP_XCR_XDATDLY(0) | + DAVINCI_MCBSP_XCR_XFIG); + break; + case SND_SOC_DAIFMT_I2S: + default: + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, + DAVINCI_MCBSP_RCR_RFRLEN1(1) | + DAVINCI_MCBSP_RCR_RDATDLY(1)); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, + DAVINCI_MCBSP_XCR_XFRLEN1(1) | + DAVINCI_MCBSP_XCR_XDATDLY(1) | + DAVINCI_MCBSP_XCR_XFIG); + break; + } + return 0; } @@ -223,13 +256,6 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(1)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(1) | - DAVINCI_MCBSP_XCR_XFIG); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); From f43aa025b7de79d6a615ea4c1e6be7e6b1cea538 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Nov 2008 16:24:26 +0100 Subject: [PATCH 081/367] ALSA: hda - Fix another cache list management Fix another silly bug in the amp cache list management. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 7 +++---- sound/pci/hda/hda_codec.h | 10 ++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 06e99c785155..5d5e8012d6a5 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -887,11 +887,10 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, { u16 idx = key % (u16)ARRAY_SIZE(cache->hash); u16 cur = cache->hash[idx]; - struct hda_cache_head *info_head = cache->buf.list; struct hda_cache_head *info; while (cur != 0xffff) { - info = &info_head[cur]; + info = snd_array_elem(&cache->buf, cur); if (info->key == key) return info; cur = info->next; @@ -901,7 +900,7 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, info = snd_array_new(&cache->buf); if (!info) return NULL; - cur = cache->buf.used - 1; /* the last entry */ + cur = snd_array_index(&cache->buf, info); info->key = key; info->val = 0; info->next = cache->hash[idx]; @@ -3414,7 +3413,7 @@ void *snd_array_new(struct snd_array *array) array->list = nlist; array->alloced = num; } - return array->list + (array->used++ * array->elem_size); + return snd_array_elem(array, array->used++); } /* free the given array elements */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index a73f0eb99283..ee122b009fd4 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -539,6 +539,16 @@ static inline void snd_array_init(struct snd_array *array, unsigned int size, array->alloc_align = align; } +static inline void *snd_array_elem(struct snd_array *array, unsigned int idx) +{ + return array->list + idx * array->elem_size; +} + +static inline unsigned int snd_array_index(struct snd_array *array, void *ptr) +{ + return (unsigned long)(ptr - array->list) / array->elem_size; +} + /* * Structures */ From a7d26f84cb76b962217ce277c3e3a9748a26ac11 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 12 Nov 2008 11:02:25 +0100 Subject: [PATCH 082/367] ALSA: Release v1.0.18a Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/version.h b/include/sound/version.h index eae315573563..2b48237e23bf 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.18" +#define CONFIG_SND_VERSION "1.0.18a" #define CONFIG_SND_DATE "" From fb0ef645f2c546f8297b2fbf9b2b8fff4a7455e8 Mon Sep 17 00:00:00 2001 From: Naresh Medisetty Date: Wed, 12 Nov 2008 10:26:31 +0530 Subject: [PATCH 083/367] ASoC: DaVinci: Audio: Fix swapping of channels at start of stereo playback Fixes swapping of channels at start of stereo playback. Channel swap can be observed while playing left-only or right-only audio data. The channel swap is fixed by handling the XSYNCERR condition. Signed-off-by: Naresh Medisetty Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 51 ++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d814ec8947e5..8c1bf876031d 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -111,17 +111,60 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_platform *platform = socdev->platform; u32 w; + int ret; /* Start the sample generator and enable transmitter/receiver */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - else - MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Stop the DMA to avoid data loss */ + /* while the transmitter is out of reset to handle XSYNCERR */ + if (platform->pcm_ops->trigger) { + ret = platform->pcm_ops->trigger(substream, + SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) + printk(KERN_DEBUG "Playback DMA stop failed\n"); + } + + /* Enable the transmitter */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + /* wait for any unexpected frame sync error to occur */ + udelay(100); + + /* Disable the transmitter to clear any outstanding XSYNCERR */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + /* Restart the DMA */ + if (platform->pcm_ops->trigger) { + ret = platform->pcm_ops->trigger(substream, + SNDRV_PCM_TRIGGER_START); + if (ret < 0) + printk(KERN_DEBUG "Playback DMA start failed\n"); + } + /* Enable the transmitter */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + } else { + + /* Enable the reciever */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } + + /* Start frame sync */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_FRST, 1); From 11843ee4d5ee130b84de01c019dde7bf0a3eca78 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 12 Nov 2008 15:18:41 +0100 Subject: [PATCH 084/367] ALSA: powermac - Rename mic-analog loopback mixer element PCM Playback Volume:1 is actually assigned to a mic loopback volume on iBook G4. Let's rename it. Signed-off-by: Takashi Iwai --- sound/ppc/tumbler.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index f746e15b8481..3eb223385416 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -875,7 +875,8 @@ static struct snd_kcontrol_new snapper_mixers[] __initdata = { .put = tumbler_put_master_switch }, DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM), - DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2), + /* Alternative PCM is assigned to Mic analog loopback on iBook G4 */ + DEFINE_SNAPPER_MIX("Mic Playback Volume", 0, VOL_IDX_PCM2), DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC), DEFINE_SNAPPER_MONO("Tone Control - Bass", bass), DEFINE_SNAPPER_MONO("Tone Control - Treble", treble), From 9fb6198e8c574c6547fbfac0ae1eaf7894ddfdcc Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 11 Nov 2008 16:51:02 +0100 Subject: [PATCH 085/367] ALSA: add /sys/class/sound/card#/id (r/w) and card#/number (r/o) files For udev, we need a way to rename soundcard names. The soundcard numbers (indexes) are hardwired but we have a text identification which can be changed at run-time. The ALSA user space tools already allow using of this text identification. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/init.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/sound/core/init.c b/sound/core/init.c index b47ff8b44be8..5ff297d1d89a 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -533,6 +533,64 @@ static void choose_default_id(struct snd_card *card) } } +#ifndef CONFIG_SYSFS_DEPRECATED +static ssize_t +card_id_show_attr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_card *card = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%s\n", card ? card->id : "(null)"); +} + +static ssize_t +card_id_store_attr(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_card *card = dev_get_drvdata(dev); + char buf1[sizeof(card->id)]; + size_t copy = count > sizeof(card->id) - 1 ? + sizeof(card->id) - 1 : count; + size_t idx; + int c; + + for (idx = 0; idx < copy; idx++) { + c = buf[idx]; + if (!isalnum(c) && c != '_' && c != '-') + return -EINVAL; + } + memcpy(buf1, buf, copy); + buf1[copy] = '\0'; + mutex_lock(&snd_card_mutex); + if (!snd_info_check_reserved_words(buf1)) { + __exist: + mutex_unlock(&snd_card_mutex); + return -EEXIST; + } + for (idx = 0; idx < snd_ecards_limit; idx++) { + if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) + goto __exist; + } + strcpy(card->id, buf1); + mutex_unlock(&snd_card_mutex); + + return count; +} + +static struct device_attribute card_id_attrs = + __ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr); + +static ssize_t +card_number_show_attr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_card *card = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%i\n", card ? card->number : -1); +} + +static struct device_attribute card_number_attrs = + __ATTR(number, S_IRUGO, card_number_show_attr, NULL); +#endif /* CONFIG_SYSFS_DEPRECATED */ + /** * snd_card_register - register the soundcard * @card: soundcard structure @@ -553,7 +611,7 @@ int snd_card_register(struct snd_card *card) #ifndef CONFIG_SYSFS_DEPRECATED if (!card->card_dev) { card->card_dev = device_create(sound_class, card->dev, - MKDEV(0, 0), NULL, + MKDEV(0, 0), card, "card%i", card->number); if (IS_ERR(card->card_dev)) card->card_dev = NULL; @@ -575,6 +633,12 @@ int snd_card_register(struct snd_card *card) #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); +#endif +#ifndef CONFIG_SYSFS_DEPRECATED + if (card->card_dev) { + device_create_file(card->card_dev, &card_id_attrs); + device_create_file(card->card_dev, &card_number_attrs); + } #endif return 0; } From c2eb9c4ea383aee154e7139395872c4da629e715 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 12 Nov 2008 16:31:37 +0100 Subject: [PATCH 086/367] ALSA: when card identification is changed, change also /proc/asound symlink Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/info.h | 2 ++ sound/core/info.c | 17 +++++++++++++++++ sound/core/init.c | 1 + 3 files changed, 20 insertions(+) diff --git a/include/sound/info.h b/include/sound/info.h index 8ae72e74f898..46f702a76e4f 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -126,6 +126,7 @@ int snd_info_card_create(struct snd_card * card); int snd_info_card_register(struct snd_card * card); int snd_info_card_free(struct snd_card * card); void snd_info_card_disconnect(struct snd_card * card); +void snd_info_card_id_change(struct snd_card * card); int snd_info_register(struct snd_info_entry * entry); /* for card drivers */ @@ -160,6 +161,7 @@ static inline int snd_info_card_create(struct snd_card * card) { return 0; } static inline int snd_info_card_register(struct snd_card * card) { return 0; } static inline int snd_info_card_free(struct snd_card * card) { return 0; } static inline void snd_info_card_disconnect(struct snd_card * card) { } +static inline void snd_info_card_id_change(struct snd_card * card) { } static inline int snd_info_register(struct snd_info_entry * entry) { return 0; } static inline int snd_card_proc_new(struct snd_card *card, const char *name, diff --git a/sound/core/info.c b/sound/core/info.c index 527b207462b0..70fa87189f36 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -652,6 +652,23 @@ int snd_info_card_register(struct snd_card *card) return 0; } +/* + * called on card->id change + */ +void snd_info_card_id_change(struct snd_card *card) +{ + mutex_lock(&info_mutex); + if (card->proc_root_link) { + snd_remove_proc_entry(snd_proc_root, card->proc_root_link); + card->proc_root_link = NULL; + } + if (strcmp(card->id, card->proc_root->name)) + card->proc_root_link = proc_symlink(card->id, + snd_proc_root, + card->proc_root->name); + mutex_unlock(&info_mutex); +} + /* * de-register the card proc file * called from init.c diff --git a/sound/core/init.c b/sound/core/init.c index 5ff297d1d89a..af1e407ca27f 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -571,6 +571,7 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, goto __exist; } strcpy(card->id, buf1); + snd_info_card_id_change(card); mutex_unlock(&snd_card_mutex); return count; From 972d4c50fbbb1b9c10293ff90e4e1d45e7fb21ac Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 12 Nov 2008 16:37:48 +0100 Subject: [PATCH 087/367] ALSA: hdsp/hdspm: remove card->id from rawmidi device name The card->id (card text identification) can be changed at runtime. It might be confusing to have old text identification in device name. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/rme9652/hdsp.c | 2 +- sound/pci/rme9652/hdspm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 736246f98acc..fdd3be5b439d 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -1452,7 +1452,7 @@ static int snd_hdsp_create_midi (struct snd_card *card, struct hdsp *hdsp, int i if (snd_rawmidi_new (card, buf, id, 1, 1, &hdsp->midi[id].rmidi) < 0) return -1; - sprintf (hdsp->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); + sprintf(hdsp->midi[id].rmidi->name, "HDSP MIDI %d", id+1); hdsp->midi[id].rmidi->private_data = &hdsp->midi[id]; snd_rawmidi_set_ops (hdsp->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_hdsp_midi_output); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 98762f909d64..dc5c4baa1e64 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1293,7 +1293,7 @@ static int __devinit snd_hdspm_create_midi (struct snd_card *card, if (err < 0) return err; - sprintf (hdspm->midi[id].rmidi->name, "%s MIDI %d", card->id, id+1); + sprintf(hdspm->midi[id].rmidi->name, "HDSPM MIDI %d", id+1); hdspm->midi[id].rmidi->private_data = &hdspm->midi[id]; snd_rawmidi_set_ops(hdspm->midi[id].rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, From fd64138c0eff8351b93ef99f7da929bb8a49b9ed Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 12 Nov 2008 16:53:47 +0100 Subject: [PATCH 088/367] ALSA: include/sound/info.h - coding style changed Change coding style to be more acceptable by checkpatch.pl. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/info.h | 104 +++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/include/sound/info.h b/include/sound/info.h index 46f702a76e4f..7c2ee1a21b00 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -40,30 +40,34 @@ struct snd_info_buffer { struct snd_info_entry; struct snd_info_entry_text { - void (*read) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); - void (*write) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); + void (*read)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer); + void (*write)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer); }; struct snd_info_entry_ops { - int (*open) (struct snd_info_entry *entry, - unsigned short mode, void **file_private_data); - int (*release) (struct snd_info_entry * entry, - unsigned short mode, void *file_private_data); - long (*read) (struct snd_info_entry *entry, void *file_private_data, - struct file * file, char __user *buf, + int (*open)(struct snd_info_entry *entry, + unsigned short mode, void **file_private_data); + int (*release)(struct snd_info_entry *entry, + unsigned short mode, void *file_private_data); + long (*read)(struct snd_info_entry *entry, void *file_private_data, + struct file *file, char __user *buf, + unsigned long count, unsigned long pos); + long (*write)(struct snd_info_entry *entry, void *file_private_data, + struct file *file, const char __user *buf, unsigned long count, unsigned long pos); - long (*write) (struct snd_info_entry *entry, void *file_private_data, - struct file * file, const char __user *buf, - unsigned long count, unsigned long pos); - long long (*llseek) (struct snd_info_entry *entry, void *file_private_data, - struct file * file, long long offset, int orig); - unsigned int (*poll) (struct snd_info_entry *entry, void *file_private_data, - struct file * file, poll_table * wait); - int (*ioctl) (struct snd_info_entry *entry, void *file_private_data, - struct file * file, unsigned int cmd, unsigned long arg); - int (*mmap) (struct snd_info_entry *entry, void *file_private_data, - struct inode * inode, struct file * file, - struct vm_area_struct * vma); + long long (*llseek)(struct snd_info_entry *entry, + void *file_private_data, struct file *file, + long long offset, int orig); + unsigned int(*poll)(struct snd_info_entry *entry, + void *file_private_data, struct file *file, + poll_table *wait); + int (*ioctl)(struct snd_info_entry *entry, void *file_private_data, + struct file *file, unsigned int cmd, unsigned long arg); + int (*mmap)(struct snd_info_entry *entry, void *file_private_data, + struct inode *inode, struct file *file, + struct vm_area_struct *vma); }; struct snd_info_entry { @@ -106,35 +110,37 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer); static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {} #endif -int snd_iprintf(struct snd_info_buffer * buffer, char *fmt,...) __attribute__ ((format (printf, 2, 3))); +int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) \ + __attribute__ ((format (printf, 2, 3))); int snd_info_init(void); int snd_info_done(void); -int snd_info_get_line(struct snd_info_buffer * buffer, char *line, int len); +int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len); char *snd_info_get_str(char *dest, char *src, int len); -struct snd_info_entry *snd_info_create_module_entry(struct module * module, +struct snd_info_entry *snd_info_create_module_entry(struct module *module, const char *name, - struct snd_info_entry * parent); -struct snd_info_entry *snd_info_create_card_entry(struct snd_card * card, + struct snd_info_entry *parent); +struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, - struct snd_info_entry * parent); -void snd_info_free_entry(struct snd_info_entry * entry); -int snd_info_store_text(struct snd_info_entry * entry); -int snd_info_restore_text(struct snd_info_entry * entry); + struct snd_info_entry *parent); +void snd_info_free_entry(struct snd_info_entry *entry); +int snd_info_store_text(struct snd_info_entry *entry); +int snd_info_restore_text(struct snd_info_entry *entry); -int snd_info_card_create(struct snd_card * card); -int snd_info_card_register(struct snd_card * card); -int snd_info_card_free(struct snd_card * card); -void snd_info_card_disconnect(struct snd_card * card); -void snd_info_card_id_change(struct snd_card * card); -int snd_info_register(struct snd_info_entry * entry); +int snd_info_card_create(struct snd_card *card); +int snd_info_card_register(struct snd_card *card); +int snd_info_card_free(struct snd_card *card); +void snd_info_card_disconnect(struct snd_card *card); +void snd_info_card_id_change(struct snd_card *card); +int snd_info_register(struct snd_info_entry *entry); /* for card drivers */ -int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp); +int snd_card_proc_new(struct snd_card *card, const char *name, + struct snd_info_entry **entryp); static inline void snd_info_set_text_ops(struct snd_info_entry *entry, - void *private_data, - void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) + void *private_data, + void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) { entry->private_data = private_data; entry->c.text.read = read; @@ -147,22 +153,22 @@ int snd_info_check_reserved_words(const char *str); #define snd_seq_root NULL #define snd_oss_root NULL -static inline int snd_iprintf(struct snd_info_buffer * buffer, char *fmt,...) { return 0; } +static inline int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) { return 0; } static inline int snd_info_init(void) { return 0; } static inline int snd_info_done(void) { return 0; } -static inline int snd_info_get_line(struct snd_info_buffer * buffer, char *line, int len) { return 0; } +static inline int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) { return 0; } static inline char *snd_info_get_str(char *dest, char *src, int len) { return NULL; } -static inline struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, struct snd_info_entry * parent) { return NULL; } -static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card * card, const char *name, struct snd_info_entry * parent) { return NULL; } -static inline void snd_info_free_entry(struct snd_info_entry * entry) { ; } +static inline struct snd_info_entry *snd_info_create_module_entry(struct module *module, const char *name, struct snd_info_entry *parent) { return NULL; } +static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry *parent) { return NULL; } +static inline void snd_info_free_entry(struct snd_info_entry *entry) { ; } -static inline int snd_info_card_create(struct snd_card * card) { return 0; } -static inline int snd_info_card_register(struct snd_card * card) { return 0; } -static inline int snd_info_card_free(struct snd_card * card) { return 0; } -static inline void snd_info_card_disconnect(struct snd_card * card) { } -static inline void snd_info_card_id_change(struct snd_card * card) { } -static inline int snd_info_register(struct snd_info_entry * entry) { return 0; } +static inline int snd_info_card_create(struct snd_card *card) { return 0; } +static inline int snd_info_card_register(struct snd_card *card) { return 0; } +static inline int snd_info_card_free(struct snd_card *card) { return 0; } +static inline void snd_info_card_disconnect(struct snd_card *card) { } +static inline void snd_info_card_id_change(struct snd_card *card) { } +static inline int snd_info_register(struct snd_info_entry *entry) { return 0; } static inline int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_entry **entryp) { return -EINVAL; } From 3a95cb972bb0eb80dfdb42f11628e6d58bcdde29 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 13 Nov 2008 10:19:38 +0800 Subject: [PATCH 089/367] ALSA: handle SiI1392 HDMI codec in patch_intelhdmi.c Move the handling of SiI1392 HDMI codec from patch_atihdmi.c to patch_intelhdmi.c, which makes our ASUS P5E-VM HDMI board work. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_atihdmi.c | 1 - sound/pci/hda/patch_intelhdmi.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index ba61575983fd..5603a1acddb1 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -193,7 +193,6 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = { { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi }, - { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_atihdmi }, { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 3beaf9c1090c..939b37ba7074 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -924,5 +924,6 @@ struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi }, + { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; From c4da29ca08e09ed41a2030c1f7b5860f116573be Mon Sep 17 00:00:00 2001 From: "Yang, Libin" Date: Thu, 13 Nov 2008 11:07:07 +0100 Subject: [PATCH 090/367] ALSA: hda - support detecting HD Audio devices with PCI class code The patch uses HD Audio PCI class code to detect AMD HD Audio cards. Signed-off-by: Libin Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3e112df1c0dc..f73c13fdd409 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -292,6 +292,8 @@ enum { /* Define VIA HD Audio Device ID*/ #define VIA_HDAC_DEVICE_ID 0x3288 +/* HD Audio class code */ +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 /* */ @@ -415,6 +417,7 @@ enum { AZX_DRIVER_ULI, AZX_DRIVER_NVIDIA, AZX_DRIVER_TERA, + AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ }; @@ -428,6 +431,7 @@ static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ULI] = "HDA ULI M5461", [AZX_DRIVER_NVIDIA] = "HDA NVidia", [AZX_DRIVER_TERA] = "HDA Teradici", + [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; /* @@ -2203,6 +2207,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, chip->playback_streams = ATIHDMI_NUM_PLAYBACK; chip->capture_streams = ATIHDMI_NUM_CAPTURE; break; + case AZX_DRIVER_GENERIC: default: chip->playback_streams = ICH6_NUM_PLAYBACK; chip->capture_streams = ICH6_NUM_CAPTURE; @@ -2427,6 +2432,11 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0bd7), .driver_data = AZX_DRIVER_NVIDIA }, /* Teradici */ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, + /* AMD Generic, PCI class code and Vendor ID for HD Audio */ + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), + .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, + .class_mask = 0xffffff, + .driver_data = AZX_DRIVER_GENERIC }, { 0, } }; MODULE_DEVICE_TABLE(pci, azx_ids); From bbba944410310181de14a5c60a7c161ff2447dd9 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 12 Nov 2008 17:05:41 +0200 Subject: [PATCH 091/367] ASoC: Fix supported sample rates of TWL4030 audio codec TWL4030 currently supports rates between 8 kHz and 48 kHz and sets the codec mode register accordingly in twl4030_hw_params. Expose this info so that ASoC can match other rates than 44.1 kHz or 48 kHz as well. Signed-off-by: Jarkko Nikula Acked-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 90f3b4decbab..c1893d23703d 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -504,7 +504,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, return 0; } -#define TWL4030_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) struct snd_soc_dai twl4030_dai = { From 0b6048561d5f505e3a027a519a6d0f488ba9a2bb Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 12 Nov 2008 17:05:51 +0200 Subject: [PATCH 092/367] ASoC: OMAP: Add more supported sample rates into McBSP DAI driver Originally it was put too tight limits to support only 44.1 kHz and 48 kHz sample rates in McBSP DAI driver. Extend it now to 8 kHz - 96 kHz. With 96 kHz and 2*16 bits, bit clock is 3.072 MHz < 3.125 MHz (I2S max?). Tested on Nokia N810 with TVL320AIC33 from rates 8 - 96 kHz and on Texas Instruments Beagle with TWL4030 from rates 8 - 48 kHz. Signed-off-by: Jarkko Nikula Acked-by: Steve Sakoman Acked-by: Arun KS Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 8485a8a9d0ff..3d4060b00eb3 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -36,9 +36,7 @@ #include "omap-mcbsp.h" #include "omap-pcm.h" -#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | \ - SNDRV_PCM_RATE_KNOT) +#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) struct omap_mcbsp_data { unsigned int bus_id; From 8a75f4fb28766878893b4335f4b5743ce9b931fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 14 Nov 2008 13:58:43 +0100 Subject: [PATCH 093/367] ALSA: pcsp - Use HRTIMER_CB_IRQSAFE_UNLOCKED HRTIMER_CB_IRQSAFE was removed in the upstream. Try to use HRTIMER_CB_IRQSAFE_UNLOCKED instead. Signed-off-by: Takashi Iwai --- sound/drivers/pcsp/pcsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index 87219bf0a35e..2a02f704f366 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -96,7 +96,7 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) return -EINVAL; hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE; + pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED; pcsp_chip.timer.function = pcsp_do_timer; card = snd_card_new(index, id, THIS_MODULE, 0); From 127e82e3bfaad29e78ff5d4b1c41ab5e2d69c17f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 14 Nov 2008 14:03:33 +0100 Subject: [PATCH 094/367] ALSA: hda - Support Headphone and Speaker volumes control on VAIO Split the bound Master control to individual Headphone and Speaker volume controls for VAIO with STAC982x codecs. The Master controls is still created as a vmaster. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 58d832c3835a..66c12d3e9c79 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5132,29 +5132,11 @@ static struct hda_verb vaio_ar_init[] = { {} }; -/* bind volumes of both NID 0x02 and 0x05 */ -static struct hda_bind_ctls vaio_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* bind volumes of both NID 0x02 and 0x05 */ -static struct hda_bind_ctls vaio_bind_master_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - 0, - }, -}; - static struct snd_kcontrol_new vaio_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), @@ -5170,8 +5152,10 @@ static struct snd_kcontrol_new vaio_mixer[] = { }; static struct snd_kcontrol_new vaio_ar_mixer[] = { - HDA_BIND_VOL("Master Playback Volume", &vaio_bind_master_vol), - HDA_BIND_SW("Master Playback Switch", &vaio_bind_master_sw), + HDA_CODEC_VOLUME("Headphone Playback Volume", 0x02, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone Playback Switch", 0x02, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x05, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Speaker Playback Switch", 0x05, 0, HDA_OUTPUT), /* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */ HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT), From 2bef901071448e0c86af8edb4797cd5f81b6240d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 14 Nov 2008 14:40:46 +0000 Subject: [PATCH 095/367] ASoC: Revert "ASoC: Add new parameter to s3c24xx_pcm_enqueue" This reverts commit 8dc840f88d9c9f75f46d5dbe489242f8a114fab6. Christian Pellegrin reported that on some systems the patch caused DMA to fail which is much more serious than the original skipped audio issue. Further investigation by Dave shows that the behaviour depends on the clock speed of the SoC - a better fix is neeeded. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx-pcm.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index 341198bb0c17..e13e614bada9 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -78,8 +78,7 @@ struct s3c24xx_runtime_data { * place a dma buffer onto the queue for the dma system * to handle. */ -static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream, - int dma_max) +static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) { struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; dma_addr_t pos = prtd->dma_pos; @@ -87,10 +86,7 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream, DBG("Entered %s\n", __func__); - if (!dma_max) - dma_max = prtd->dma_limit; - - while (prtd->dma_loaded < dma_max) { + while (prtd->dma_loaded < prtd->dma_limit) { unsigned long len = prtd->dma_period; DBG("dma_loaded: %d\n", prtd->dma_loaded); @@ -136,7 +132,7 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel, spin_lock(&prtd->lock); if (prtd->state & ST_RUNNING) { prtd->dma_loaded--; - s3c24xx_pcm_enqueue(substream, 0); + s3c24xx_pcm_enqueue(substream); } spin_unlock(&prtd->lock); @@ -253,7 +249,7 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) prtd->dma_pos = prtd->dma_start; /* enqueue dma buffers */ - s3c24xx_pcm_enqueue(substream, 1); + s3c24xx_pcm_enqueue(substream); return ret; } From 71cfc9028d762419ce4dea62b4afc9c32c4b4820 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 13 Nov 2008 14:33:14 +0000 Subject: [PATCH 096/367] ASoC: Add WM8728 codec driver The WM8728 is a high performance stereo DAC designed for applications such as DVD, home theatre and digital TV. Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8728.c | 574 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wm8728.h | 30 ++ 4 files changed, 610 insertions(+) create mode 100644 sound/soc/codecs/wm8728.c create mode 100644 sound/soc/codecs/wm8728.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b73c36aad677..8a84460a6f74 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -13,6 +13,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_UDA1380 if I2C select SND_SOC_WM8510 if (I2C || SPI_MASTER) select SND_SOC_WM8580 if I2C + select SND_SOC_WM8728 if (I2C || SPI_MASTER) select SND_SOC_WM8731 if (I2C || SPI_MASTER) select SND_SOC_WM8750 if (I2C || SPI_MASTER) select SND_SOC_WM8753 if (I2C || SPI_MASTER) @@ -93,6 +94,9 @@ config SND_SOC_WM8510 config SND_SOC_WM8580 tristate +config SND_SOC_WM8728 + tristate + config SND_SOC_WM8731 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3b9b58a0ea7d..7ae17a6ea271 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -11,6 +11,7 @@ snd-soc-twl4030-objs := twl4030.o snd-soc-uda1380-objs := uda1380.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o +snd-soc-wm8728-objs := wm8728.o snd-soc-wm8731-objs := wm8731.o snd-soc-wm8750-objs := wm8750.o snd-soc-wm8753-objs := wm8753.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o +obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c new file mode 100644 index 000000000000..3e39dea61241 --- /dev/null +++ b/sound/soc/codecs/wm8728.c @@ -0,0 +1,574 @@ +/* + * wm8728.c -- WM8728 ALSA SoC Audio driver + * + * Copyright 2008 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8728.h" + +struct snd_soc_codec_device soc_codec_dev_wm8728; + +/* + * We can't read the WM8728 register space so we cache them instead. + * Note that the defaults here aren't the physical defaults, we latch + * the volume update bits, mute the output and enable infinite zero + * detect. + */ +static const u16 wm8728_reg_defaults[] = { + 0x1ff, + 0x1ff, + 0x001, + 0x100, +}; + +static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); + return cache[reg]; +} + +static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg > ARRAY_SIZE(wm8728_reg_defaults)); + cache[reg] = value; +} + +/* + * write to the WM8728 register space + */ +static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8728 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8728_write_reg_cache(codec, reg, value); + + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); + +static const struct snd_kcontrol_new wm8728_snd_controls[] = { + +SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8728_DACLVOL, WM8728_DACRVOL, + 0, 255, 0, wm8728_tlv), + +SOC_SINGLE("Deemphasis", WM8728_DACCTL, 1, 1, 0), +}; + +static int wm8728_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8728_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8728_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +/* + * DAPM controls. + */ +static const struct snd_soc_dapm_widget wm8728_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_OUTPUT("VOUTL"), +SND_SOC_DAPM_OUTPUT("VOUTR"), +}; + +static const struct snd_soc_dapm_route intercon[] = { + {"VOUTL", NULL, "DAC"}, + {"VOUTR", NULL, "DAC"}, +}; + +static int wm8728_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets, + ARRAY_SIZE(wm8728_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); + + snd_soc_dapm_new_widgets(codec); + + return 0; +} + +static int wm8728_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + + if (mute) + wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); + else + wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); + + return 0; +} + +static int wm8728_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); + + dac &= ~0x18; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + dac |= 0x10; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dac |= 0x08; + break; + default: + return -EINVAL; + } + + wm8728_write(codec, WM8728_DACCTL, dac); + + return 0; +} + +static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL); + + /* Currently only I2S is supported by the driver, though the + * hardware is more flexible. + */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 1; + break; + default: + return -EINVAL; + } + + /* The hardware only support full slave mode */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + iface &= ~0x22; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x20; + iface &= ~0x02; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= 0x02; + iface &= ~0x20; + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x22; + break; + default: + return -EINVAL; + } + + wm8728_write(codec, WM8728_IFCTL, iface); + return 0; +} + +static int wm8728_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u16 reg; + int i; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Power everything up... */ + reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); + + /* ..then sync in the register cache. */ + for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) + wm8728_write(codec, i, + wm8728_read_reg_cache(codec, i)); + } + break; + + case SND_SOC_BIAS_OFF: + reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + wm8728_write(codec, WM8728_DACCTL, reg | 0x4); + break; + } + codec->bias_level = level; + return 0; +} + +#define WM8728_RATES (SNDRV_PCM_RATE_8000_192000) + +#define WM8728_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +struct snd_soc_dai wm8728_dai = { + .name = "WM8728", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = WM8728_RATES, + .formats = WM8728_FORMATS, + }, + .ops = { + .hw_params = wm8728_hw_params, + }, + .dai_ops = { + .digital_mute = wm8728_mute, + .set_fmt = wm8728_set_dai_fmt, + } +}; +EXPORT_SYMBOL_GPL(wm8728_dai); + +static int wm8728_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); + + return 0; +} + +static int wm8728_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8728_set_bias_level(codec, codec->suspend_bias_level); + + return 0; +} + +/* + * initialise the WM8728 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8728_init(struct snd_soc_device *socdev) +{ + struct snd_soc_codec *codec = socdev->codec; + int ret = 0; + + codec->name = "WM8728"; + codec->owner = THIS_MODULE; + codec->read = wm8728_read_reg_cache; + codec->write = wm8728_write; + codec->set_bias_level = wm8728_set_bias_level; + codec->dai = &wm8728_dai; + codec->num_dai = 1; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults); + codec->reg_cache = kmemdup(wm8728_reg_defaults, + sizeof(wm8728_reg_defaults), + GFP_KERNEL); + if (codec->reg_cache == NULL) + return -ENOMEM; + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "wm8728: failed to create pcms\n"); + goto pcm_err; + } + + /* power on device */ + wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + wm8728_add_controls(codec); + wm8728_add_widgets(codec); + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "wm8728: failed to register card\n"); + goto card_err; + } + + return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); + return ret; +} + +static struct snd_soc_device *wm8728_socdev; + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + +/* + * WM8728 2 wire address is determined by GPIO5 + * state during powerup. + * low = 0x1a + * high = 0x1b + */ + +static int wm8728_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_device *socdev = wm8728_socdev; + struct snd_soc_codec *codec = socdev->codec; + int ret; + + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = wm8728_init(socdev); + if (ret < 0) + pr_err("failed to initialise WM8728\n"); + + return ret; +} + +static int wm8728_i2c_remove(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + kfree(codec->reg_cache); + return 0; +} + +static const struct i2c_device_id wm8728_i2c_id[] = { + { "wm8728", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); + +static struct i2c_driver wm8728_i2c_driver = { + .driver = { + .name = "WM8728 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = wm8728_i2c_probe, + .remove = wm8728_i2c_remove, + .id_table = wm8728_i2c_id, +}; + +static int wm8728_add_i2c_device(struct platform_device *pdev, + const struct wm8728_setup_data *setup) +{ + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client; + int ret; + + ret = i2c_add_driver(&wm8728_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } + + memset(&info, 0, sizeof(struct i2c_board_info)); + info.addr = setup->i2c_address; + strlcpy(info.type, "wm8728", I2C_NAME_SIZE); + + adapter = i2c_get_adapter(setup->i2c_bus); + if (!adapter) { + dev_err(&pdev->dev, "can't get i2c adapter %d\n", + setup->i2c_bus); + goto err_driver; + } + + client = i2c_new_device(adapter, &info); + i2c_put_adapter(adapter); + if (!client) { + dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", + (unsigned int)info.addr); + goto err_driver; + } + + return 0; + +err_driver: + i2c_del_driver(&wm8728_i2c_driver); + return -ENODEV; +} +#endif + +#if defined(CONFIG_SPI_MASTER) +static int __devinit wm8728_spi_probe(struct spi_device *spi) +{ + struct snd_soc_device *socdev = wm8728_socdev; + struct snd_soc_codec *codec = socdev->codec; + int ret; + + codec->control_data = spi; + + ret = wm8728_init(socdev); + if (ret < 0) + dev_err(&spi->dev, "failed to initialise WM8728\n"); + + return ret; +} + +static int __devexit wm8728_spi_remove(struct spi_device *spi) +{ + return 0; +} + +static struct spi_driver wm8728_spi_driver = { + .driver = { + .name = "wm8728", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm8728_spi_probe, + .remove = __devexit_p(wm8728_spi_remove), +}; + +static int wm8728_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} +#endif /* CONFIG_SPI_MASTER */ + +static int wm8728_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8728_setup_data *setup; + struct snd_soc_codec *codec; + int ret = 0; + + setup = socdev->codec_data; + codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (codec == NULL) + return -ENOMEM; + + socdev->codec = codec; + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + wm8728_socdev = socdev; + ret = -ENODEV; + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + if (setup->i2c_address) { + codec->hw_write = (hw_write_t)i2c_master_send; + ret = wm8728_add_i2c_device(pdev, setup); + } +#endif +#if defined(CONFIG_SPI_MASTER) + if (setup->spi) { + codec->hw_write = (hw_write_t)wm8728_spi_write; + ret = spi_register_driver(&wm8728_spi_driver); + if (ret != 0) + printk(KERN_ERR "can't add spi driver"); + } +#endif + + if (ret != 0) + kfree(codec); + + return ret; +} + +/* power down chip */ +static int wm8728_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + if (codec->control_data) + wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_unregister_device(codec->control_data); + i2c_del_driver(&wm8728_i2c_driver); +#endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&wm8728_spi_driver); +#endif + kfree(codec); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_wm8728 = { + .probe = wm8728_probe, + .remove = wm8728_remove, + .suspend = wm8728_suspend, + .resume = wm8728_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); + +MODULE_DESCRIPTION("ASoC WM8728 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8728.h b/sound/soc/codecs/wm8728.h new file mode 100644 index 000000000000..d269c132474b --- /dev/null +++ b/sound/soc/codecs/wm8728.h @@ -0,0 +1,30 @@ +/* + * wm8728.h -- WM8728 ASoC codec driver + * + * Copyright 2008 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * 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 _WM8728_H +#define _WM8728_H + +#define WM8728_DACLVOL 0x00 +#define WM8728_DACRVOL 0x01 +#define WM8728_DACCTL 0x02 +#define WM8728_IFCTL 0x03 + +struct wm8728_setup_data { + int spi; + int i2c_bus; + unsigned short i2c_address; +}; + +extern struct snd_soc_dai wm8728_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8728; + +#endif From 3ab909351a3c653a879a35b3342979ac483c0460 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 17 Nov 2008 09:51:09 +0100 Subject: [PATCH 097/367] ALSA: hda: alc883 model for ASUS P5Q-EM boards Add a new alc883 model ALC1200_ASUS_P5Q for ASUS P5Q-EM boards. It is the same as ALC883_6ST_DIG except that the SPDIF digital output nid is 0x10. Tested-by: Andrei Tanas Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 017abd01299d..04e153a77dbc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -232,6 +232,7 @@ enum { ALC883_3ST_6ch_INTEL, ALC888_ASUS_M90V, ALC888_ASUS_EEE1601, + ALC1200_ASUS_P5Q, ALC883_AUTO, ALC883_MODEL_LAST, }; @@ -6868,6 +6869,8 @@ static int patch_alc882(struct hda_codec *codec) #define ALC883_DIGOUT_NID 0x06 #define ALC883_DIGIN_NID 0x0a +#define ALC1200_DIGOUT_NID 0x10 + static hda_nid_t alc883_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x03, 0x04, 0x05 @@ -8190,6 +8193,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_CLEVO_M720] = "clevo-m720", [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", + [ALC1200_ASUS_P5Q] = "asus-p5q", [ALC883_AUTO] = "auto", }; @@ -8208,6 +8212,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), + SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), @@ -8555,6 +8560,17 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_eee1601_unsol_event, .init_hook = alc883_eee1601_inithook, }, + [ALC1200_ASUS_P5Q] = { + .mixers = { alc883_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC1200_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), + .channel_mode = alc883_sixstack_modes, + .input_mux = &alc883_capture_source, + }, }; From c0cea0d09d15350c398e2951e7cf4d6f0fc98977 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sun, 16 Nov 2008 11:42:34 -0500 Subject: [PATCH 098/367] ALSA: hda: STAC_DELL_M6 EAPD Add support for EAPD on system suspend and disabling EAPD on headphone jack detection for STAC_DELL_M6 laptops. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6d9c634632d4..1aa3f6cbcb96 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -147,6 +147,7 @@ struct sigmatel_spec { unsigned int num_mixers; int board_config; + unsigned int eapd_switch: 1; unsigned int surr_switch: 1; unsigned int line_switch: 1; unsigned int mic_switch: 1; @@ -4001,7 +4002,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) for (i = 0; i < cfg->speaker_outs; i++) stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], AC_PINCTL_OUT_EN); - if (spec->eapd_mask) + if (spec->eapd_mask && spec->eapd_switch) stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data & ~spec->eapd_mask); @@ -4016,7 +4017,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) for (i = 0; i < cfg->speaker_outs; i++) stac92xx_set_pinctl(codec, cfg->speaker_pins[i], AC_PINCTL_OUT_EN); - if (spec->eapd_mask) + if (spec->eapd_mask && spec->eapd_switch) stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data | spec->eapd_mask); @@ -4376,6 +4377,7 @@ again: spec->num_smuxes = 0; spec->mixer = &stac92hd73xx_6ch_mixer[DELL_M6_MIXER]; spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; + spec->eapd_switch = 0; spec->num_amps = 1; if (!spec->init) @@ -4407,6 +4409,7 @@ again: default: spec->num_dmics = STAC92HD73XX_NUM_DMICS; spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); + spec->eapd_switch = 1; } if (spec->board_config > STAC_92HD73XX_REF) { /* GPIO0 High = Enable EAPD */ @@ -4552,7 +4555,13 @@ static int stac92hd71xx_resume(struct hda_codec *codec) static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) { + struct sigmatel_spec *spec = codec->spec; + stac92hd71xx_set_power_state(codec, AC_PWRST_D3); + if (spec->eapd_mask) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); return 0; }; @@ -4942,6 +4951,7 @@ static int patch_stac927x(struct hda_codec *codec) spec->num_pwrs = 0; spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; + spec->eapd_switch = 1; err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); if (!err) { @@ -5022,6 +5032,7 @@ static int patch_stac9205(struct hda_codec *codec) spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; + spec->eapd_switch = 1; spec->multiout.dac_nids = spec->dac_nids; switch (spec->board_config){ From 796359d150356adabb677d708a4e66a09d29d9d8 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 17 Nov 2008 16:57:33 +0800 Subject: [PATCH 099/367] ALSA: hda-intel: reorder HDMI audio enabling sequence Reorder HDMI audio enabling sequence so that 1) the sink knows about the coming audio stream 2) unmute 3) start transferring audio samples The theory is that in the path A=>B=>C, we first make C ready, and then enable B, and lastly allow A to send audio samples. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 939b37ba7074..d99cd6297249 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -312,16 +312,16 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, static void hdmi_enable_output(struct hda_codec *codec) { - /* Enable pin out and unmute */ - snd_hda_sequence_write(codec, pinout_enable_verb); - 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); - /* Enable Audio InfoFrame Transmission */ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); snd_hda_codec_write(codec, PIN_NID, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); + /* Unmute */ + 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); + /* Enable pin out */ + snd_hda_sequence_write(codec, pinout_enable_verb); } static void hdmi_disable_output(struct hda_codec *codec) From 6e5d9db271ab57789b09bcc61083ab71b7eabea9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 14 Nov 2008 08:57:28 +0200 Subject: [PATCH 100/367] ASoC: Fix for master playback/capture volume range for TWL4030 codec FGAIN for playback is in range of 0-0x3f, while for capture GAIN it is in the range of 0-0x1f. The original value of 128 (0x7f) would modify the CGAIN also for playback. Signed-off-by: Peter Ujfalusi Acked-by: Steve Sakoman Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c1893d23703d..c778eb446a5b 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -192,10 +192,10 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R("Master Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 0, 127, 0), + 0, 0x3f, 0), SOC_DOUBLE_R("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, - 0, 127, 0), + 0, 0x1f, 0), }; /* add non dapm controls */ From 1cad1de1b216b355a60d907c103b2daf1a285345 Mon Sep 17 00:00:00 2001 From: Christian Pellegrin Date: Sat, 15 Nov 2008 08:58:16 +0100 Subject: [PATCH 101/367] ASoC: UDA134x codec driver Signed-off-by: Christian Pellegrin Signed-off-by: Mark Brown --- include/sound/l3.h | 18 + include/sound/uda134x.h | 26 ++ sound/soc/codecs/Kconfig | 8 + sound/soc/codecs/Makefile | 4 + sound/soc/codecs/l3.c | 91 +++++ sound/soc/codecs/uda134x.c | 656 +++++++++++++++++++++++++++++++ sound/soc/codecs/uda134x_codec.h | 36 ++ 7 files changed, 839 insertions(+) create mode 100644 include/sound/l3.h create mode 100644 include/sound/uda134x.h create mode 100644 sound/soc/codecs/l3.c create mode 100644 sound/soc/codecs/uda134x.c create mode 100644 sound/soc/codecs/uda134x_codec.h diff --git a/include/sound/l3.h b/include/sound/l3.h new file mode 100644 index 000000000000..423a08f0f1b0 --- /dev/null +++ b/include/sound/l3.h @@ -0,0 +1,18 @@ +#ifndef _L3_H_ +#define _L3_H_ 1 + +struct l3_pins { + void (*setdat)(int); + void (*setclk)(int); + void (*setmode)(int); + int data_hold; + int data_setup; + int clock_high; + int mode_hold; + int mode; + int mode_setup; +}; + +int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len); + +#endif diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h new file mode 100644 index 000000000000..475ef8bb7dcd --- /dev/null +++ b/include/sound/uda134x.h @@ -0,0 +1,26 @@ +/* + * uda134x.h -- UDA134x ALSA SoC Codec driver + * + * Copyright 2007 Dension Audio Systems Ltd. + * Author: Zoltan Devai + * + * 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 _UDA134X_H +#define _UDA134X_H + +#include + +struct uda134x_platform_data { + struct l3_pins l3; + void (*power) (int); + int model; +#define UDA134X_UDA1340 1 +#define UDA134X_UDA1341 2 +#define UDA134X_UDA1344 3 +}; + +#endif /* _UDA134X_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8a84460a6f74..04f49f5c3c3d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -10,6 +10,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC3X if I2C select SND_SOC_TWL4030 if TWL4030_CORE + select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C select SND_SOC_WM8510 if (I2C || SPI_MASTER) select SND_SOC_WM8580 if I2C @@ -66,6 +67,9 @@ config SND_SOC_CS4270_VD33_ERRATA bool depends on SND_SOC_CS4270 +config SND_SOC_L3 + tristate + config SND_SOC_SSM2602 tristate @@ -85,6 +89,10 @@ config SND_SOC_TWL4030 tristate depends on TWL4030_CORE +config SND_SOC_UDA134X + tristate + select SND_SOC_L3 + config SND_SOC_UDA1380 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7ae17a6ea271..de6572356d1b 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -3,11 +3,13 @@ snd-soc-ad1980-objs := ad1980.o snd-soc-ad73311-objs := ad73311.o snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o +snd-soc-l3-objs := l3.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-twl4030-objs := twl4030.o +snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o @@ -27,11 +29,13 @@ obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o +obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o +obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c new file mode 100644 index 000000000000..5353af58862c --- /dev/null +++ b/sound/soc/codecs/l3.c @@ -0,0 +1,91 @@ +/* + * L3 code + * + * Copyright (C) 2008, Christian Pellegrin + * + * 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. + * + * + * based on: + * + * L3 bus algorithm module. + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * + */ + +#include +#include +#include + +#include + +/* + * Send one byte of data to the chip. Data is latched into the chip on + * the rising edge of the clock. + */ +static void sendbyte(struct l3_pins *adap, unsigned int byte) +{ + int i; + + for (i = 0; i < 8; i++) { + adap->setclk(0); + udelay(adap->data_hold); + adap->setdat(byte & 1); + udelay(adap->data_setup); + adap->setclk(1); + udelay(adap->clock_high); + byte >>= 1; + } +} + +/* + * Send a set of bytes to the chip. We need to pulse the MODE line + * between each byte, but never at the start nor at the end of the + * transfer. + */ +static void sendbytes(struct l3_pins *adap, const u8 *buf, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (i) { + udelay(adap->mode_hold); + adap->setmode(0); + udelay(adap->mode); + } + adap->setmode(1); + udelay(adap->mode_setup); + sendbyte(adap, buf[i]); + } +} + +int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) +{ + adap->setclk(1); + adap->setdat(1); + adap->setmode(1); + udelay(adap->mode); + + adap->setmode(0); + udelay(adap->mode_setup); + sendbyte(adap, addr); + udelay(adap->mode_hold); + + sendbytes(adap, data, len); + + adap->setclk(1); + adap->setdat(1); + adap->setmode(0); + + return len; +} +EXPORT_SYMBOL_GPL(l3_write); + +MODULE_DESCRIPTION("L3 bit-banging driver"); +MODULE_AUTHOR("Christian Pellegrin "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c new file mode 100644 index 000000000000..04b30da10228 --- /dev/null +++ b/sound/soc/codecs/uda134x.c @@ -0,0 +1,656 @@ +/* + * uda134x.c -- UDA134X ALSA SoC Codec driver + * + * Modifications by Christian Pellegrin + * + * Copyright 2007 Dension Audio Systems Ltd. + * Author: Zoltan Devai + * + * Based on the WM87xx drivers by Liam Girdwood and Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "uda134x_codec.h" + + +#define POWER_OFF_ON_STANDBY 1 +/* + ALSA SOC usually puts the device in standby mode when it's not used + for sometime. If you define POWER_OFF_ON_STANDBY the driver will + turn off the ADC/DAC when this callback is invoked and turn it back + on when needed. Unfortunately this will result in a very light bump + (it can be audible only with good earphones). If this bothers you + just comment this line, you will have slightly higher power + consumption . Please note that sending the L3 command for ADC is + enough to make the bump, so it doesn't make difference if you + completely take off power from the codec. + */ + +#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 +#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) + +struct uda134x_priv { + int sysclk; + int dai_fmt; + + struct snd_pcm_substream *master_substream; + struct snd_pcm_substream *slave_substream; +}; + +/* In-data addresses are hard-coded into the reg-cache values */ +static const char uda134x_reg[UDA134X_REGS_NUM] = { + /* Extended address registers */ + 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + /* Status, data regs */ + 0x00, 0x83, 0x00, 0x40, 0x80, 0x00, +}; + +/* + * The codec has no support for reading its registers except for peak level... + */ +static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u8 *cache = codec->reg_cache; + + if (reg >= UDA134X_REGS_NUM) + return -1; + return cache[reg]; +} + +/* + * Write the register cache + */ +static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec, + u8 reg, unsigned int value) +{ + u8 *cache = codec->reg_cache; + + if (reg >= UDA134X_REGS_NUM) + return; + cache[reg] = value; +} + +/* + * Write to the uda134x registers + * + */ +static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + int ret; + u8 addr; + u8 data = value; + struct uda134x_platform_data *pd = codec->control_data; + + pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); + + if (reg >= UDA134X_REGS_NUM) { + printk(KERN_ERR "%s unkown register: reg: %d", + __func__, reg); + return -EINVAL; + } + + uda134x_write_reg_cache(codec, reg, value); + + switch (reg) { + case UDA134X_STATUS0: + case UDA134X_STATUS1: + addr = UDA134X_STATUS_ADDR; + break; + case UDA134X_DATA000: + case UDA134X_DATA001: + case UDA134X_DATA010: + addr = UDA134X_DATA0_ADDR; + break; + case UDA134X_DATA1: + addr = UDA134X_DATA1_ADDR; + break; + default: + /* It's an extended address register */ + addr = (reg | UDA134X_EXTADDR_PREFIX); + + ret = l3_write(&pd->l3, + UDA134X_DATA0_ADDR, &addr, 1); + if (ret != 1) + return -EIO; + + addr = UDA134X_DATA0_ADDR; + data = (value | UDA134X_EXTDATA_PREFIX); + break; + } + + ret = l3_write(&pd->l3, + addr, &data, 1); + if (ret != 1) + return -EIO; + + return 0; +} + +static inline void uda134x_reset(struct snd_soc_codec *codec) +{ + u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0); + uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6)); + msleep(1); + uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6)); +} + +static int uda134x_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010); + + pr_debug("%s mute: %d\n", __func__, mute); + + if (mute) + mute_reg |= (1<<2); + else + mute_reg &= ~(1<<2); + + uda134x_write(codec, UDA134X_DATA010, mute_reg & ~(1<<2)); + + return 0; +} + +static int uda134x_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct uda134x_priv *uda134x = codec->private_data; + struct snd_pcm_runtime *master_runtime; + + if (uda134x->master_substream) { + master_runtime = uda134x->master_substream->runtime; + + pr_debug("%s constraining to %d bits at %d\n", __func__, + master_runtime->sample_bits, + master_runtime->rate); + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, + master_runtime->rate, + master_runtime->rate); + + snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + master_runtime->sample_bits, + master_runtime->sample_bits); + + uda134x->slave_substream = substream; + } else + uda134x->master_substream = substream; + + return 0; +} + +static void uda134x_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct uda134x_priv *uda134x = codec->private_data; + + if (uda134x->master_substream == substream) + uda134x->master_substream = uda134x->slave_substream; + + uda134x->slave_substream = NULL; +} + +static int uda134x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->codec; + struct uda134x_priv *uda134x = codec->private_data; + u8 hw_params; + + if (substream == uda134x->slave_substream) { + pr_debug("%s ignoring hw_params for slave substream\n", + __func__); + return 0; + } + + hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0); + hw_params &= STATUS0_SYSCLK_MASK; + hw_params &= STATUS0_DAIFMT_MASK; + + pr_debug("%s sysclk: %d, rate:%d\n", __func__, + uda134x->sysclk, params_rate(params)); + + /* set SYSCLK / fs ratio */ + switch (uda134x->sysclk / params_rate(params)) { + case 512: + break; + case 384: + hw_params |= (1<<4); + break; + case 256: + hw_params |= (1<<5); + break; + default: + printk(KERN_ERR "%s unsupported fs\n", __func__); + return -EINVAL; + } + + pr_debug("%s dai_fmt: %d, params_format:%d\n", __func__, + uda134x->dai_fmt, params_format(params)); + + /* set DAI format and word length */ + switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + hw_params |= (1<<1); + break; + case SNDRV_PCM_FORMAT_S18_3LE: + hw_params |= (1<<2); + break; + case SNDRV_PCM_FORMAT_S20_3LE: + hw_params |= ((1<<2) | (1<<1)); + break; + default: + printk(KERN_ERR "%s unsupported format (right)\n", + __func__); + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_LEFT_J: + hw_params |= (1<<3); + break; + default: + printk(KERN_ERR "%s unsupported format\n", __func__); + return -EINVAL; + } + + uda134x_write(codec, UDA134X_STATUS0, hw_params); + + return 0; +} + +static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct uda134x_priv *uda134x = codec->private_data; + + pr_debug("%s clk_id: %d, freq: %d, dir: %d\n", __func__, + clk_id, freq, dir); + + /* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable + because the codec is slave. Of course limitations of the clock + master (the IIS controller) apply. + We'll error out on set_hw_params if it's not OK */ + if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { + uda134x->sysclk = freq; + return 0; + } + + printk(KERN_ERR "%s unsupported sysclk\n", __func__); + return -EINVAL; +} + +static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct uda134x_priv *uda134x = codec->private_data; + + pr_debug("%s fmt: %08X\n", __func__, fmt); + + /* codec supports only full slave mode */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + printk(KERN_ERR "%s unsupported slave mode\n", __func__); + return -EINVAL; + } + + /* no support for clock inversion */ + if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) { + printk(KERN_ERR "%s unsupported clock inversion\n", __func__); + return -EINVAL; + } + + /* We can't setup DAI format here as it depends on the word bit num */ + /* so let's just store the value for later */ + uda134x->dai_fmt = fmt; + + return 0; +} + +static int uda134x_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + u8 reg; + struct uda134x_platform_data *pd = codec->control_data; + int i; + u8 *cache = codec->reg_cache; + + pr_debug("%s bias level %d\n", __func__, level); + + switch (level) { + case SND_SOC_BIAS_ON: + /* ADC, DAC on */ + reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); + uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); + break; + case SND_SOC_BIAS_PREPARE: + /* power on */ + if (pd->power) { + pd->power(1); + /* Sync reg_cache with the hardware */ + for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++) + codec->write(codec, i, *cache++); + } + break; + case SND_SOC_BIAS_STANDBY: + /* ADC, DAC power off */ + reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); + uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); + break; + case SND_SOC_BIAS_OFF: + /* power off */ + if (pd->power) + pd->power(0); + break; + } + codec->bias_level = level; + return 0; +} + +static const char *uda134x_dsp_setting[] = {"Flat", "Minimum1", + "Minimum2", "Maximum"}; +static const char *uda134x_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; +static const char *uda134x_mixmode[] = {"Differential", "Analog1", + "Analog2", "Both"}; + +static const struct soc_enum uda134x_mixer_enum[] = { +SOC_ENUM_SINGLE(UDA134X_DATA010, 0, 0x04, uda134x_dsp_setting), +SOC_ENUM_SINGLE(UDA134X_DATA010, 3, 0x04, uda134x_deemph), +SOC_ENUM_SINGLE(UDA134X_EA010, 0, 0x04, uda134x_mixmode), +}; + +static const struct snd_kcontrol_new uda1341_snd_controls[] = { +SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), +SOC_SINGLE("Capture Volume", UDA134X_EA010, 2, 0x07, 0), +SOC_SINGLE("Analog1 Volume", UDA134X_EA000, 0, 0x1F, 1), +SOC_SINGLE("Analog2 Volume", UDA134X_EA001, 0, 0x1F, 1), + +SOC_SINGLE("Mic Sensitivity", UDA134X_EA010, 2, 7, 0), +SOC_SINGLE("Mic Volume", UDA134X_EA101, 0, 0x1F, 0), + +SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), +SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), + +SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), +SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), +SOC_ENUM("Input Mux", uda134x_mixer_enum[2]), + +SOC_SINGLE("AGC Switch", UDA134X_EA100, 4, 1, 0), +SOC_SINGLE("AGC Target Volume", UDA134X_EA110, 0, 0x03, 1), +SOC_SINGLE("AGC Timing", UDA134X_EA110, 2, 0x07, 0), + +SOC_SINGLE("DAC +6dB Switch", UDA134X_STATUS1, 6, 1, 0), +SOC_SINGLE("ADC +6dB Switch", UDA134X_STATUS1, 5, 1, 0), +SOC_SINGLE("ADC Polarity Switch", UDA134X_STATUS1, 4, 1, 0), +SOC_SINGLE("DAC Polarity Switch", UDA134X_STATUS1, 3, 1, 0), +SOC_SINGLE("Double Speed Playback Switch", UDA134X_STATUS1, 2, 1, 0), +SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), +}; + +static const struct snd_kcontrol_new uda1340_snd_controls[] = { +SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1), + +SOC_SINGLE("Tone Control - Bass", UDA134X_DATA001, 2, 0xF, 0), +SOC_SINGLE("Tone Control - Treble", UDA134X_DATA001, 0, 3, 0), + +SOC_ENUM("Sound Processing Filter", uda134x_mixer_enum[0]), +SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]), + +SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0), +}; + +static int uda134x_add_controls(struct snd_soc_codec *codec) +{ + int err, i, n; + const struct snd_kcontrol_new *ctrls; + struct uda134x_platform_data *pd = codec->control_data; + + switch (pd->model) { + case UDA134X_UDA1340: + case UDA134X_UDA1344: + n = ARRAY_SIZE(uda1340_snd_controls); + ctrls = uda1340_snd_controls; + break; + case UDA134X_UDA1341: + n = ARRAY_SIZE(uda1341_snd_controls); + ctrls = uda1341_snd_controls; + break; + default: + printk(KERN_ERR "%s unkown codec type: %d", + __func__, pd->model); + return -EINVAL; + } + + for (i = 0; i < n; i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&ctrls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +struct snd_soc_dai uda134x_dai = { + .name = "UDA134X", + /* playback capabilities */ + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = UDA134X_RATES, + .formats = UDA134X_FORMATS, + }, + /* capture capabilities */ + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = UDA134X_RATES, + .formats = UDA134X_FORMATS, + }, + /* pcm operations */ + .ops = { + .startup = uda134x_startup, + .shutdown = uda134x_shutdown, + .hw_params = uda134x_hw_params, + }, + /* DAI operations */ + .dai_ops = { + .digital_mute = uda134x_mute, + .set_sysclk = uda134x_set_dai_sysclk, + .set_fmt = uda134x_set_dai_fmt, + } +}; +EXPORT_SYMBOL(uda134x_dai); + + +static int uda134x_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct uda134x_priv *uda134x; + void *codec_setup_data = socdev->codec_data; + int ret = -ENOMEM; + struct uda134x_platform_data *pd; + + printk(KERN_INFO "UDA134X SoC Audio Codec\n"); + + if (!codec_setup_data) { + printk(KERN_ERR "UDA134X SoC codec: " + "missing L3 bitbang function\n"); + return -ENODEV; + } + + pd = codec_setup_data; + switch (pd->model) { + case UDA134X_UDA1340: + case UDA134X_UDA1341: + case UDA134X_UDA1344: + break; + default: + printk(KERN_ERR "UDA134X SoC codec: " + "unsupported model %d\n", + pd->model); + return -EINVAL; + } + + socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (socdev->codec == NULL) + return ret; + + codec = socdev->codec; + + uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); + if (uda134x == NULL) + goto priv_err; + codec->private_data = uda134x; + + codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg), + GFP_KERNEL); + if (codec->reg_cache == NULL) + goto reg_err; + + mutex_init(&codec->mutex); + + codec->reg_cache_size = sizeof(uda134x_reg); + codec->reg_cache_step = 1; + + codec->name = "UDA134X"; + codec->owner = THIS_MODULE; + codec->dai = &uda134x_dai; + codec->num_dai = 1; + codec->read = uda134x_read_reg_cache; + codec->write = uda134x_write; +#ifdef POWER_OFF_ON_STANDBY + codec->set_bias_level = uda134x_set_bias_level; +#endif + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->control_data = codec_setup_data; + + if (pd->power) + pd->power(1); + + uda134x_reset(codec); + + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "UDA134X: failed to register pcms\n"); + goto pcm_err; + } + + ret = uda134x_add_controls(codec); + if (ret < 0) { + printk(KERN_ERR "UDA134X: failed to register controls\n"); + goto pcm_err; + } + + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "UDA134X: failed to register card\n"); + goto card_err; + } + + return 0; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + kfree(codec->reg_cache); +reg_err: + kfree(codec->private_data); +priv_err: + kfree(codec); + return ret; +} + +/* power down chip */ +static int uda134x_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + kfree(codec->private_data); + kfree(codec->reg_cache); + kfree(codec); + + return 0; +} + +#if defined(CONFIG_PM) +static int uda134x_soc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int uda134x_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); + uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); + return 0; +} +#else +#define uda134x_soc_suspend NULL +#define uda134x_soc_resume NULL +#endif /* CONFIG_PM */ + +struct snd_soc_codec_device soc_codec_dev_uda134x = { + .probe = uda134x_soc_probe, + .remove = uda134x_soc_remove, + .suspend = uda134x_soc_suspend, + .resume = uda134x_soc_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); + +MODULE_DESCRIPTION("UDA134X ALSA soc codec driver"); +MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x_codec.h b/sound/soc/codecs/uda134x_codec.h new file mode 100644 index 000000000000..94f440490b31 --- /dev/null +++ b/sound/soc/codecs/uda134x_codec.h @@ -0,0 +1,36 @@ +#ifndef _UDA134X_CODEC_H +#define _UDA134X_CODEC_H + +#define UDA134X_L3ADDR 5 +#define UDA134X_DATA0_ADDR ((UDA134X_L3ADDR << 2) | 0) +#define UDA134X_DATA1_ADDR ((UDA134X_L3ADDR << 2) | 1) +#define UDA134X_STATUS_ADDR ((UDA134X_L3ADDR << 2) | 2) + +#define UDA134X_EXTADDR_PREFIX 0xC0 +#define UDA134X_EXTDATA_PREFIX 0xE0 + +/* UDA134X registers */ +#define UDA134X_EA000 0 +#define UDA134X_EA001 1 +#define UDA134X_EA010 2 +#define UDA134X_EA011 3 +#define UDA134X_EA100 4 +#define UDA134X_EA101 5 +#define UDA134X_EA110 6 +#define UDA134X_EA111 7 +#define UDA134X_STATUS0 8 +#define UDA134X_STATUS1 9 +#define UDA134X_DATA000 10 +#define UDA134X_DATA001 11 +#define UDA134X_DATA010 12 +#define UDA134X_DATA1 13 + +#define UDA134X_REGS_NUM 14 + +#define STATUS0_DAIFMT_MASK (~(7<<1)) +#define STATUS0_SYSCLK_MASK (~(3<<4)) + +extern struct snd_soc_dai uda134x_dai; +extern struct snd_soc_codec_device soc_codec_dev_uda134x; + +#endif From 7ad933d7a6677c20ce1bdb17425e732cf1ebee8a Mon Sep 17 00:00:00 2001 From: Christian Pellegrin Date: Sat, 15 Nov 2008 08:58:32 +0100 Subject: [PATCH 102/367] ASoC: Machine driver for for s3c24xx with uda134x Signed-off-by: Christian Pellegrin Signed-off-by: Mark Brown --- include/sound/s3c24xx_uda134x.h | 14 ++ sound/soc/s3c24xx/Kconfig | 5 + sound/soc/s3c24xx/Makefile | 2 + sound/soc/s3c24xx/s3c24xx_uda134x.c | 374 ++++++++++++++++++++++++++++ 4 files changed, 395 insertions(+) create mode 100644 include/sound/s3c24xx_uda134x.h create mode 100644 sound/soc/s3c24xx/s3c24xx_uda134x.c diff --git a/include/sound/s3c24xx_uda134x.h b/include/sound/s3c24xx_uda134x.h new file mode 100644 index 000000000000..33df4cb909d3 --- /dev/null +++ b/include/sound/s3c24xx_uda134x.h @@ -0,0 +1,14 @@ +#ifndef _S3C24XX_UDA134X_H_ +#define _S3C24XX_UDA134X_H_ 1 + +#include + +struct s3c24xx_uda134x_platform_data { + int l3_clk; + int l3_mode; + int l3_data; + void (*power) (int); + int model; +}; + +#endif diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index b9f2353effeb..fcd03acf10f6 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig @@ -44,3 +44,8 @@ config SND_S3C24XX_SOC_LN2440SBC_ALC650 Say Y if you want to add support for SoC audio on ln2440sbc with the ALC650. +config SND_S3C24XX_SOC_S3C24XX_UDA134X + tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" + depends on SND_S3C24XX_SOC + select SND_S3C24XX_SOC_I2S + select SND_SOC_UDA134X diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 0aa5fb0b9700..96b3f3f617d4 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile @@ -13,7 +13,9 @@ obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o +snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o +obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c new file mode 100644 index 000000000000..29a68132f169 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -0,0 +1,374 @@ +/* + * Modifications by Christian Pellegrin + * + * s3c24xx_uda134x.c -- S3C24XX_UDA134X ALSA SoC Audio board driver + * + * Copyright 2007 Dension Audio Systems Ltd. + * Author: Zoltan Devai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "s3c24xx-pcm.h" +#include "s3c24xx-i2s.h" +#include "../codecs/uda134x_codec.h" + + +/* #define ENFORCE_RATES 1 */ +/* + Unfortunately the S3C24XX in master mode has a limited capacity of + generating the clock for the codec. If you define this only rates + that are really available will be enforced. But be careful, most + user level application just want the usual sampling frequencies (8, + 11.025, 22.050, 44.1 kHz) and anyway resampling is a costly + operation for embedded systems. So if you aren't very lucky or your + hardware engineer wasn't very forward-looking it's better to leave + this undefined. If you do so an approximate value for the requested + sampling rate in the range -/+ 5% will be chosen. If this in not + possible an error will be returned. +*/ + +static struct clk *xtal; +static struct clk *pclk; +/* this is need because we don't have a place where to keep the + * pointers to the clocks in each substream. We get the clocks only + * when we are actually using them so we don't block stuff like + * frequency change or oscillator power-off */ +static int clk_users; +static DEFINE_MUTEX(clk_lock); + +static unsigned int rates[33 * 2]; +#ifdef ENFORCE_RATES +static struct snd_pcm_hw_constraint_list hw_constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; +#endif + +static struct platform_device *s3c24xx_uda134x_snd_device; + +int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; +#ifdef ENFORCE_RATES + struct snd_pcm_runtime *runtime = substream->runtime;; +#endif + + mutex_lock(&clk_lock); + pr_debug("%s %d\n", __func__, clk_users); + if (clk_users == 0) { + xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal"); + if (!xtal) { + printk(KERN_ERR "%s cannot get xtal\n", __func__); + ret = -EBUSY; + } else { + pclk = clk_get(&s3c24xx_uda134x_snd_device->dev, + "pclk"); + if (!pclk) { + printk(KERN_ERR "%s cannot get pclk\n", + __func__); + clk_put(xtal); + ret = -EBUSY; + } + } + if (!ret) { + int i, j; + + for (i = 0; i < 2; i++) { + int fs = i ? 256 : 384; + + rates[i*33] = clk_get_rate(xtal) / fs; + for (j = 1; j < 33; j++) + rates[i*33 + j] = clk_get_rate(pclk) / + (j * fs); + } + } + } + clk_users += 1; + mutex_unlock(&clk_lock); + if (!ret) { +#ifdef ENFORCE_RATES + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &hw_constraints_rates); + if (ret < 0) + printk(KERN_ERR "%s cannot set constraints\n", + __func__); +#endif + } + return ret; +} + +void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) +{ + mutex_lock(&clk_lock); + pr_debug("%s %d\n", __func__, clk_users); + clk_users -= 1; + if (clk_users == 0) { + clk_put(xtal); + xtal = NULL; + clk_put(pclk); + pclk = NULL; + } + mutex_unlock(&clk_lock); +} + +static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int clk = 0; + int ret = 0; + int clk_source, fs_mode; + unsigned long rate = params_rate(params); + long err, cerr; + unsigned int div; + int i, bi; + + err = 999999; + bi = 0; + for (i = 0; i < 2*33; i++) { + cerr = rates[i] - rate; + if (cerr < 0) + cerr = -cerr; + if (cerr < err) { + err = cerr; + bi = i; + } + } + if (bi / 33 == 1) + fs_mode = S3C2410_IISMOD_256FS; + else + fs_mode = S3C2410_IISMOD_384FS; + if (bi % 33 == 0) { + clk_source = S3C24XX_CLKSRC_MPLL; + div = 1; + } else { + clk_source = S3C24XX_CLKSRC_PCLK; + div = bi % 33; + } + pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi); + + clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate; + pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__, + fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS", + clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK", + div, clk, err); + + if ((err * 100 / rate) > 5) { + printk(KERN_ERR "S3C24XX_UDA134X: effective frequency " + "too different from desired (%ld%%)\n", + err * 100 / rate); + return -EINVAL; + } + + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, clk_source , clk, + SND_SOC_CLOCK_IN); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, + fs_mode); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, + S3C2410_IISMOD_32FS); + if (ret < 0) + return ret; + + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, + S3C24XX_PRESCALE(div, div)); + if (ret < 0) + return ret; + + /* set the codec system clock for DAC and ADC */ + ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, clk, + SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops s3c24xx_uda134x_ops = { + .startup = s3c24xx_uda134x_startup, + .shutdown = s3c24xx_uda134x_shutdown, + .hw_params = s3c24xx_uda134x_hw_params, +}; + +static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { + .name = "UDA134X", + .stream_name = "UDA134X", + .codec_dai = &uda134x_dai, + .cpu_dai = &s3c24xx_i2s_dai, + .ops = &s3c24xx_uda134x_ops, +}; + +static struct snd_soc_machine snd_soc_machine_s3c24xx_uda134x = { + .name = "S3C24XX_UDA134X", + .dai_link = &s3c24xx_uda134x_dai_link, + .num_links = 1, +}; + +static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins; + +static void setdat(int v) +{ + gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0); +} + +static void setclk(int v) +{ + gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0); +} + +static void setmode(int v) +{ + gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0); +} + +static struct uda134x_platform_data s3c24xx_uda134x = { + .l3 = { + .setdat = setdat, + .setclk = setclk, + .setmode = setmode, + .data_hold = 1, + .data_setup = 1, + .clock_high = 1, + .mode_hold = 1, + .mode = 1, + .mode_setup = 1, + }, +}; + +static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { + .machine = &snd_soc_machine_s3c24xx_uda134x, + .platform = &s3c24xx_soc_platform, + .codec_dev = &soc_codec_dev_uda134x, + .codec_data = &s3c24xx_uda134x, +}; + +static int s3c24xx_uda134x_setup_pin(int pin, char *fun) +{ + if (gpio_request(pin, "s3c24xx_uda134x") < 0) { + printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " + "l3 %s pin already in use", fun); + return -EBUSY; + } + gpio_direction_output(pin, 0); + return 0; +} + +static int s3c24xx_uda134x_probe(struct platform_device *pdev) +{ + int ret; + + printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n"); + + s3c24xx_uda134x_l3_pins = pdev->dev.platform_data; + if (s3c24xx_uda134x_l3_pins == NULL) { + printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " + "unable to find platform data\n"); + return -ENODEV; + } + s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power; + s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model; + + if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data, + "data") < 0) + return -EBUSY; + if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk, + "clk") < 0) { + gpio_free(s3c24xx_uda134x_l3_pins->l3_data); + return -EBUSY; + } + if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, + "mode") < 0) { + gpio_free(s3c24xx_uda134x_l3_pins->l3_data); + gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); + return -EBUSY; + } + + s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1); + if (!s3c24xx_uda134x_snd_device) { + printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " + "Unable to register\n"); + return -ENOMEM; + } + + platform_set_drvdata(s3c24xx_uda134x_snd_device, + &s3c24xx_uda134x_snd_devdata); + s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev; + ret = platform_device_add(s3c24xx_uda134x_snd_device); + if (ret) { + printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n"); + platform_device_put(s3c24xx_uda134x_snd_device); + } + + return ret; +} + +static int s3c24xx_uda134x_remove(struct platform_device *pdev) +{ + platform_device_unregister(s3c24xx_uda134x_snd_device); + gpio_free(s3c24xx_uda134x_l3_pins->l3_data); + gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); + gpio_free(s3c24xx_uda134x_l3_pins->l3_mode); + return 0; +} + +static struct platform_driver s3c24xx_uda134x_driver = { + .probe = s3c24xx_uda134x_probe, + .remove = s3c24xx_uda134x_remove, + .driver = { + .name = "s3c24xx_uda134x", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c24xx_uda134x_init(void) +{ + return platform_driver_register(&s3c24xx_uda134x_driver); +} + +static void __exit s3c24xx_uda134x_exit(void) +{ + platform_driver_unregister(&s3c24xx_uda134x_driver); +} + + +module_init(s3c24xx_uda134x_init); +module_exit(s3c24xx_uda134x_exit); + +MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); +MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver"); +MODULE_LICENSE("GPL"); From ba533e95b929c577d69237692ee588001347be8a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Nov 2008 16:59:24 +0000 Subject: [PATCH 103/367] ASoC: Allow writes to uncached registers in WM8990 Only fully documented registers are cached in the WM8990 but additional registers exist. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8990.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 572d22b0880b..5c84f02c4579 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -106,6 +106,7 @@ static const u16 wm8990_reg[] = { 0x0008, /* R60 - PLL1 */ 0x0031, /* R61 - PLL2 */ 0x0026, /* R62 - PLL3 */ + 0x0000, /* R63 - Driver internal */ }; /* @@ -126,10 +127,9 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u16 *cache = codec->reg_cache; - BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); - /* Reset register is uncached */ - if (reg == 0) + /* Reset register and reserved registers are uncached */ + if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1) return; cache[reg] = value; From be1b87c70af69acfadb8a27a7a76dfb61de92643 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Nov 2008 17:09:34 +0000 Subject: [PATCH 104/367] ASoC: Enable WM8990 ADC clocking workaround Enable a hardware workaround which avoids problems with the clocking of the ADCs in certain configurations. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8990.c | 6 ++++-- sound/soc/codecs/wm8990.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 5c84f02c4579..938e15429207 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1272,9 +1272,11 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); - } else { - /* ON -> standby */ + /* Enable workaround for ADC clocking issue. */ + wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); + wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); + wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); } break; diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h index 0e192f3b0788..7114ddc88b4b 100644 --- a/sound/soc/codecs/wm8990.h +++ b/sound/soc/codecs/wm8990.h @@ -80,8 +80,8 @@ #define WM8990_PLL3 0x3E #define WM8990_INTDRIVBITS 0x3F -#define WM8990_REGISTER_COUNT 60 -#define WM8990_MAX_REGISTER 0x3F +#define WM8990_EXT_ACCESS_ENA 0x75 +#define WM8990_EXT_CTL1 0x7a /* * Field Definitions. From 2adb9833d1782262c20b21457d645163928cf2a2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Nov 2008 17:11:14 +0000 Subject: [PATCH 105/367] ASoC: Manage VMID mode for WM8990 A small additional power saving can be achieved for the WM8990 by maintaining VMID using a 2*250k divider when in standby mode. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8990.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 938e15429207..2d7b0096d929 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1222,8 +1222,14 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: break; + case SND_SOC_BIAS_PREPARE: + /* VMID=2*50k */ + val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & + ~WM8990_VMID_MODE_MASK; + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); break; + case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Enable all output discharge bits */ @@ -1278,6 +1284,11 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); } + + /* VMID=2*250k */ + val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & + ~WM8990_VMID_MODE_MASK; + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); break; case SND_SOC_BIAS_OFF: From 8d702f2376d25ab277c38b57015f4aa990bc7f16 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 17 Nov 2008 21:42:01 +0000 Subject: [PATCH 106/367] ASoC: Build tlv320aic23 cleanly Also merge down a couple of last minute style changes that got lost in the shuffle. Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index a95b538b8fe7..c903e4f48dc4 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -331,10 +331,11 @@ static int find_rate(int mclk, u32 need_adc, u32 need_dac) adc_h = need_adc + (need_adc >> 5); dac_l = need_dac - (need_dac >> 5); dac_h = need_dac + (need_dac >> 5); - for (i = 0; i < 4; i++) { + for (i = 0; i < ARRAY_SIZE(bosr_usb_divisor_table); i++) { int base = mclk / bosr_usb_divisor_table[i]; int mask = sr_valid_mask[i]; - for (j = 0; j < 16; j++, mask >>= 1) { + for (j = 0; j < ARRAY_SIZE(sr_adc_mult_table); + j++, mask >>= 1) { int adc; int dac; int score; @@ -364,6 +365,7 @@ static int find_rate(int mclk, u32 need_adc, u32 need_dac) return (best_j << 2) | best_i | (best_div << TLV320AIC23_CLKIN_SHIFT); } +#ifdef DEBUG static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, u32 *sample_rate_adc, u32 *sample_rate_dac) { @@ -379,6 +381,7 @@ static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, *sample_rate_adc = adc; *sample_rate_dac = dac; } +#endif static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, u32 sample_rate_adc, u32 sample_rate_dac) @@ -391,12 +394,14 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, return -EINVAL; } tlv320aic23_write(codec, TLV320AIC23_SRATE, data); - if (1) { - int adc, dac; +#ifdef DEBUG + { + u32 adc, dac; get_current_sample_rates(codec, mclk, &adc, &dac); printk(KERN_DEBUG "actual samplerate = %u,%u reg=%x\n", adc, dac, data); } +#endif return 0; } From bc4a68fed4b4c01005ef3c71ede6a8cbe91b7dc9 Mon Sep 17 00:00:00 2001 From: Risto Suominen Date: Tue, 18 Nov 2008 07:35:14 +0100 Subject: [PATCH 107/367] ALSA: snd-powermac: enable mic on iMac G4 Allow input from microphone on iMac G4 Flat-panel (Tumbler). Signed-off-by: Risto Suominen Signed-off-by: Takashi Iwai --- sound/ppc/pmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index a38c0c790d2b..af76ee862d27 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -1033,7 +1033,7 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) } if (of_device_is_compatible(sound, "tumbler")) { chip->model = PMAC_TUMBLER; - chip->can_capture = 0; /* no capture */ + chip->can_capture = machine_is_compatible("PowerMac4,2"); chip->can_duplex = 0; // chip->can_byte_swap = 0; /* FIXME: check this */ chip->num_freqs = ARRAY_SIZE(tumbler_freqs); From 2eca83ba9cc6f811f8c63314b22b4bc0532e2207 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 18 Nov 2008 10:21:55 +0800 Subject: [PATCH 108/367] ALSA: hda: remove redundant get_amp_nid() Remove get_amp_nid(): it duplicates the one defined in hda_local.h Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 760e14ae3bff..05182be1c9f0 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -142,8 +142,6 @@ enum { AUTO_SEQ_SIDE }; -#define get_amp_nid(kc) ((kc)->private_value & 0xffff) - /* Some VT1708S based boards gets the micboost setting wrong, so we have * to apply some brute-force and re-write the TLV's by software. */ static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag, From 33deeca3bb6a945677d70876ea9d044fc5797eb3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 18 Nov 2008 11:47:51 +0800 Subject: [PATCH 109/367] ALSA: introduce snd_print_pcm_rates() We want to share some code with print_pcm_rates(), so extract a common routine snd_print_pcm_rates() from it. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_local.h | 3 +++ sound/pci/hda/hda_proc.c | 20 ++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index aac569b05599..d7e3a164effe 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -284,6 +284,9 @@ int snd_hda_codec_proc_new(struct hda_codec *codec); static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } #endif +#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 +void snd_print_pcm_rates(int pcm, char *buf, int buflen); + /* * Misc */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 64b6a38fa963..512eb674b743 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -89,20 +89,28 @@ static void print_amp_vals(struct snd_info_buffer *buffer, snd_iprintf(buffer, "\n"); } -static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) +void snd_print_pcm_rates(int pcm, char *buf, int buflen) { static unsigned int rates[] = { 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 384000 }; - int i; + int i, j; + for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) + if (pcm & (1 << i)) + j += snprintf(buf + j, buflen - j, " %d", rates[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) +{ + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; pcm &= AC_SUPPCM_RATES; snd_iprintf(buffer, " rates [0x%x]:", pcm); - for (i = 0; i < ARRAY_SIZE(rates); i++) - if (pcm & (1 << i)) - snd_iprintf(buffer, " %d", rates[i]); - snd_iprintf(buffer, "\n"); + snd_print_pcm_rates(pcm, buf, sizeof(buf)); + snd_iprintf(buffer, "%s\n", buf); } static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) From 7f4a9f43427793bfe4d42e71f42e2b551bcfe354 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 18 Nov 2008 11:47:52 +0800 Subject: [PATCH 110/367] ALSA: create hda_eld.c for ELD routines and proc interface ELD handling routines can be shared by all HDMI codecs, and they are large enough to make a standalone source file. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 4 + sound/pci/hda/Makefile | 1 + sound/pci/hda/hda_eld.c | 454 ++++++++++++++++++++++++++++++ sound/pci/hda/hda_local.h | 41 +++ sound/pci/hda/patch_intelhdmi.c | 480 +------------------------------- 5 files changed, 505 insertions(+), 475 deletions(-) create mode 100644 sound/pci/hda/hda_eld.c diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 21e9327a0ef4..157a0a6b10ae 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -582,6 +582,10 @@ config SND_HDA_CODEC_INTELHDMI Say Y here to include INTEL HDMI HD-audio codec support in snd-hda-intel driver, such as Eaglelake integrated HDMI. +config SND_HDA_ELD + def_bool y + depends on SND_HDA_CODEC_INTELHDMI + config SND_HDA_CODEC_CONEXANT bool "Build Conexant HD-audio codec support" depends on SND_HDA_INTEL diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 6fb5add1e39a..6daf5fd9a279 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -4,6 +4,7 @@ snd-hda-intel-y := hda_intel.o # designed to be individual modules snd-hda-intel-y += hda_codec.o snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o +snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c new file mode 100644 index 000000000000..a69a7e87d26a --- /dev/null +++ b/sound/pci/hda/hda_eld.c @@ -0,0 +1,454 @@ +/* + * Generic routines and proc interface for ELD(EDID Like Data) information + * + * Copyright(c) 2008 Intel Corporation. + * + * Authors: + * Wu Fengguang + * + * 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. + * + * This driver 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 +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + +enum eld_versions { + ELD_VER_CEA_861D = 2, + ELD_VER_PARTIAL = 31, +}; + +static char *eld_versoin_names[32] = { + "reserved", + "reserved", + "CEA-861D or below", + [3 ... 30] = "reserved", + [31] = "partial" +}; + +enum cea_edid_versions { + CEA_EDID_VER_NONE = 0, + CEA_EDID_VER_CEA861 = 1, + CEA_EDID_VER_CEA861A = 2, + CEA_EDID_VER_CEA861BCD = 3, + CEA_EDID_VER_RESERVED = 4, +}; + +static char *cea_edid_version_names[8] = { + "no CEA EDID Timing Extension block present", + "CEA-861", + "CEA-861-A", + "CEA-861-B, C or D", + [4 ... 7] = "reserved" +}; + +static char *cea_speaker_allocation_names[] = { + /* 0 */ "FL/FR", + /* 1 */ "LFE", + /* 2 */ "FC", + /* 3 */ "RL/RR", + /* 4 */ "RC", + /* 5 */ "FLC/FRC", + /* 6 */ "RLC/RRC", + /* 7 */ "FLW/FRW", + /* 8 */ "FLH/FRH", + /* 9 */ "TC", + /* 10 */ "FCH", +}; + +static char *eld_connection_type_names[4] = { + "HDMI", + "Display Port", + "2-reserved", + "3-reserved" +}; + +enum cea_audio_coding_types { + AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, + AUDIO_CODING_TYPE_LPCM = 1, + AUDIO_CODING_TYPE_AC3 = 2, + AUDIO_CODING_TYPE_MPEG1 = 3, + AUDIO_CODING_TYPE_MP3 = 4, + AUDIO_CODING_TYPE_MPEG2 = 5, + AUDIO_CODING_TYPE_AACLC = 6, + AUDIO_CODING_TYPE_DTS = 7, + AUDIO_CODING_TYPE_ATRAC = 8, + AUDIO_CODING_TYPE_SACD = 9, + AUDIO_CODING_TYPE_EAC3 = 10, + AUDIO_CODING_TYPE_DTS_HD = 11, + AUDIO_CODING_TYPE_MLP = 12, + AUDIO_CODING_TYPE_DST = 13, + AUDIO_CODING_TYPE_WMAPRO = 14, + AUDIO_CODING_TYPE_REF_CXT = 15, + /* also include valid xtypes below */ + AUDIO_CODING_TYPE_HE_AAC = 15, + AUDIO_CODING_TYPE_HE_AAC2 = 16, + AUDIO_CODING_TYPE_MPEG_SURROUND = 17, +}; + +enum cea_audio_coding_xtypes { + AUDIO_CODING_XTYPE_HE_REF_CT = 0, + AUDIO_CODING_XTYPE_HE_AAC = 1, + AUDIO_CODING_XTYPE_HE_AAC2 = 2, + AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, + AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, +}; + +static char *cea_audio_coding_type_names[] = { + /* 0 */ "undefined", + /* 1 */ "LPCM", + /* 2 */ "AC-3", + /* 3 */ "MPEG1", + /* 4 */ "MP3", + /* 5 */ "MPEG2", + /* 6 */ "AAC-LC", + /* 7 */ "DTS", + /* 8 */ "ATRAC", + /* 9 */ "DSD (1-bit audio)", + /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", + /* 11 */ "DTS-HD", + /* 12 */ "MLP (Dolby TrueHD)", + /* 13 */ "DST", + /* 14 */ "WMAPro", + /* 15 */ "HE-AAC", + /* 16 */ "HE-AACv2", + /* 17 */ "MPEG Surround", +}; + +/* + * The following two lists are shared between + * - HDMI audio InfoFrame (source to sink) + * - CEA E-EDID extension (sink to source) + */ + +/* + * SS1:SS0 index => sample size + */ +static int cea_sample_sizes[4] = { + 0, /* 0: Refer to Stream Header */ + AC_SUPPCM_BITS_16, /* 1: 16 bits */ + AC_SUPPCM_BITS_20, /* 2: 20 bits */ + AC_SUPPCM_BITS_24, /* 3: 24 bits */ +}; + +/* + * SF2:SF1:SF0 index => sampling frequency + */ +static int cea_sampling_frequencies[8] = { + 0, /* 0: Refer to Stream Header */ + SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ + SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ + SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ + SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ + SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ + SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ + SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ +}; + +static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, + int byte_index) +{ + unsigned int val; + + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_HDMI_ELDD, byte_index); + +#ifdef BE_PARANOID + printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); +#endif + + if ((val & AC_ELDD_ELD_VALID) == 0) { + snd_printd(KERN_INFO "Invalid ELD data byte %d\n", + byte_index); + val = 0; + } + + return val & AC_ELDD_ELD_DATA; +} + +#define GRAB_BITS(buf, byte, lowbit, bits) \ +({ \ + BUILD_BUG_ON(lowbit > 7); \ + BUILD_BUG_ON(bits > 8); \ + BUILD_BUG_ON(bits <= 0); \ + \ + (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ +}) + +static void hdmi_update_short_audio_desc(struct cea_sad *a, + const unsigned char *buf) +{ + int i; + int val; + + val = GRAB_BITS(buf, 1, 0, 7); + a->rates = 0; + for (i = 0; i < 7; i++) + if (val & (1 << i)) + a->rates |= cea_sampling_frequencies[i + 1]; + + a->channels = GRAB_BITS(buf, 0, 0, 3); + a->channels++; + + a->format = GRAB_BITS(buf, 0, 3, 4); + switch (a->format) { + case AUDIO_CODING_TYPE_REF_STREAM_HEADER: + snd_printd(KERN_INFO + "audio coding type 0 not expected in ELD\n"); + break; + + case AUDIO_CODING_TYPE_LPCM: + val = GRAB_BITS(buf, 2, 0, 3); + a->sample_bits = 0; + for (i = 0; i < 3; i++) + if (val & (1 << i)) + a->sample_bits |= cea_sample_sizes[i + 1]; + break; + + case AUDIO_CODING_TYPE_AC3: + case AUDIO_CODING_TYPE_MPEG1: + case AUDIO_CODING_TYPE_MP3: + case AUDIO_CODING_TYPE_MPEG2: + case AUDIO_CODING_TYPE_AACLC: + case AUDIO_CODING_TYPE_DTS: + case AUDIO_CODING_TYPE_ATRAC: + a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); + a->max_bitrate *= 8000; + break; + + case AUDIO_CODING_TYPE_SACD: + break; + + case AUDIO_CODING_TYPE_EAC3: + break; + + case AUDIO_CODING_TYPE_DTS_HD: + break; + + case AUDIO_CODING_TYPE_MLP: + break; + + case AUDIO_CODING_TYPE_DST: + break; + + case AUDIO_CODING_TYPE_WMAPRO: + a->profile = GRAB_BITS(buf, 2, 0, 3); + break; + + case AUDIO_CODING_TYPE_REF_CXT: + a->format = GRAB_BITS(buf, 2, 3, 5); + if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || + a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { + snd_printd(KERN_INFO + "audio coding xtype %d not expected in ELD\n", + a->format); + a->format = 0; + } else + a->format += AUDIO_CODING_TYPE_HE_AAC - + AUDIO_CODING_XTYPE_HE_AAC; + break; + } +} + +/* + * Be careful, ELD buf could be totally rubbish! + */ +static int hdmi_update_sink_eld(struct sink_eld *e, + const unsigned char *buf, int size) +{ + int mnl; + int i; + + e->eld_ver = GRAB_BITS(buf, 0, 3, 5); + if (e->eld_ver != ELD_VER_CEA_861D && + e->eld_ver != ELD_VER_PARTIAL) { + snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); + goto out_fail; + } + + e->eld_size = size; + e->baseline_len = GRAB_BITS(buf, 2, 0, 8); + mnl = GRAB_BITS(buf, 4, 0, 5); + e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); + + e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); + e->support_ai = GRAB_BITS(buf, 5, 1, 1); + e->conn_type = GRAB_BITS(buf, 5, 2, 2); + e->sad_count = GRAB_BITS(buf, 5, 4, 4); + + e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; + e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); + + e->port_id = get_unaligned_le64(buf + 8); + + /* not specified, but the spec's tendency is little endian */ + e->manufacture_id = get_unaligned_le16(buf + 16); + e->product_id = get_unaligned_le16(buf + 18); + + if (mnl > ELD_MAX_MNL) { + snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); + goto out_fail; + } else if (ELD_FIXED_BYTES + mnl > size) { + snd_printd(KERN_INFO "out of range MNL %d\n", mnl); + goto out_fail; + } else + strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); + + for (i = 0; i < e->sad_count; i++) { + if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { + snd_printd(KERN_INFO "out of range SAD %d\n", i); + goto out_fail; + } + hdmi_update_short_audio_desc(e->sad + i, + buf + ELD_FIXED_BYTES + mnl + 3 * i); + } + + return 0; + +out_fail: + e->eld_ver = 0; + return -EINVAL; +} + +static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); +} + +static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) +{ + int eldv; + int present; + + present = hdmi_present_sense(codec, nid); + eldv = (present & AC_PINSENSE_ELDV); + present = (present & AC_PINSENSE_PRESENCE); + +#ifdef CONFIG_SND_DEBUG_VERBOSE + printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); +#endif + + return eldv && present; +} + +int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, + AC_DIPSIZE_ELD_BUF); +} + +int snd_hdmi_get_eld(struct sink_eld *eld, + struct hda_codec *codec, hda_nid_t nid) +{ + int i; + int ret; + int size; + unsigned char *buf; + + if (!hdmi_eld_valid(codec, nid)) + return -ENOENT; + + size = snd_hdmi_get_eld_size(codec, nid); + if (size == 0) { + /* wfg: workaround for ASUS P5E-VM HDMI board */ + snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); + size = 128; + } + if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { + snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); + return -ERANGE; + } + + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < size; i++) + buf[i] = hdmi_get_eld_byte(codec, nid, i); + + ret = hdmi_update_sink_eld(eld, buf, size); + + kfree(buf); + return ret; +} + +static void hdmi_show_short_audio_desc(struct cea_sad *a) +{ + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + + printk(KERN_INFO "coding type: %s\n", + cea_audio_coding_type_names[a->format]); + printk(KERN_INFO "channels: %d\n", a->channels); + + snd_print_pcm_rates(a->rates, buf, sizeof(buf)); + printk(KERN_INFO "sampling frequencies: %s\n", buf); + + if (a->format == AUDIO_CODING_TYPE_LPCM) + printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); + + if (a->max_bitrate) + printk(KERN_INFO "max bitrate: %d\n", a->max_bitrate); + + if (a->profile) + printk(KERN_INFO "profile: %d\n", a->profile); +} + +#define HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 +static void hdmi_print_channel_allocation(int spk_alloc, char *buf, int buflen) +{ + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { + if (spk_alloc & (1 << i)) + j += snprintf(buf + j, buflen - j, "%s ", + cea_speaker_allocation_names[i]); + } + if (j) + j--; /* skip last space */ + buf[j] = '\0'; /* necessary when j == 0 */ +} + +void snd_hdmi_show_eld(struct sink_eld *e) +{ + int i; + char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); + printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); + printk(KERN_INFO "vendor block len is %d\n", + e->eld_size - e->baseline_len * 4 - 4); + printk(KERN_INFO "ELD version is %s\n", + eld_versoin_names[e->eld_ver]); + printk(KERN_INFO "CEA EDID version is %s\n", + cea_edid_version_names[e->cea_edid_ver]); + printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); + printk(KERN_INFO "product id is 0x%x\n", e->product_id); + printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); + printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); + printk(KERN_INFO "AI support is %d\n", e->support_ai); + printk(KERN_INFO "SAD count is %d\n", e->sad_count); + printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); + printk(KERN_INFO "connection type is %s\n", + eld_connection_type_names[e->conn_type]); + printk(KERN_INFO "monitor name is %s\n", e->monitor_name); + + hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); + + for (i = 0; i < e->sad_count; i++) + hdmi_show_short_audio_desc(e->sad + i); +} diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index d7e3a164effe..e1b76686672a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -443,4 +443,45 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) +/* + * CEA Short Audio Descriptor data + */ +struct cea_sad { + int channels; + int format; /* (format == 0) indicates invalid SAD */ + int rates; + int sample_bits; /* for LPCM */ + int max_bitrate; /* for AC3...ATRAC */ + int profile; /* for WMAPRO */ +}; + +#define ELD_FIXED_BYTES 20 +#define ELD_MAX_MNL 16 +#define ELD_MAX_SAD 16 + +/* + * ELD: EDID Like Data + */ +struct sink_eld { + int eld_size; + int baseline_len; + int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ + int cea_edid_ver; + char monitor_name[ELD_MAX_MNL + 1]; + int manufacture_id; + int product_id; + u64 port_id; + int support_hdcp; + int support_ai; + int conn_type; + int aud_synch_delay; + int spk_alloc; + int sad_count; + struct cea_sad sad[ELD_MAX_SAD]; +}; + +int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); +int snd_hdmi_get_eld(struct sink_eld *, struct hda_codec *, hda_nid_t); +void snd_hdmi_show_eld(struct sink_eld *eld); + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index d99cd6297249..489278d3d773 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "hda_codec.h" #include "hda_local.h" #include "hda_patch.h" @@ -40,43 +39,6 @@ #define INTEL_HDMI_EVENT_TAG 0x08 -/* - * CEA Short Audio Descriptor data - */ -struct cea_sad { - int channels; - int format; /* (format == 0) indicates invalid SAD */ - int rates; - int sample_bits; /* for LPCM */ - int max_bitrate; /* for AC3...ATRAC */ - int profile; /* for WMAPRO */ -}; - -#define ELD_FIXED_BYTES 20 -#define ELD_MAX_MNL 16 -#define ELD_MAX_SAD 16 - -/* - * ELD: EDID Like Data - */ -struct sink_eld { - int eld_size; - int baseline_len; - int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ - int cea_edid_ver; - char monitor_name[ELD_MAX_MNL + 1]; - int manufacture_id; - int product_id; - u64 port_id; - int support_hdcp; - int support_ai; - int conn_type; - int aud_synch_delay; - int spk_alloc; - int sad_count; - struct cea_sad sad[ELD_MAX_SAD]; -}; - struct intel_hdmi_spec { struct hda_multi_out multiout; struct hda_pcm pcm_rec; @@ -126,161 +88,10 @@ struct hdmi_audio_infoframe { u8 reserved[5]; /* PB6 - PB10 */ }; -/* - * SS1:SS0 index => sample size - */ -static int cea_sample_sizes[4] = { - 0, /* 0: Refer to Stream Header */ - AC_SUPPCM_BITS_16, /* 1: 16 bits */ - AC_SUPPCM_BITS_20, /* 2: 20 bits */ - AC_SUPPCM_BITS_24, /* 3: 24 bits */ -}; - -/* - * SF2:SF1:SF0 index => sampling frequency - */ -static int cea_sampling_frequencies[8] = { - 0, /* 0: Refer to Stream Header */ - SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ - SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ - SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ - SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ - SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ - SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ - SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ -}; - -enum eld_versions { - ELD_VER_CEA_861D = 2, - ELD_VER_PARTIAL = 31, -}; - -static char *eld_versoin_names[32] = { - "0-reserved", - "1-reserved", - "CEA-861D or below", - "3-reserved", - [4 ... 30] = "reserved", - [31] = "partial" -}; - -enum cea_edid_versions { - CEA_EDID_VER_NONE = 0, - CEA_EDID_VER_CEA861 = 1, - CEA_EDID_VER_CEA861A = 2, - CEA_EDID_VER_CEA861BCD = 3, - CEA_EDID_VER_RESERVED = 4, -}; - -static char *cea_edid_version_names[8] = { - "no CEA EDID Timing Extension block present", - "CEA-861", - "CEA-861-A", - "CEA-861-B, C or D", - "4-reserved", - [5 ... 7] = "reserved" -}; - -/* - * CEA Speaker Allocation data block bits - */ -#define CEA_SA_FLR (0 << 0) -#define CEA_SA_LFE (1 << 1) -#define CEA_SA_FC (1 << 2) -#define CEA_SA_RLR (1 << 3) -#define CEA_SA_RC (1 << 4) -#define CEA_SA_FLRC (1 << 5) -#define CEA_SA_RLRC (1 << 6) -/* the following are not defined in ELD yet */ -#define CEA_SA_FLRW (1 << 7) -#define CEA_SA_FLRH (1 << 8) -#define CEA_SA_TC (1 << 9) -#define CEA_SA_FCH (1 << 10) - -static char *cea_speaker_allocation_names[] = { - /* 0 */ "FL/FR", - /* 1 */ "LFE", - /* 2 */ "FC", - /* 3 */ "RL/RR", - /* 4 */ "RC", - /* 5 */ "FLC/FRC", - /* 6 */ "RLC/RRC", - /* 7 */ "FLW/FRW", - /* 8 */ "FLH/FRH", - /* 9 */ "TC", - /* 10 */ "FCH", -}; - -static char *eld_connection_type_names[4] = { - "HDMI", - "Display Port", - "2-reserved", - "3-reserved" -}; - -enum cea_audio_coding_types { - AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, - AUDIO_CODING_TYPE_LPCM = 1, - AUDIO_CODING_TYPE_AC3 = 2, - AUDIO_CODING_TYPE_MPEG1 = 3, - AUDIO_CODING_TYPE_MP3 = 4, - AUDIO_CODING_TYPE_MPEG2 = 5, - AUDIO_CODING_TYPE_AACLC = 6, - AUDIO_CODING_TYPE_DTS = 7, - AUDIO_CODING_TYPE_ATRAC = 8, - AUDIO_CODING_TYPE_SACD = 9, - AUDIO_CODING_TYPE_EAC3 = 10, - AUDIO_CODING_TYPE_DTS_HD = 11, - AUDIO_CODING_TYPE_MLP = 12, - AUDIO_CODING_TYPE_DST = 13, - AUDIO_CODING_TYPE_WMAPRO = 14, - AUDIO_CODING_TYPE_REF_CXT = 15, - /* also include valid xtypes below */ - AUDIO_CODING_TYPE_HE_AAC = 15, - AUDIO_CODING_TYPE_HE_AAC2 = 16, - AUDIO_CODING_TYPE_MPEG_SURROUND = 17, -}; - -enum cea_audio_coding_xtypes { - AUDIO_CODING_XTYPE_HE_REF_CT = 0, - AUDIO_CODING_XTYPE_HE_AAC = 1, - AUDIO_CODING_XTYPE_HE_AAC2 = 2, - AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, - AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, -}; - -static char *cea_audio_coding_type_names[] = { - /* 0 */ "undefined", - /* 1 */ "LPCM", - /* 2 */ "AC-3", - /* 3 */ "MPEG1", - /* 4 */ "MP3", - /* 5 */ "MPEG2", - /* 6 */ "AAC-LC", - /* 7 */ "DTS", - /* 8 */ "ATRAC", - /* 9 */ "DSD(1-bit audio)", - /* 10 */ "Dolby Digital Plus(E-AC-3/DD+)", - /* 11 */ "DTS-HD", - /* 12 */ "Dolby TrueHD(MLP)", - /* 13 */ "DST", - /* 14 */ "WMAPro", - /* 15 */ "HE-AAC", - /* 16 */ "HE-AACv2", - /* 17 */ "MPEG Surround", -}; - - /* * HDMI routines */ -static int hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, - AC_DIPSIZE_ELD_BUF); -} - #ifdef BE_PARANOID static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, int *packet_index, int *byte_index) @@ -375,294 +186,13 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec) } -/* - * ELD(EDID Like Data) routines - */ - -static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); -} - -static void hdmi_debug_present_sense(struct hda_codec *codec) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int eldv; - int present; - - present = hdmi_present_sense(codec, PIN_NID); - eldv = (present & AC_PINSENSE_ELDV); - present = (present & AC_PINSENSE_PRESENCE); - - printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); -#endif -} - -static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, int byte_index) -{ - unsigned int val; - - val = snd_hda_codec_read(codec, PIN_NID, 0, - AC_VERB_GET_HDMI_ELDD, byte_index); - -#ifdef BE_PARANOID - printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); -#endif - - if ((val & AC_ELDD_ELD_VALID) == 0) { - snd_printd(KERN_INFO "Invalid ELD data byte %d\n", - byte_index); - val = 0; - } - - return val & AC_ELDD_ELD_DATA; -} - -static inline unsigned char grab_bits(const unsigned char *buf, - int byte, int lowbit, int bits) -{ - BUG_ON(lowbit > 7); - BUG_ON(bits > 8); - BUG_ON(bits <= 0); - - return (buf[byte] >> lowbit) & ((1 << bits) - 1); -} - -static void hdmi_update_short_audio_desc(struct cea_sad *a, - const unsigned char *buf) -{ - int i; - int val; - - val = grab_bits(buf, 1, 0, 7); - a->rates = 0; - for (i = 0; i < 7; i++) - if (val & (1 << i)) - a->rates |= cea_sampling_frequencies[i + 1]; - - a->channels = grab_bits(buf, 0, 0, 3); - a->channels++; - - a->format = grab_bits(buf, 0, 3, 4); - switch (a->format) { - case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - snd_printd(KERN_INFO - "audio coding type 0 not expected in ELD\n"); - break; - - case AUDIO_CODING_TYPE_LPCM: - val = grab_bits(buf, 2, 0, 3); - a->sample_bits = 0; - for (i = 0; i < 3; i++) - if (val & (1 << i)) - a->sample_bits |= cea_sample_sizes[i + 1]; - break; - - case AUDIO_CODING_TYPE_AC3: - case AUDIO_CODING_TYPE_MPEG1: - case AUDIO_CODING_TYPE_MP3: - case AUDIO_CODING_TYPE_MPEG2: - case AUDIO_CODING_TYPE_AACLC: - case AUDIO_CODING_TYPE_DTS: - case AUDIO_CODING_TYPE_ATRAC: - a->max_bitrate = grab_bits(buf, 2, 0, 8); - a->max_bitrate *= 8000; - break; - - case AUDIO_CODING_TYPE_SACD: - break; - - case AUDIO_CODING_TYPE_EAC3: - break; - - case AUDIO_CODING_TYPE_DTS_HD: - break; - - case AUDIO_CODING_TYPE_MLP: - break; - - case AUDIO_CODING_TYPE_DST: - break; - - case AUDIO_CODING_TYPE_WMAPRO: - a->profile = grab_bits(buf, 2, 0, 3); - break; - - case AUDIO_CODING_TYPE_REF_CXT: - a->format = grab_bits(buf, 2, 3, 5); - if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || - a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - snd_printd(KERN_INFO - "audio coding xtype %d not expected in ELD\n", - a->format); - a->format = 0; - } else - a->format += AUDIO_CODING_TYPE_HE_AAC - - AUDIO_CODING_XTYPE_HE_AAC; - break; - } -} - -static int hdmi_update_sink_eld(struct hda_codec *codec, - const unsigned char *buf, int size) -{ - struct intel_hdmi_spec *spec = codec->spec; - struct sink_eld *e = &spec->sink; - int mnl; - int i; - - e->eld_ver = grab_bits(buf, 0, 3, 5); - if (e->eld_ver != ELD_VER_CEA_861D && - e->eld_ver != ELD_VER_PARTIAL) { - snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); - goto out_fail; - } - - e->eld_size = size; - e->baseline_len = grab_bits(buf, 2, 0, 8); - mnl = grab_bits(buf, 4, 0, 5); - e->cea_edid_ver = grab_bits(buf, 4, 5, 3); - - e->support_hdcp = grab_bits(buf, 5, 0, 1); - e->support_ai = grab_bits(buf, 5, 1, 1); - e->conn_type = grab_bits(buf, 5, 2, 2); - e->sad_count = grab_bits(buf, 5, 4, 4); - - e->aud_synch_delay = grab_bits(buf, 6, 0, 8); - e->spk_alloc = grab_bits(buf, 7, 0, 7); - - e->port_id = get_unaligned_le64(buf + 8); - - /* not specified, but the spec's tendency is little endian */ - e->manufacture_id = get_unaligned_le16(buf + 16); - e->product_id = get_unaligned_le16(buf + 18); - - if (mnl > ELD_MAX_MNL) { - snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); - goto out_fail; - } else if (ELD_FIXED_BYTES + mnl > size) { - snd_printd(KERN_INFO "out of range MNL %d\n", mnl); - goto out_fail; - } else - strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); - - for (i = 0; i < e->sad_count; i++) { - if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - snd_printd(KERN_INFO "out of range SAD %d\n", i); - goto out_fail; - } - hdmi_update_short_audio_desc(e->sad + i, - buf + ELD_FIXED_BYTES + mnl + 3 * i); - } - - return 0; - -out_fail: - e->eld_ver = 0; - return -EINVAL; -} - -static int hdmi_get_eld(struct hda_codec *codec) -{ - int i; - int ret; - int size; - unsigned char *buf; - - i = hdmi_present_sense(codec, PIN_NID) & AC_PINSENSE_ELDV; - if (!i) - return -ENOENT; - - size = hdmi_get_eld_size(codec, PIN_NID); - if (size == 0) { - /* wfg: workaround for ASUS P5E-VM HDMI board */ - snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); - size = 128; - } - if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { - snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); - return -ERANGE; - } - - buf = kmalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - for (i = 0; i < size; i++) - buf[i] = hdmi_get_eld_byte(codec, i); - - ret = hdmi_update_sink_eld(codec, buf, size); - - kfree(buf); - return ret; -} - -static void hdmi_show_short_audio_desc(struct cea_sad *a) -{ - printk(KERN_INFO "coding type: %s\n", - cea_audio_coding_type_names[a->format]); - printk(KERN_INFO "channels: %d\n", a->channels); - printk(KERN_INFO "sampling frequencies: 0x%x\n", a->rates); - - if (a->format == AUDIO_CODING_TYPE_LPCM) - printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); - - if (a->max_bitrate) - printk(KERN_INFO "max bitrate: %d HZ\n", a->max_bitrate); - - if (a->profile) - printk(KERN_INFO "profile: %d\n", a->profile); -} - -static void hdmi_show_eld(struct hda_codec *codec) -{ - int i; - int j; - struct intel_hdmi_spec *spec = codec->spec; - struct sink_eld *e = &spec->sink; - char buf[80]; - - printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); - printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); - printk(KERN_INFO "vendor block len is %d\n", - e->eld_size - e->baseline_len * 4 - 4); - printk(KERN_INFO "ELD version is %s\n", - eld_versoin_names[e->eld_ver]); - printk(KERN_INFO "CEA EDID version is %s\n", - cea_edid_version_names[e->cea_edid_ver]); - printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); - printk(KERN_INFO "product id is 0x%x\n", e->product_id); - printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); - printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); - printk(KERN_INFO "AI support is %d\n", e->support_ai); - printk(KERN_INFO "SAD count is %d\n", e->sad_count); - printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); - printk(KERN_INFO "connection type is %s\n", - eld_connection_type_names[e->conn_type]); - printk(KERN_INFO "monitor name is %s\n", e->monitor_name); - - j = 0; - for (i = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { - if (e->spk_alloc & (1 << i)) - j += snprintf(buf + j, sizeof(buf) - j, " %s", - cea_speaker_allocation_names[i]); - } - buf[j] = '\0'; /* necessary when j == 0 */ - printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); - - for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(e->sad + i); -} - -/* - * Be careful, ELD buf could be totally rubbish! - */ static void hdmi_parse_eld(struct hda_codec *codec) { - hdmi_debug_present_sense(codec); + struct intel_hdmi_spec *spec = codec->spec; + struct sink_eld *eld = &spec->sink; - if (!hdmi_get_eld(codec)) - hdmi_show_eld(codec); + if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) + snd_hdmi_show_eld(eld); } @@ -676,7 +206,7 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) int i; int size; - size = hdmi_get_eld_size(codec, PIN_NID); + size = snd_hdmi_get_eld_size(codec, PIN_NID); printk(KERN_DEBUG "ELD buf size is %d\n", size); for (i = 0; i < 8; i++) { From 5f1e71b1cc2cc788c0f452772e2ce5e7430c40c2 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Tue, 18 Nov 2008 11:47:53 +0800 Subject: [PATCH 111/367] ALSA: ELD proc interface for HDMI sinks Create /proc/asound/card/eld# to reflect the audio configurations and capabilities of the attached HDMI sink. Some notes: - Shall we show an empty file if the ELD content is not valid? Well it's not that simple. There could be partially populated ELD, and there may be malformed ELD provided by buggy drivers/monitors. So expose ELD as it is. - The ELD retrieval routines rely on the Intel HDA interface, others are/could be universal and independent ones. - How do we name the proc file? If there are going to be two HDMI pins per codec, then the current naming scheme (eld#) will fail. Luckily the user space dependencies should be minimal, so it would be trivial to do the rename if that happens. - The ELD proc file content is designed to be easy for scripts and human reading. Its lines all have the pattern: \t[\t]* where is a keyword in c language, while could be any contents, including white spaces. could also be a null value. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 74 +++++++++++++++++++++++++++++++++ sound/pci/hda/hda_local.h | 9 ++++ sound/pci/hda/patch_intelhdmi.c | 2 + 3 files changed, 85 insertions(+) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index a69a7e87d26a..7fa065cd1d9c 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -452,3 +452,77 @@ void snd_hdmi_show_eld(struct sink_eld *e) for (i = 0; i < e->sad_count; i++) hdmi_show_short_audio_desc(e->sad + i); } + +#ifdef CONFIG_PROC_FS + +static void hdmi_print_sad_info(int i, struct cea_sad *a, + struct snd_info_buffer *buffer) +{ + char buf[80]; + + snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", + i, a->format, cea_audio_coding_type_names[a->format]); + snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); + + snd_print_pcm_rates(a->rates, buf, sizeof(buf)); + snd_iprintf(buffer, "sad%d_sampling_rates\t[0x%x] %s\n", + i, a->rates, buf); + + if (a->format == AUDIO_CODING_TYPE_LPCM) + snd_iprintf(buffer, "sad%d_sample_bits\t0x%x\n", + i, a->sample_bits); + + if (a->max_bitrate) + snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", + i, a->max_bitrate); + + if (a->profile) + snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); +} + +static void hdmi_print_eld_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct sink_eld *e = entry->private_data; + char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + int i; + + snd_iprintf(buffer, "monitor name\t\t%s\n", e->monitor_name); + snd_iprintf(buffer, "connection_type\t\t%s\n", + eld_connection_type_names[e->conn_type]); + snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, + eld_versoin_names[e->eld_ver]); + snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, + cea_edid_version_names[e->cea_edid_ver]); + snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); + snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); + snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); + snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); + snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); + snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); + + hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_iprintf(buffer, "speakers\t\t[0x%x] %s\n", e->spk_alloc, buf); + + snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); + + for (i = 0; i < e->sad_count; i++) + hdmi_print_sad_info(i, e->sad + i, buffer); +} + +int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) +{ + char name[32]; + struct snd_info_entry *entry; + int err; + + snprintf(name, sizeof(name), "eld#%d", codec->addr); + err = snd_card_proc_new(codec->bus->card, name, &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); + return 0; +} + +#endif diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index e1b76686672a..02ac7321e5e4 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -484,4 +484,13 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct sink_eld *, struct hda_codec *, hda_nid_t); void snd_hdmi_show_eld(struct sink_eld *eld); +#ifdef CONFIG_PROC_FS +int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld); +#else +inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) +{ + return 0; +} +#endif + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 489278d3d773..c95abc47614f 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -446,6 +446,8 @@ static int patch_intel_hdmi(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = intel_hdmi_patch_ops; + snd_hda_eld_proc_new(codec, &spec->sink); + return 0; } From e4973e1e5a42072ce88736ba0e39e4b8fc6c3c44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 09:32:42 +0100 Subject: [PATCH 112/367] ALSA: hda - Create jack detection elements in build_controls The jack detection input elements should be created in build_controls callback instead of init callback because init can be called multiple times by suspend/resume and power-saving. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 59 +++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 1aa3f6cbcb96..b6cf821434c8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1249,10 +1249,13 @@ static const char *slave_sws[] = { }; static void stac92xx_free_kctls(struct hda_codec *codec); +static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type); static int stac92xx_build_controls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; int err; int i; @@ -1323,6 +1326,36 @@ static int stac92xx_build_controls(struct hda_codec *codec) } stac92xx_free_kctls(codec); /* no longer needed */ + + /* create jack input elements */ + if (spec->hp_detect) { + for (i = 0; i < cfg->hp_outs; i++) { + int type = SND_JACK_HEADPHONE; + nid = cfg->hp_pins[i]; + /* jack detection */ + if (cfg->hp_outs == i) + type |= SND_JACK_LINEOUT; + err = stac92xx_add_jack(codec, nid, type); + if (err < 0) + return err; + } + } + for (i = 0; i < cfg->line_outs; i++) { + err = stac92xx_add_jack(codec, cfg->line_out_pins[i], + SND_JACK_LINEOUT); + if (err < 0) + return err; + } + for (i = 0; i < AUTO_PIN_LAST; i++) { + nid = cfg->input_pins[i]; + if (nid) { + err = stac92xx_add_jack(codec, nid, + SND_JACK_MICROPHONE); + if (err < 0) + return err; + } + } + return 0; } @@ -3658,6 +3691,7 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, static int stac92xx_add_jack(struct hda_codec *codec, hda_nid_t nid, int type) { +#ifdef CONFIG_SND_JACK struct sigmatel_spec *spec = codec->spec; struct sigmatel_jack *jack; int def_conf = snd_hda_codec_read(codec, nid, @@ -3681,6 +3715,9 @@ static int stac92xx_add_jack(struct hda_codec *codec, snd_hda_get_jack_location(def_conf)); return snd_jack_new(codec->bus->card, name, type, &jack->jack); +#else + return 0; +#endif } static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, @@ -3748,7 +3785,7 @@ static int stac92xx_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; + int i; snd_hda_sequence_write(codec, spec->init); @@ -3762,16 +3799,8 @@ static int stac92xx_init(struct hda_codec *codec) if (spec->hp_detect) { /* Enable unsolicited responses on the HP widget */ for (i = 0; i < cfg->hp_outs; i++) { - int type = SND_JACK_HEADPHONE; hda_nid_t nid = cfg->hp_pins[i]; enable_pin_detect(codec, nid, STAC_HP_EVENT | nid); - /* jack detection */ - if (cfg->hp_outs == i) - type |= SND_JACK_LINEOUT; - err = stac92xx_add_jack(codec, nid, type); - if (err < 0) - return err; - } /* force to enable the first line-out; the others are set up * in unsol_event @@ -3785,12 +3814,6 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); } - for (i = 0; i < cfg->line_outs; i++) { - err = stac92xx_add_jack(codec, - cfg->line_out_pins[i], SND_JACK_LINEOUT); - if (err < 0) - return err; - } for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = cfg->input_pins[i]; if (nid) { @@ -3807,10 +3830,6 @@ static int stac92xx_init(struct hda_codec *codec) } pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); - err = stac92xx_add_jack(codec, nid, - SND_JACK_MICROPHONE); - if (err < 0) - return err; enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid); } } @@ -3855,6 +3874,7 @@ static int stac92xx_init(struct hda_codec *codec) static void stac92xx_free_jacks(struct hda_codec *codec) { +#ifdef CONFIG_SND_JACK struct sigmatel_spec *spec = codec->spec; if (spec->jacks.list) { struct sigmatel_jack *jacks = spec->jacks.list; @@ -3863,6 +3883,7 @@ static void stac92xx_free_jacks(struct hda_codec *codec) snd_device_free(codec->bus->card, &jacks[i].jack); } snd_array_free(&spec->jacks); +#endif } static void stac92xx_free_kctls(struct hda_codec *codec) From 2c885878c1b29293f04cfb4a5bd285c969148a8b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 09:36:55 +0100 Subject: [PATCH 113/367] ALSA: hda - Use init callback in stac92xx_resume() Call the init callback and remove duplicated codes in stac92xx_resume(). This also fixes the missing initialization such as digital I/O pins. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b6cf821434c8..bf9a40ee789e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4142,17 +4142,13 @@ static int stac92xx_resume(struct hda_codec *codec) struct sigmatel_spec *spec = codec->spec; stac92xx_set_config_regs(codec); - snd_hda_sequence_write(codec, spec->init); - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); + stac92xx_init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); - /* power down inactive DACs */ - if (spec->dac_list) - stac92xx_power_down(codec); - /* invoke unsolicited event to reset the HP state */ + /* fake event to set up pins again to override cached values */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); + codec->patch_ops.unsol_event(codec, + (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); return 0; } #endif From af9f341a94482594ac28cb5b07c655b458bfe84e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 10:38:56 +0100 Subject: [PATCH 114/367] ALSA: hda - Fix restore of pin configs at resume for STAC/IDT codecs Fixed the restore of pin configs at resume for some STAC/IDT codec models. These models set explicitly the pin configs after the default init configs, and these aren't restored properly at resume. This patch introduces two changes: - Allocate always pin_configs array in stac_spec so that the driver can overwrite the value freely - Introduce stac_change_pin_config() to change the pin config value Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 178 ++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 82 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index bf9a40ee789e..3029f5b1419a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -210,7 +210,6 @@ struct sigmatel_spec { hda_nid_t *pin_nids; unsigned int num_pins; unsigned int *pin_configs; - unsigned int *bios_pin_configs; /* codec specific stuff */ struct hda_verb *init; @@ -2219,12 +2218,11 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec) int i; struct sigmatel_spec *spec = codec->spec; - if (! spec->bios_pin_configs) { - spec->bios_pin_configs = kcalloc(spec->num_pins, - sizeof(*spec->bios_pin_configs), GFP_KERNEL); - if (! spec->bios_pin_configs) - return -ENOMEM; - } + kfree(spec->pin_configs); + spec->pin_configs = kcalloc(spec->num_pins, sizeof(*spec->pin_configs), + GFP_KERNEL); + if (!spec->pin_configs) + return -ENOMEM; for (i = 0; i < spec->num_pins; i++) { hda_nid_t nid = spec->pin_nids[i]; @@ -2234,7 +2232,7 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec) AC_VERB_GET_CONFIG_DEFAULT, 0x00); snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x bios pin config %8.8x\n", nid, pin_cfg); - spec->bios_pin_configs[i] = pin_cfg; + spec->pin_configs[i] = pin_cfg; } return 0; @@ -2276,6 +2274,39 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) spec->pin_configs[i]); } +static int stac_save_pin_cfgs(struct hda_codec *codec, unsigned int *pins) +{ + struct sigmatel_spec *spec = codec->spec; + + if (!pins) + return stac92xx_save_bios_config_regs(codec); + + kfree(spec->pin_configs); + spec->pin_configs = kmemdup(pins, + spec->num_pins * sizeof(*pins), + GFP_KERNEL); + if (!spec->pin_configs) + return -ENOMEM; + + stac92xx_set_config_regs(codec); + return 0; +} + +static void stac_change_pin_config(struct hda_codec *codec, hda_nid_t nid, + unsigned int cfg) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_nids[i] == nid) { + spec->pin_configs[i] = cfg; + stac92xx_set_config_reg(codec, nid, cfg); + break; + } + } +} + /* * Analog playback callbacks */ @@ -3906,8 +3937,7 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; - if (spec->bios_pin_configs) - kfree(spec->bios_pin_configs); + kfree(spec->pin_configs); stac92xx_free_jacks(codec); snd_array_free(&spec->events); @@ -4182,14 +4212,12 @@ static int patch_stac9200(struct hda_codec *codec) if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac9200_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac9200_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.max_channels = 2; @@ -4245,14 +4273,12 @@ static int patch_stac925x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac925x_brd_tbl[spec->board_config] != NULL){ - spec->pin_configs = stac925x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac925x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.max_channels = 2; @@ -4334,14 +4360,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD73XX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd73xx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, @@ -4517,14 +4541,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD83XXX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd83xxx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd83xxx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } err = stac92xx_parse_auto_config(codec, 0x1d, 0); @@ -4631,14 +4653,12 @@ again: snd_printdd(KERN_INFO "hda_codec: Unknown model for" " STAC92HD71BXX, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac92hd71bxx_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } switch (codec->vendor_id) { @@ -4680,7 +4700,7 @@ again: /* disable VSW */ spec->init = &stac92hd71bxx_analog_core_init[HD_DISABLE_PORTF]; - stac92xx_set_config_reg(codec, 0xf, 0x40f000f0); + stac_change_pin_config(codec, 0xf, 0x40f000f0); break; case 0x111d7603: /* 6 Port with Analog Mixer */ if ((codec->revision_id & 0xf) == 1) { @@ -4729,7 +4749,7 @@ again: spec->num_dmuxes = 0; /* enable internal microphone */ - stac92xx_set_config_reg(codec, 0x0e, 0x01813040); + stac_change_pin_config(codec, 0x0e, 0x01813040); stac92xx_auto_set_pinctl(codec, 0x0e, AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); break; @@ -4824,14 +4844,12 @@ static int patch_stac922x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " "using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else if (stac922x_brd_tbl[spec->board_config] != NULL) { - spec->pin_configs = stac922x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac922x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->adc_nids = stac922x_adc_nids; @@ -4894,14 +4912,12 @@ static int patch_stac927x(struct hda_codec *codec) snd_printdd(KERN_INFO "hda_codec: Unknown model for" "STAC927x, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac927x_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac927x_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->digbeep_nid = 0x23; @@ -4931,15 +4947,15 @@ static int patch_stac927x(struct hda_codec *codec) case 0x10280209: case 0x1028022e: /* correct the device field to SPDIF out */ - stac92xx_set_config_reg(codec, 0x21, 0x01442070); + stac_change_pin_config(codec, 0x21, 0x01442070); break; }; /* configure the analog microphone on some laptops */ - stac92xx_set_config_reg(codec, 0x0c, 0x90a79130); + stac_change_pin_config(codec, 0x0c, 0x90a79130); /* correct the front output jack as a hp out */ - stac92xx_set_config_reg(codec, 0x0f, 0x0227011f); + stac_change_pin_config(codec, 0x0f, 0x0227011f); /* correct the front input jack as a mic */ - stac92xx_set_config_reg(codec, 0x0e, 0x02a79130); + stac_change_pin_config(codec, 0x0e, 0x02a79130); /* fallthru */ case STAC_DELL_3ST: /* GPIO2 High = Enable EAPD */ @@ -5021,14 +5037,12 @@ static int patch_stac9205(struct hda_codec *codec) if (spec->board_config < 0) { snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); err = stac92xx_save_bios_config_regs(codec); - if (err < 0) { - stac92xx_free(codec); - return err; - } - spec->pin_configs = spec->bios_pin_configs; - } else { - spec->pin_configs = stac9205_brd_tbl[spec->board_config]; - stac92xx_set_config_regs(codec); + } else + err = stac_save_pin_cfgs(codec, + stac9205_brd_tbl[spec->board_config]); + if (err < 0) { + stac92xx_free(codec); + return err; } spec->digbeep_nid = 0x23; @@ -5055,8 +5069,8 @@ static int patch_stac9205(struct hda_codec *codec) switch (spec->board_config){ case STAC_9205_DELL_M43: /* Enable SPDIF in/out */ - stac92xx_set_config_reg(codec, 0x1f, 0x01441030); - stac92xx_set_config_reg(codec, 0x20, 0x1c410030); + stac_change_pin_config(codec, 0x1f, 0x01441030); + stac_change_pin_config(codec, 0x20, 0x1c410030); /* Enable unsol response for GPIO4/Dock HP connection */ snd_hda_codec_write(codec, codec->afg, 0, From cd896c331dd442c43cd9e23de3f1a4f3c111c292 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Nov 2008 12:36:33 +0100 Subject: [PATCH 115/367] ALSA: hda - Allow multiple imux for matrix-type mixers of ALC codecs Allow the multiple imux instances for matrix-type mixers like ALC882. So far, only ALC260 used this feature, but other codecs may need a similar stuff. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 04e153a77dbc..b7d34390eff4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -382,11 +382,15 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux = spec->input_mux; + const struct hda_input_mux *imux; unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int mux_idx; hda_nid_t nid = spec->capsrc_nids ? spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx]; + mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; + imux = &spec->input_mux[mux_idx]; + if (spec->is_mix_capture) { /* Matrix-mixer style (e.g. ALC882) */ unsigned int *cur_val = &spec->cur_mux[adc_idx]; @@ -407,10 +411,7 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, return 1; } else { /* MUX style (e.g. ALC880) */ - unsigned int mux_idx; - mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; - return snd_hda_input_mux_put(codec, &spec->input_mux[mux_idx], - ucontrol, nid, + return snd_hda_input_mux_put(codec, imux, ucontrol, nid, &spec->cur_mux[adc_idx]); } } From cb6e2063697e91ca6983f9fe6958d20469b43641 Mon Sep 17 00:00:00 2001 From: Naresh Medisetty Date: Tue, 18 Nov 2008 11:01:03 +0530 Subject: [PATCH 116/367] ASoC: DaVinci: Fix audio stall when doing full duplex Fix concurrent capture/playback issue. The issue is caused by re-initialization of control registers used specifically for capture or playback in both capture and playback operations. Signed-off-by: Steve Chen Signed-off-by: Naresh Medisetty Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 8c1bf876031d..11c20d0b7bcc 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -295,10 +295,14 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, u32 w; /* general line settings */ - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, - DAVINCI_MCBSP_SPCR_RINTM(3) | - DAVINCI_MCBSP_SPCR_XINTM(3) | - DAVINCI_MCBSP_SPCR_FREE); + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } else { + w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); @@ -329,16 +333,19 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + } else { + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + } return 0; } From a11311d71d59145d920c19c0a4eed3fa7e26d222 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 18 Nov 2008 16:18:15 +0800 Subject: [PATCH 117/367] ASoC: Blackfin: updates Kconfig for SPORT tweak SPORT range for non-BF54x so we get proper behavior for BF52x parts Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index dc006206f622..3fce18788b77 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -80,7 +80,7 @@ config SND_BF5XX_SPORT_NUM int "Set a SPORT for Sound chip" depends on (SND_BF5XX_I2S || SND_BF5XX_AC97) range 0 3 if BF54x - range 0 1 if (BF53x || BF561) + range 0 1 if !BF54x default 0 help Set the correct SPORT for sound chip. From 9905ed35fdec0ebb3be8a724021ff3b104571667 Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Tue, 18 Nov 2008 16:18:16 +0800 Subject: [PATCH 118/367] ASoC: AD1980 codec: add multi-channel function support We added multi-channel function to this codec driver and Blackfin ASoC driver as well. It was tested on Blackfin hardware. Signed-off-by: Cliff Cai Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 1397b8e06c0b..410fed953c54 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -85,6 +85,9 @@ SOC_DOUBLE("Line HP Swap Switch", AC97_AD_MISC, 10, 5, 1, 0), SOC_DOUBLE("Surround Playback Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1), SOC_DOUBLE("Surround Playback Switch", AC97_SURROUND_MASTER, 15, 7, 1, 1), +SOC_DOUBLE("Center/LFE Playback Volume", AC97_CENTER_LFE_MASTER, 8, 0, 31, 1), +SOC_DOUBLE("Center/LFE Playback Switch", AC97_CENTER_LFE_MASTER, 15, 7, 1, 1), + SOC_ENUM("Capture Source", ad1980_cap_src), SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0), @@ -145,7 +148,7 @@ struct snd_soc_dai ad1980_dai = { .playback = { .stream_name = "Playback", .channels_min = 2, - .channels_max = 2, + .channels_max = 6, .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { @@ -192,6 +195,7 @@ static int ad1980_soc_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0; u16 vendor_id2; + u16 ext_status; printk(KERN_INFO "AD1980 SoC Audio Codec\n"); @@ -253,9 +257,16 @@ static int ad1980_soc_probe(struct platform_device *pdev) "supported\n"); } - ac97_write(codec, AC97_MASTER, 0x0000); /* unmute line out volume */ - ac97_write(codec, AC97_PCM, 0x0000); /* unmute PCM out volume */ - ac97_write(codec, AC97_REC_GAIN, 0x0000);/* unmute record volume */ + /* unmute captures and playbacks volume */ + ac97_write(codec, AC97_MASTER, 0x0000); + ac97_write(codec, AC97_PCM, 0x0000); + ac97_write(codec, AC97_REC_GAIN, 0x0000); + ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); + ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); + + /*power on LFE/CENTER/Surround DACs*/ + ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); + ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); ad1980_add_controls(codec); ret = snd_soc_register_card(socdev); From 67f854b910613eeffec4fe71e35c0cd8c32c82ec Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Tue, 18 Nov 2008 16:18:17 +0800 Subject: [PATCH 119/367] ASoC: Blackfin: add multi-channel function support This patch provides a option for users to enable multi-channel function support in Blackfin ASoC driver. Because Blackfin is without MMU, it is easy for us and the user to enable this function at compiling stage not dynamically on the fly. Signed-off-by: Cliff Cai Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 14 ++- sound/soc/blackfin/bf5xx-ac97-pcm.c | 80 ++++++++----- sound/soc/blackfin/bf5xx-ac97.c | 176 ++++++++++++++++------------ sound/soc/blackfin/bf5xx-ac97.h | 35 +++++- sound/soc/blackfin/bf5xx-sport.h | 2 +- 5 files changed, 194 insertions(+), 113 deletions(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 3fce18788b77..43d89fc253ae 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -47,7 +47,7 @@ config SND_BF5XX_AC97 properly with this driver. This driver is known to work with the Analog Devices line of AC97 codecs. -config SND_MMAP_SUPPORT +config SND_BF5XX_MMAP_SUPPORT bool "Enable MMAP Support" depends on SND_BF5XX_AC97 default y @@ -55,9 +55,17 @@ config SND_MMAP_SUPPORT Say y if you want AC97 driver to support mmap mode. We introduce an intermediate buffer to simulate mmap. +config SND_BF5XX_MULTICHAN_SUPPORT + bool "Enable Multichannel Support" + depends on SND_BF5XX_AC97 + default n + help + Say y if you want AC97 driver to support up to 5.1 channel audio. + this mode will consume much more memory for DMA. + config SND_BF5XX_SOC_SPORT tristate - + config SND_BF5XX_SOC_I2S tristate select SND_BF5XX_SOC_SPORT @@ -90,7 +98,7 @@ config SND_BF5XX_HAVE_COLD_RESET depends on SND_BF5XX_AC97 default y if BFIN548_EZKIT default n if !BFIN548_EZKIT - + config SND_BF5XX_RESET_GPIO_NUM int "Set a GPIO for cold reset" depends on SND_BF5XX_HAVE_COLD_RESET diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 25e50d2ea1ec..4be1a490f4fb 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -43,24 +43,34 @@ #include "bf5xx-ac97.h" #include "bf5xx-sport.h" -#if defined(CONFIG_SND_MMAP_SUPPORT) +static unsigned int ac97_chan_mask[] = { + SP_FL, /* Mono */ + SP_STEREO, /* Stereo */ + SP_2DOT1, /* 2.1*/ + SP_QUAD,/*Quadraquic*/ + SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */ + SP_5DOT1, /* 5.1 */ +}; + +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, snd_pcm_uframes_t count) { struct snd_pcm_runtime *runtime = substream->runtime; struct sport_device *sport = runtime->private_data; + unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - bf5xx_pcm_to_ac97( - (struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos, - (__u32 *)runtime->dma_area + sport->tx_pos, count); + bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf + + sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos * + runtime->channels, count, chan_mask); sport->tx_pos += runtime->period_size; if (sport->tx_pos >= runtime->buffer_size) sport->tx_pos %= runtime->buffer_size; sport->tx_delay_pos = sport->tx_pos; } else { - bf5xx_ac97_to_pcm( - (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, - (__u32 *)runtime->dma_area + sport->rx_pos, count); + bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf + + sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos * + runtime->channels, count); sport->rx_pos += runtime->period_size; if (sport->rx_pos >= runtime->buffer_size) sport->rx_pos %= runtime->buffer_size; @@ -71,7 +81,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, static void bf5xx_dma_irq(void *data) { struct snd_pcm_substream *pcm = data; -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = pcm->runtime; struct sport_device *sport = runtime->private_data; bf5xx_mmap_copy(pcm, runtime->period_size); @@ -90,7 +100,7 @@ static void bf5xx_dma_irq(void *data) * The total rx/tx buffer is for ac97 frame to hold all pcm data * is 0x20000 * sizeof(struct ac97_frame) / 4. */ -#ifdef CONFIG_SND_MMAP_SUPPORT +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static const struct snd_pcm_hardware bf5xx_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | @@ -123,10 +133,20 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) { +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - memset(runtime->dma_area, 0, runtime->buffer_size); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sport->once = 0; + if (runtime->dma_area) + memset(runtime->dma_area, 0, runtime->buffer_size); + memset(sport->tx_dma_buf, 0, runtime->buffer_size * + sizeof(struct ac97_frame)); + } else + memset(sport->rx_dma_buf, 0, runtime->buffer_size * + sizeof(struct ac97_frame)); +#endif snd_pcm_lib_free_pages(substream); return 0; } @@ -139,7 +159,7 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) /* An intermediate buffer is introduced for implementing mmap for * SPORT working in TMD mode(include AC97). */ -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { sport_set_tx_callback(sport, bf5xx_dma_irq, substream); sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, @@ -174,23 +194,21 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { bf5xx_mmap_copy(substream, runtime->period_size); - snd_pcm_period_elapsed(substream); sport->tx_delay_pos = 0; sport_tx_start(sport); - } - else + } else sport_rx_start(sport); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) sport->tx_pos = 0; #endif sport_tx_stop(sport); } else { -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) sport->rx_pos = 0; #endif sport_rx_stop(sport); @@ -208,7 +226,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) struct sport_device *sport = runtime->private_data; unsigned int curr; -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) curr = sport->tx_delay_pos; else @@ -257,14 +275,16 @@ static int bf5xx_pcm_close(struct snd_pcm_substream *substream) pr_debug("%s enter\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { sport->once = 0; - memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + memset(sport->tx_dma_buf, 0, runtime->buffer_size * + sizeof(struct ac97_frame)); } else - memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + memset(sport->rx_dma_buf, 0, runtime->buffer_size * + sizeof(struct ac97_frame)); return 0; } -#ifdef CONFIG_SND_MMAP_SUPPORT +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) { @@ -286,13 +306,11 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, substream->stream ? "Capture" : "Playback", pos, count); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - bf5xx_pcm_to_ac97( - (struct ac97_frame *)runtime->dma_area + pos, - buf, count); + bf5xx_pcm_to_ac97((struct ac97_frame *)runtime->dma_area + pos, + (__u16 *)buf, count, chan_mask); else - bf5xx_ac97_to_pcm( - (struct ac97_frame *)runtime->dma_area + pos, - buf, count); + bf5xx_ac97_to_pcm((struct ac97_frame *)runtime->dma_area + pos, + (__u16 *)buf, count); return 0; } #endif @@ -306,7 +324,7 @@ struct snd_pcm_ops bf5xx_pcm_ac97_ops = { .prepare = bf5xx_pcm_prepare, .trigger = bf5xx_pcm_trigger, .pointer = bf5xx_pcm_pointer, -#ifdef CONFIG_SND_MMAP_SUPPORT +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) .mmap = bf5xx_pcm_mmap, #else .copy = bf5xx_pcm_copy, @@ -344,7 +362,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) * Need to allocate local buffer when enable * MMAP for SPORT working in TMD mode (include AC97). */ -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (!sport_handle->tx_dma_buf) { sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ @@ -381,7 +399,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) struct snd_pcm_substream *substream; struct snd_dma_buffer *buf; int stream; -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) size_t size = bf5xx_pcm_hardware.buffer_bytes_max * sizeof(struct ac97_frame) / 4; #endif @@ -395,7 +413,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) continue; dma_free_coherent(NULL, buf->bytes, buf->area, 0); buf->area = NULL; -#if defined(CONFIG_SND_MMAP_SUPPORT) +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (sport_handle->tx_dma_buf) dma_free_coherent(NULL, size, \ diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 5e5aafb6485f..65c162c4bfad 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -54,71 +54,103 @@ static int *cmd_count; static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; -#if defined(CONFIG_BF54x) +static u16 sport_req[][7] = { + PIN_REQ_SPORT_0, +#ifdef PIN_REQ_SPORT_1 + PIN_REQ_SPORT_1, +#endif +#ifdef PIN_REQ_SPORT_2 + PIN_REQ_SPORT_2, +#endif +#ifdef PIN_REQ_SPORT_3 + PIN_REQ_SPORT_3, +#endif + }; + static struct sport_param sport_params[4] = { - { - .dma_rx_chan = CH_SPORT0_RX, - .dma_tx_chan = CH_SPORT0_TX, - .err_irq = IRQ_SPORT0_ERR, - .regs = (struct sport_register *)SPORT0_TCR1, - }, - { - .dma_rx_chan = CH_SPORT1_RX, - .dma_tx_chan = CH_SPORT1_TX, - .err_irq = IRQ_SPORT1_ERR, - .regs = (struct sport_register *)SPORT1_TCR1, - }, - { - .dma_rx_chan = CH_SPORT2_RX, - .dma_tx_chan = CH_SPORT2_TX, - .err_irq = IRQ_SPORT2_ERR, - .regs = (struct sport_register *)SPORT2_TCR1, - }, - { - .dma_rx_chan = CH_SPORT3_RX, - .dma_tx_chan = CH_SPORT3_TX, - .err_irq = IRQ_SPORT3_ERR, - .regs = (struct sport_register *)SPORT3_TCR1, - } -}; -#else -static struct sport_param sport_params[2] = { { .dma_rx_chan = CH_SPORT0_RX, .dma_tx_chan = CH_SPORT0_TX, .err_irq = IRQ_SPORT0_ERROR, .regs = (struct sport_register *)SPORT0_TCR1, }, +#ifdef PIN_REQ_SPORT_1 { .dma_rx_chan = CH_SPORT1_RX, .dma_tx_chan = CH_SPORT1_TX, .err_irq = IRQ_SPORT1_ERROR, .regs = (struct sport_register *)SPORT1_TCR1, - } -}; + }, #endif +#ifdef PIN_REQ_SPORT_2 + { + .dma_rx_chan = CH_SPORT2_RX, + .dma_tx_chan = CH_SPORT2_TX, + .err_irq = IRQ_SPORT2_ERROR, + .regs = (struct sport_register *)SPORT2_TCR1, + }, +#endif +#ifdef PIN_REQ_SPORT_3 + { + .dma_rx_chan = CH_SPORT3_RX, + .dma_tx_chan = CH_SPORT3_TX, + .err_irq = IRQ_SPORT3_ERROR, + .regs = (struct sport_register *)SPORT3_TCR1, + } +#endif +}; -void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ - size_t count) +void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, + size_t count, unsigned int chan_mask) { while (count--) { - dst->ac97_tag = TAG_VALID | TAG_PCM; - (dst++)->ac97_pcm = *src++; + dst->ac97_tag = TAG_VALID; + if (chan_mask & SP_FL) { + dst->ac97_pcm_r = *src++; + dst->ac97_tag |= TAG_PCM_RIGHT; + } + if (chan_mask & SP_FR) { + dst->ac97_pcm_l = *src++; + dst->ac97_tag |= TAG_PCM_LEFT; + + } +#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) + if (chan_mask & SP_SR) { + dst->ac97_sl = *src++; + dst->ac97_tag |= TAG_PCM_SL; + } + if (chan_mask & SP_SL) { + dst->ac97_sr = *src++; + dst->ac97_tag |= TAG_PCM_SR; + } + if (chan_mask & SP_LFE) { + dst->ac97_lfe = *src++; + dst->ac97_tag |= TAG_PCM_LFE; + } + if (chan_mask & SP_FC) { + dst->ac97_center = *src++; + dst->ac97_tag |= TAG_PCM_CENTER; + } +#endif + dst++; } } EXPORT_SYMBOL(bf5xx_pcm_to_ac97); -void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ +void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, size_t count) { - while (count--) - *(dst++) = (src++)->ac97_pcm; + while (count--) { + *(dst++) = src->ac97_pcm_l; + *(dst++) = src->ac97_pcm_r; + src++; + } } EXPORT_SYMBOL(bf5xx_ac97_to_pcm); static unsigned int sport_tx_curr_frag(struct sport_device *sport) { - return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \ + return sport->tx_curr_frag = sport_curr_offset_tx(sport) / sport->tx_fragsize; } @@ -130,7 +162,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) sport_incfrag(sport, &nextfrag, 1); - nextwrite = (struct ac97_frame *)(sport->tx_buf + \ + nextwrite = (struct ac97_frame *)(sport->tx_buf + nextfrag * sport->tx_fragsize); pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n", sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]); @@ -297,20 +329,15 @@ static int bf5xx_ac97_resume(struct platform_device *pdev, static int bf5xx_ac97_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { - int ret; -#if defined(CONFIG_BF54x) - u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1, - PIN_REQ_SPORT_2, PIN_REQ_SPORT_3}; -#else - u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1}; -#endif + int ret = 0; cmd_count = (int *)get_zeroed_page(GFP_KERNEL); if (cmd_count == NULL) return -ENOMEM; if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { pr_err("Requesting Peripherals failed\n"); - return -EFAULT; + ret = -EFAULT; + goto peripheral_err; } #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET @@ -318,54 +345,52 @@ static int bf5xx_ac97_probe(struct platform_device *pdev, if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { pr_err("Failed to request GPIO_%d for reset\n", CONFIG_SND_BF5XX_RESET_GPIO_NUM); - peripheral_free_list(&sport_req[sport_num][0]); - return -1; + ret = -1; + goto gpio_err; } gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); #endif sport_handle = sport_init(&sport_params[sport_num], 2, \ sizeof(struct ac97_frame), NULL); if (!sport_handle) { - peripheral_free_list(&sport_req[sport_num][0]); -#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); -#endif - return -ENODEV; + ret = -ENODEV; + goto sport_err; } /*SPORT works in TDM mode to simulate AC97 transfers*/ ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); if (ret) { pr_err("SPORT is busy!\n"); - kfree(sport_handle); - peripheral_free_list(&sport_req[sport_num][0]); -#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); -#endif - return -EBUSY; + ret = -EBUSY; + goto sport_config_err; } ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); - kfree(sport_handle); - peripheral_free_list(&sport_req[sport_num][0]); -#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); -#endif - return -EBUSY; + ret = -EBUSY; + goto sport_config_err; } ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); if (ret) { pr_err("SPORT is busy!\n"); - kfree(sport_handle); - peripheral_free_list(&sport_req[sport_num][0]); -#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET - gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); -#endif - return -EBUSY; + ret = -EBUSY; + goto sport_config_err; } - return 0; + +sport_config_err: + kfree(sport_handle); +sport_err: +#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET + gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); +#endif +gpio_err: + peripheral_free_list(&sport_req[sport_num][0]); +peripheral_err: + free_page((unsigned long)cmd_count); + cmd_count = NULL; + + return ret; } static void bf5xx_ac97_remove(struct platform_device *pdev, @@ -373,6 +398,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, { free_page((unsigned long)cmd_count); cmd_count = NULL; + peripheral_free_list(&sport_req[sport_num][0]); #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); #endif @@ -389,7 +415,11 @@ struct snd_soc_dai bfin_ac97_dai = { .playback = { .stream_name = "AC97 Playback", .channels_min = 2, +#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) + .channels_max = 6, +#else .channels_max = 2, +#endif .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, .capture = { diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h index 3f77cc558dc0..3f2a911fe0cb 100644 --- a/sound/soc/blackfin/bf5xx-ac97.h +++ b/sound/soc/blackfin/bf5xx-ac97.h @@ -16,21 +16,46 @@ struct ac97_frame { u16 ac97_tag; /* slot 0 */ u16 ac97_addr; /* slot 1 */ u16 ac97_data; /* slot 2 */ - u32 ac97_pcm; /* slot 3 and 4: left and right pcm data */ + u16 ac97_pcm_l; /*slot 3:front left*/ + u16 ac97_pcm_r; /*slot 4:front left*/ +#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) + u16 ac97_mdm_l1; + u16 ac97_center; /*slot 6:center*/ + u16 ac97_sl; /*slot 7:surround left*/ + u16 ac97_sr; /*slot 8:surround right*/ + u16 ac97_lfe; /*slot 9:lfe*/ +#endif } __attribute__ ((packed)); +/* Speaker location */ +#define SP_FL 0x0001 +#define SP_FR 0x0010 +#define SP_FC 0x0002 +#define SP_LFE 0x0020 +#define SP_SL 0x0004 +#define SP_SR 0x0040 + +#define SP_STEREO (SP_FL | SP_FR) +#define SP_2DOT1 (SP_FL | SP_FR | SP_LFE) +#define SP_QUAD (SP_FL | SP_FR | SP_SL | SP_SR) +#define SP_5DOT1 (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR) + #define TAG_VALID 0x8000 #define TAG_CMD 0x6000 #define TAG_PCM_LEFT 0x1000 #define TAG_PCM_RIGHT 0x0800 -#define TAG_PCM (TAG_PCM_LEFT | TAG_PCM_RIGHT) +#define TAG_PCM_MDM_L1 0x0400 +#define TAG_PCM_CENTER 0x0200 +#define TAG_PCM_SL 0x0100 +#define TAG_PCM_SR 0x0080 +#define TAG_PCM_LFE 0x0040 extern struct snd_soc_dai bfin_ac97_dai; -void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ - size_t count); +void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \ + size_t count, unsigned int chan_mask); -void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ +void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \ size_t count); #endif diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index fcadcc081f7f..2e63dea73e9c 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h @@ -116,7 +116,7 @@ struct sport_device { void *err_data; unsigned char *tx_dma_buf; unsigned char *rx_dma_buf; -#ifdef CONFIG_SND_MMAP_SUPPORT +#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT dma_addr_t tx_dma_phy; dma_addr_t rx_dma_phy; int tx_pos;/*pcm sample count*/ From a89e611a1dfefbf5d21f6def54c958bf6c4971bc Mon Sep 17 00:00:00 2001 From: Cliff Cai Date: Tue, 18 Nov 2008 16:18:18 +0800 Subject: [PATCH 120/367] ASoC: Blackfin: Fix AD1980/1 build with MMAP support disabled clean up redudent code and correct building problem in non-mmap mode Signed-off-by: Cliff Cai Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97-pcm.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 4be1a490f4fb..4d25f73274e8 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -193,8 +193,10 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) bf5xx_mmap_copy(substream, runtime->period_size); sport->tx_delay_pos = 0; +#endif sport_tx_start(sport); } else sport_rx_start(sport); @@ -267,23 +269,6 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) return ret; } -static int bf5xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct sport_device *sport = runtime->private_data; - - pr_debug("%s enter\n", __func__); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - sport->once = 0; - memset(sport->tx_dma_buf, 0, runtime->buffer_size * - sizeof(struct ac97_frame)); - } else - memset(sport->rx_dma_buf, 0, runtime->buffer_size * - sizeof(struct ac97_frame)); - - return 0; -} - #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) @@ -301,7 +286,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, void __user *buf, snd_pcm_uframes_t count) { struct snd_pcm_runtime *runtime = substream->runtime; - + unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; pr_debug("%s copy pos:0x%lx count:0x%lx\n", substream->stream ? "Capture" : "Playback", pos, count); @@ -317,7 +302,6 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, struct snd_pcm_ops bf5xx_pcm_ac97_ops = { .open = bf5xx_pcm_open, - .close = bf5xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = bf5xx_pcm_hw_params, .hw_free = bf5xx_pcm_hw_free, From 0cade26e366549adcf211f67200b2934c8220f05 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 18 Nov 2008 16:18:19 +0800 Subject: [PATCH 121/367] ASoC: Fix Blackfin AC97 DAI probe function return code A probe function should have a clean return 0 path. Cc: Cliff Cai Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 65c162c4bfad..5dcd3f665ab1 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -378,6 +378,8 @@ static int bf5xx_ac97_probe(struct platform_device *pdev, goto sport_config_err; } + return 0; + sport_config_err: kfree(sport_handle); sport_err: From caa45836d6bdfde603f3afd739ec3fc2360b1dac Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 18 Nov 2008 16:18:20 +0800 Subject: [PATCH 122/367] ASoC: Blackfin: do not force TWI bus for ssm2602 codec Cc: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 43d89fc253ae..f0fd235ca892 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -13,7 +13,6 @@ config SND_BF5XX_SOC_SSM2602 select SND_BF5XX_SOC_I2S select SND_SOC_SSM2602 select I2C - select I2C_BLACKFIN_TWI help Say Y if you want to add support for SoC audio on BF527-EZKIT. From 27b9be5a7894f571bbfb87de19ad7cd8c7737d22 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Tue, 18 Nov 2008 16:18:21 +0800 Subject: [PATCH 123/367] ASoC: Blackfin: Simplify the MMAP_SUPPORT macros protected code Cc: Cliff Cai Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97-pcm.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 4d25f73274e8..d3d51bcb4569 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -100,17 +100,14 @@ static void bf5xx_dma_irq(void *data) * The total rx/tx buffer is for ac97 frame to hold all pcm data * is 0x20000 * sizeof(struct ac97_frame) / 4. */ -#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) static const struct snd_pcm_hardware bf5xx_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | +#if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BLOCK_TRANSFER, -#else -static const struct snd_pcm_hardware bf5xx_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, #endif + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_LE, .period_bytes_min = 32, .period_bytes_max = 0x10000, From a0bd65f45faae78bda7a2a07370c40c3e0a2502a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 18 Nov 2008 16:18:22 +0800 Subject: [PATCH 124/367] ASoC: Blackfin: always set a default value for that GPIO range Cc: Cliff Cai Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu Signed-off-by: Mark Brown --- sound/soc/blackfin/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index f0fd235ca892..e162cbbd3f3b 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -104,5 +104,6 @@ config SND_BF5XX_RESET_GPIO_NUM range 0 159 default 19 if BFIN548_EZKIT default 5 if BFIN537_STAMP + default 0 help Set the correct GPIO for RESET the sound chip. From 72f2b894455775b980a5ac7ae70ab560b3d3d247 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 12:25:46 +0000 Subject: [PATCH 125/367] ASoC: Move uda134x_codec.h to uda134x.h For consistency with other ASoC codec drivers. Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 2 +- sound/soc/codecs/{uda134x_codec.h => uda134x.h} | 0 sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename sound/soc/codecs/{uda134x_codec.h => uda134x.h} (100%) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 04b30da10228..69ef521a2ed1 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -24,7 +24,7 @@ #include #include -#include "uda134x_codec.h" +#include "uda134x.h" #define POWER_OFF_ON_STANDBY 1 diff --git a/sound/soc/codecs/uda134x_codec.h b/sound/soc/codecs/uda134x.h similarity index 100% rename from sound/soc/codecs/uda134x_codec.h rename to sound/soc/codecs/uda134x.h diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index 29a68132f169..487b010730b8 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -26,7 +26,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-i2s.h" -#include "../codecs/uda134x_codec.h" +#include "../codecs/uda134x.h" /* #define ENFORCE_RATES 1 */ From 2af752936b311a846622668f8b0f1893d8eccade Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Tue, 18 Nov 2008 12:25:06 -0500 Subject: [PATCH 126/367] sound: Fix warnings relating to ignored return value in snd_card_register Do not ignore the return of 'device_create_file' in 'snd_card_register' and thereby fixing the following warnings: sound/core/init.c: In function 'snd_card_register': sound/core/init.c:640: warning: ignoring return value of 'device_create_file', declared with attribute warn_unused_result sound/core/init.c:641: warning: ignoring return value of 'device_create_file', declared with attribute warn_unused_result Signed-off-by: Hannes Eder Signed-off-by: Takashi Iwai --- sound/core/init.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/core/init.c b/sound/core/init.c index af1e407ca27f..0d5520c415d3 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -637,8 +637,12 @@ int snd_card_register(struct snd_card *card) #endif #ifndef CONFIG_SYSFS_DEPRECATED if (card->card_dev) { - device_create_file(card->card_dev, &card_id_attrs); - device_create_file(card->card_dev, &card_number_attrs); + err = device_create_file(card->card_dev, &card_id_attrs); + if (err < 0) + return err; + err = device_create_file(card->card_dev, &card_number_attrs); + if (err < 0) + return err; } #endif return 0; From ca3ea02e90d63a6a91c1c2a445d6d71f9031a44a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 20:40:36 +0000 Subject: [PATCH 127/367] ASoC: Remove unused snd_soc_machine_config declaration Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index fa1b99b45893..077dfe4e51f0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -228,7 +228,6 @@ struct snd_soc_dai_mode; struct snd_soc_pcm_runtime; struct snd_soc_dai; struct snd_soc_codec; -struct snd_soc_machine_config; struct soc_enum; struct snd_soc_ac97_ops; struct snd_soc_clock_info; From 5457a98039cebf20b564b5c3d73a50615e2b2696 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 08:56:15 +0800 Subject: [PATCH 128/367] ALSA: hda: make standalone hdmi_fill_audio_infoframe() code refactor: make a standalone function hdmi_fill_audio_infoframe(). Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index c95abc47614f..028fce996aa2 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -246,26 +246,33 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) #endif } -static void hdmi_setup_audio_infoframe(struct hda_codec *codec, - struct snd_pcm_substream *substream) +static void hdmi_fill_audio_infoframe(struct hda_codec *codec, + struct hdmi_audio_infoframe *ai) { - struct hdmi_audio_infoframe audio_infoframe = { - .type = 0x84, - .ver = 0x01, - .len = 0x0a, - .CC02_CT47 = substream->runtime->channels - 1, - }; - u8 *params = (u8 *)&audio_infoframe; + u8 *params = (u8 *)ai; int i; hdmi_debug_dip_size(codec); hdmi_clear_dip_buffers(codec); /* be paranoid */ hdmi_set_dip_index(codec, PIN_NID, 0x0, 0x0); - for (i = 0; i < sizeof(audio_infoframe); i++) + for (i = 0; i < sizeof(ai); i++) hdmi_write_dip_byte(codec, PIN_NID, params[i]); } +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_audio_infoframe ai = { + .type = 0x84, + .ver = 0x01, + .len = 0x0a, + .CC02_CT47 = substream->runtime->channels - 1, + }; + + hdmi_fill_audio_infoframe(codec, &ai); +} + /* * Unsolicited events From 903b21d8b7bb49d3438abdd7b9d4145511e1cba2 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 08:56:16 +0800 Subject: [PATCH 129/367] ALSA: hda: make global snd_print_channel_allocation() code refactor: make a global function snd_print_channel_allocation(). Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 11 +++++------ sound/pci/hda/hda_local.h | 3 +++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 7fa065cd1d9c..18078de0abcc 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -407,8 +407,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) printk(KERN_INFO "profile: %d\n", a->profile); } -#define HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 -static void hdmi_print_channel_allocation(int spk_alloc, char *buf, int buflen) +void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) { int i, j; @@ -425,7 +424,7 @@ static void hdmi_print_channel_allocation(int spk_alloc, char *buf, int buflen) void snd_hdmi_show_eld(struct sink_eld *e) { int i; - char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); @@ -446,7 +445,7 @@ void snd_hdmi_show_eld(struct sink_eld *e) eld_connection_type_names[e->conn_type]); printk(KERN_INFO "monitor name is %s\n", e->monitor_name); - hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); for (i = 0; i < e->sad_count; i++) @@ -484,7 +483,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct sink_eld *e = entry->private_data; - char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; snd_iprintf(buffer, "monitor name\t\t%s\n", e->monitor_name); @@ -501,7 +500,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); - hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); snd_iprintf(buffer, "speakers\t\t[0x%x] %s\n", e->spk_alloc, buf); snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 02ac7321e5e4..0baa9b816ca8 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -493,4 +493,7 @@ inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) } #endif +#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 +void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); + #endif /* __SOUND_HDA_LOCAL_H */ From 698544de8a31a7cadc26c27cbaa69ae82dd4f86c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 08:56:17 +0800 Subject: [PATCH 130/367] ALSA: hda: HDMI channel allocations for audio infoframe To play a 3+ channels LPCM/DSD stream via HDMI, - HDMI sink must tell HDMI source about its speaker placements (via ELD, speaker-allocation field) - HDMI source must tell the HDMI sink about channel allocation (via audio infoframe, channel-allocation field) (related docs: HDMI 1.3a spec section 7.4, CEA-861-D section 7.5.3 and 6.6) This patch attempts to set the CA(channel-allocation) byte in the audio infoframe according to - the number of channels in the current stream - the speakers attached to the HDMI sink A channel_allocations[] line must meet the following two criteria to be considered as a valid candidate for CA: 1) its number of allocated channels = substream->runtime->channels 2) its speakers are a subset of the available ones on the sink side If there are multiple candidates, the first one is selected. This simple policy shall cheat the sink into playing music, but may direct data to the wrong speakers. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 205 ++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 028fce996aa2..6b5c3e2cf93b 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -88,6 +88,132 @@ struct hdmi_audio_infoframe { u8 reserved[5]; /* PB6 - PB10 */ }; +/* + * CEA speaker placement: + * + * FLH FCH FRH + * FLW FL FLC FC FRC FR FRW + * + * LFE + * TC + * + * RL RLC RC RRC RR + * + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to + * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. + */ +enum cea_speaker_placement { + FL = (1 << 0), /* Front Left */ + FC = (1 << 1), /* Front Center */ + FR = (1 << 2), /* Front Right */ + FLC = (1 << 3), /* Front Left Center */ + FRC = (1 << 4), /* Front Right Center */ + RL = (1 << 5), /* Rear Left */ + RC = (1 << 6), /* Rear Center */ + RR = (1 << 7), /* Rear Right */ + RLC = (1 << 8), /* Rear Left Center */ + RRC = (1 << 9), /* Rear Right Center */ + LFE = (1 << 10), /* Low Frequency Effect */ + FLW = (1 << 11), /* Front Left Wide */ + FRW = (1 << 12), /* Front Right Wide */ + FLH = (1 << 13), /* Front Left High */ + FCH = (1 << 14), /* Front Center High */ + FRH = (1 << 15), /* Front Right High */ + TC = (1 << 16), /* Top Center */ +}; + +/* + * ELD SA bits in the CEA Speaker Allocation data block + */ +static int eld_speaker_allocation_bits[] = { + [0] = FL | FR, + [1] = LFE, + [2] = FC, + [3] = RL | RR, + [4] = RC, + [5] = FLC | FRC, + [6] = RLC | RRC, + /* the following are not defined in ELD yet */ + [7] = FLW | FRW, + [8] = FLH | FRH, + [9] = TC, + [10] = FCH, +}; + +struct cea_channel_speaker_allocation { + int ca_index; + int speakers[8]; + + /* derived values, just for convenience */ + int channels; + int spk_mask; +}; + +/* + * This is an ordered list! + * + * The preceding ones have better chances to be selected by + * hdmi_setup_channel_allocation(). + */ +static struct cea_channel_speaker_allocation channel_allocations[] = { +/* channel: 8 7 6 5 4 3 2 1 */ +{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, + /* 2.1 */ +{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, + /* dolby surround */ +{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, +{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, + /* 5.1 */ +{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, + /* 6.1 */ +{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, + /* 7.1 */ +{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, +{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, +{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, +{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, +}; + /* * HDMI routines */ @@ -260,6 +386,81 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec, hdmi_write_dip_byte(codec, PIN_NID, params[i]); } +/* + * Compute derived values in channel_allocations[]. + */ +static void init_channel_allocations(void) +{ + int i, j; + struct cea_channel_speaker_allocation *p; + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + p = channel_allocations + i; + p->channels = 0; + p->spk_mask = 0; + for (j = 0; j < ARRAY_SIZE(p->speakers); j++) + if (p->speakers[j]) { + p->channels++; + p->spk_mask |= p->speakers[j]; + } + } +} + +/* + * The transformation takes two steps: + * + * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask + * spk_mask => (channel_allocations[]) => ai->CA + * + * TODO: it could select the wrong CA from multiple candidates. +*/ +static int hdmi_setup_channel_allocation(struct hda_codec *codec, + struct hdmi_audio_infoframe *ai) +{ + struct intel_hdmi_spec *spec = codec->spec; + struct sink_eld *eld = &spec->sink; + int i; + int spk_mask = 0; + int channels = 1 + (ai->CC02_CT47 & 0x7); + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + /* + * CA defaults to 0 for basic stereo audio + */ + if (!eld->eld_ver) + return 0; + if (!eld->spk_alloc) + return 0; + if (channels <= 2) + return 0; + + /* + * expand ELD's speaker allocation mask + * + * ELD tells the speaker mask in a compact(paired) form, + * expand ELD's notions to match the ones used by audio infoframe. + */ + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { + if (eld->spk_alloc & (1 << i)) + spk_mask |= eld_speaker_allocation_bits[i]; + } + + /* search for the first working match in the CA table */ + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channels == channel_allocations[i].channels && + (spk_mask & channel_allocations[i].spk_mask) == + channel_allocations[i].spk_mask) { + ai->CA = channel_allocations[i].ca_index; + return 0; + } + } + + snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); + snd_printd(KERN_INFO "failed to setup channel allocation: %d of %s\n", + channels, buf); + return -1; +} + static void hdmi_setup_audio_infoframe(struct hda_codec *codec, struct snd_pcm_substream *substream) { @@ -270,6 +471,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, .CC02_CT47 = substream->runtime->channels - 1, }; + hdmi_setup_channel_allocation(codec, &ai); + hdmi_fill_audio_infoframe(codec, &ai); } @@ -455,6 +658,8 @@ static int patch_intel_hdmi(struct hda_codec *codec) snd_hda_eld_proc_new(codec, &spec->sink); + init_channel_allocations(); + return 0; } From 9c8641e8ee438273079337c86f4d739fbfdd8b33 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 08:56:18 +0800 Subject: [PATCH 131/367] ALSA: hda: HDMI channel mapping cleanups Refactor the channel mapping code for consistent naming and make it more informed about channel allocations. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 6b5c3e2cf93b..747aa84d0ecd 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -290,7 +290,7 @@ static void hdmi_set_channel_count(struct hda_codec *codec, int chs) chs, hdmi_get_channel_count(codec)); } -static void hdmi_debug_slot_mapping(struct hda_codec *codec) +static void hdmi_debug_channel_mapping(struct hda_codec *codec) { #ifdef CONFIG_SND_DEBUG_VERBOSE int i; @@ -305,13 +305,6 @@ static void hdmi_debug_slot_mapping(struct hda_codec *codec) #endif } -static void hdmi_setup_channel_mapping(struct hda_codec *codec) -{ - snd_hda_sequence_write(codec, def_chan_map); - hdmi_debug_slot_mapping(codec); -} - - static void hdmi_parse_eld(struct hda_codec *codec) { struct intel_hdmi_spec *spec = codec->spec; @@ -461,6 +454,22 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, return -1; } +static void hdmi_setup_channel_mapping(struct hda_codec *codec, + struct hdmi_audio_infoframe *ai) +{ + if (!ai->CA) + return; + + /* + * TODO: adjust channel mapping if necessary + * ALSA sequence is front/surr/clfe/side? + */ + + snd_hda_sequence_write(codec, def_chan_map); + hdmi_debug_channel_mapping(codec); +} + + static void hdmi_setup_audio_infoframe(struct hda_codec *codec, struct snd_pcm_substream *substream) { @@ -472,6 +481,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, }; hdmi_setup_channel_allocation(codec, &ai); + hdmi_setup_channel_mapping(codec, &ai); hdmi_fill_audio_infoframe(codec, &ai); } @@ -569,9 +579,6 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_set_channel_count(codec, substream->runtime->channels); - /* wfg: channel mapping not supported by DEVCTG */ - hdmi_setup_channel_mapping(codec); - hdmi_setup_audio_infoframe(codec, substream); hdmi_enable_output(codec); From c6798d2bd1805e32a92ba8db168ec51cdbb534b0 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Tue, 18 Nov 2008 20:54:17 -0500 Subject: [PATCH 132/367] ALSA: hda: EAPD mute on suspend Moved support for EAPD mute on suspend from stac92hd71xx_suspend to the generic stac92xx_suspend function. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 139efe37f3b3..c346c77e3068 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4185,6 +4185,16 @@ static int stac92xx_resume(struct hda_codec *codec) (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); return 0; } + +static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct sigmatel_spec *spec = codec->spec; + if (spec->eapd_mask) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); + return 0; +} #endif static struct hda_codec_ops stac92xx_patch_ops = { @@ -4194,6 +4204,7 @@ static struct hda_codec_ops stac92xx_patch_ops = { .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, #ifdef SND_HDA_NEEDS_RESUME + .suspend = stac92xx_suspend, .resume = stac92xx_resume, #endif }; @@ -4598,14 +4609,8 @@ static int stac92hd71xx_resume(struct hda_codec *codec) static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) { - struct sigmatel_spec *spec = codec->spec; - stac92hd71xx_set_power_state(codec, AC_PWRST_D3); - if (spec->eapd_mask) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data & - ~spec->eapd_mask); - return 0; + return stac92xx_suspend(codec, state); }; #endif @@ -4617,8 +4622,8 @@ static struct hda_codec_ops stac92hd71bxx_patch_ops = { .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, #ifdef SND_HDA_NEEDS_RESUME - .resume = stac92hd71xx_resume, .suspend = stac92hd71xx_suspend, + .resume = stac92hd71xx_resume, #endif }; From 4e19c58f27af67735d64d9af0b184181cea7ca63 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:13:59 +0800 Subject: [PATCH 133/367] ALSA: hda: minor code cleanups Some minor code cleanups. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/patch_intelhdmi.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 18078de0abcc..da08ddaef4fc 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -132,7 +132,7 @@ static char *cea_audio_coding_type_names[] = { /* * The following two lists are shared between * - HDMI audio InfoFrame (source to sink) - * - CEA E-EDID extension (sink to source) + * - CEA E-EDID Extension (sink to source) */ /* diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 747aa84d0ecd..459b04576de1 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -85,7 +85,7 @@ struct hdmi_audio_infoframe { u8 CXT04; u8 CA; u8 LFEPBL01_LSV36_DM_INH7; - u8 reserved[5]; /* PB6 - PB10 */ + u8 reserved[5]; /* PB6 - PB10 */ }; /* @@ -160,7 +160,7 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { { .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, /* 2.1 */ { .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, - /* dolby surround */ + /* Dolby Surround */ { .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, { .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, { .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, @@ -287,7 +287,7 @@ static void hdmi_set_channel_count(struct hda_codec *codec, int chs) if (chs != hdmi_get_channel_count(codec)) snd_printd(KERN_INFO "Channel count expect=%d, real=%d\n", - chs, hdmi_get_channel_count(codec)); + chs, hdmi_get_channel_count(codec)); } static void hdmi_debug_channel_mapping(struct hda_codec *codec) @@ -300,7 +300,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) slot = snd_hda_codec_read(codec, CVT_NID, 0, AC_VERB_GET_HDMI_CHAN_SLOT, i); printk(KERN_DEBUG "ASP channel %d => slot %d\n", - slot >> 4, slot & 0x7); + slot >> 4, slot & 0x7); } #endif } @@ -316,7 +316,7 @@ static void hdmi_parse_eld(struct hda_codec *codec) /* - * Audio Infoframe routines + * Audio InfoFrame routines */ static void hdmi_debug_dip_size(struct hda_codec *codec) @@ -547,8 +547,8 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) */ static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct intel_hdmi_spec *spec = codec->spec; @@ -556,8 +556,8 @@ static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, } static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct intel_hdmi_spec *spec = codec->spec; From 5b87ebb7a79455358c1910f2896112ac0fa0d0fa Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:14:00 +0800 Subject: [PATCH 134/367] ALSA: hda: rename sink_eld to hdmi_eld Rename struct sink_eld to hdmi_eld. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 14 +++++++------- sound/pci/hda/hda_local.h | 10 +++++----- sound/pci/hda/patch_intelhdmi.c | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index da08ddaef4fc..1b3ec1e7f268 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -267,8 +267,8 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, /* * Be careful, ELD buf could be totally rubbish! */ -static int hdmi_update_sink_eld(struct sink_eld *e, - const unsigned char *buf, int size) +static int hdmi_update_eld(struct hdmi_eld *e, + const unsigned char *buf, int size) { int mnl; int i; @@ -351,7 +351,7 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) AC_DIPSIZE_ELD_BUF); } -int snd_hdmi_get_eld(struct sink_eld *eld, +int snd_hdmi_get_eld(struct hdmi_eld *eld, struct hda_codec *codec, hda_nid_t nid) { int i; @@ -380,7 +380,7 @@ int snd_hdmi_get_eld(struct sink_eld *eld, for (i = 0; i < size; i++) buf[i] = hdmi_get_eld_byte(codec, nid, i); - ret = hdmi_update_sink_eld(eld, buf, size); + ret = hdmi_update_eld(eld, buf, size); kfree(buf); return ret; @@ -421,7 +421,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -void snd_hdmi_show_eld(struct sink_eld *e) +void snd_hdmi_show_eld(struct hdmi_eld *e) { int i; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; @@ -482,7 +482,7 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, static void hdmi_print_eld_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - struct sink_eld *e = entry->private_data; + struct hdmi_eld *e = entry->private_data; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; @@ -509,7 +509,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, hdmi_print_sad_info(i, e->sad + i, buffer); } -int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) +int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) { char name[32]; struct snd_info_entry *entry; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 0baa9b816ca8..a1473c6cb4bf 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -462,7 +462,7 @@ struct cea_sad { /* * ELD: EDID Like Data */ -struct sink_eld { +struct hdmi_eld { int eld_size; int baseline_len; int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ @@ -481,13 +481,13 @@ struct sink_eld { }; int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); -int snd_hdmi_get_eld(struct sink_eld *, struct hda_codec *, hda_nid_t); -void snd_hdmi_show_eld(struct sink_eld *eld); +int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); +void snd_hdmi_show_eld(struct hdmi_eld *eld); #ifdef CONFIG_PROC_FS -int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld); +int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); #else -inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld) +inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) { return 0; } diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 459b04576de1..5393f84f6755 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -42,7 +42,7 @@ struct intel_hdmi_spec { struct hda_multi_out multiout; struct hda_pcm pcm_rec; - struct sink_eld sink; + struct hdmi_eld sink_eld; }; static struct hda_verb pinout_enable_verb[] = { @@ -308,7 +308,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) static void hdmi_parse_eld(struct hda_codec *codec) { struct intel_hdmi_spec *spec = codec->spec; - struct sink_eld *eld = &spec->sink; + struct hdmi_eld *eld = &spec->sink_eld; if (!snd_hdmi_get_eld(eld, codec, PIN_NID)) snd_hdmi_show_eld(eld); @@ -411,7 +411,7 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, struct hdmi_audio_infoframe *ai) { struct intel_hdmi_spec *spec = codec->spec; - struct sink_eld *eld = &spec->sink; + struct hdmi_eld *eld = &spec->sink_eld; int i; int spk_mask = 0; int channels = 1 + (ai->CC02_CT47 & 0x7); @@ -663,7 +663,7 @@ static int patch_intel_hdmi(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = intel_hdmi_patch_ops; - snd_hda_eld_proc_new(codec, &spec->sink); + snd_hda_eld_proc_new(codec, &spec->sink_eld); init_channel_allocations(); From 06f69d17a90ced7d74ff12ce69b7b101aed4ffd9 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:14:01 +0800 Subject: [PATCH 135/367] ALSA: hda: minor output message cleanups Some minor user visible message cleanups. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 1b3ec1e7f268..75e9a4014f4e 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -118,7 +118,7 @@ static char *cea_audio_coding_type_names[] = { /* 6 */ "AAC-LC", /* 7 */ "DTS", /* 8 */ "ATRAC", - /* 9 */ "DSD (1-bit audio)", + /* 9 */ "DSD (One Bit Audio)", /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", /* 11 */ "DTS-HD", /* 12 */ "MLP (Dolby TrueHD)", @@ -395,7 +395,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) printk(KERN_INFO "channels: %d\n", a->channels); snd_print_pcm_rates(a->rates, buf, sizeof(buf)); - printk(KERN_INFO "sampling frequencies: %s\n", buf); + printk(KERN_INFO "sampling rates: %s\n", buf); if (a->format == AUDIO_CODING_TYPE_LPCM) printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); @@ -413,11 +413,9 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { if (spk_alloc & (1 << i)) - j += snprintf(buf + j, buflen - j, "%s ", + j += snprintf(buf + j, buflen - j, " %s", cea_speaker_allocation_names[i]); } - if (j) - j--; /* skip last space */ buf[j] = '\0'; /* necessary when j == 0 */ } @@ -464,11 +462,10 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); snd_print_pcm_rates(a->rates, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_sampling_rates\t[0x%x] %s\n", - i, a->rates, buf); + snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_iprintf(buffer, "sad%d_sample_bits\t0x%x\n", + snd_iprintf(buffer, "sad%d_bits\t\t0x%x\n", i, a->sample_bits); if (a->max_bitrate) @@ -501,7 +498,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - snd_iprintf(buffer, "speakers\t\t[0x%x] %s\n", e->spk_alloc, buf); + snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); From d39b4352f2356bde9d4dae8591d4c8022360922f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:14:02 +0800 Subject: [PATCH 136/367] ALSA: hda: make global snd_print_pcm_bits() Introduce a global function snd_print_pcm_bits() and use it in the ELD code. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 10 ++++++---- sound/pci/hda/hda_local.h | 3 +++ sound/pci/hda/hda_proc.c | 22 ++++++++++++++++------ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 75e9a4014f4e..8e575bb56ff7 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -455,7 +455,7 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) static void hdmi_print_sad_info(int i, struct cea_sad *a, struct snd_info_buffer *buffer) { - char buf[80]; + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", i, a->format, cea_audio_coding_type_names[a->format]); @@ -464,9 +464,11 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, snd_print_pcm_rates(a->rates, buf, sizeof(buf)); snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); - if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_iprintf(buffer, "sad%d_bits\t\t0x%x\n", - i, a->sample_bits); + if (a->format == AUDIO_CODING_TYPE_LPCM) { + snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); + snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", + i, a->sample_bits, buf); + } if (a->max_bitrate) snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index a1473c6cb4bf..a2d01a9a0b16 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -287,6 +287,9 @@ static inline int snd_hda_codec_proc_new(struct hda_codec *codec) { return 0; } #define SND_PRINT_RATES_ADVISED_BUFSIZE 80 void snd_print_pcm_rates(int pcm, char *buf, int buflen); +#define SND_PRINT_BITS_ADVISED_BUFSIZE 16 +void snd_print_pcm_bits(int pcm, char *buf, int buflen); + /* * Misc */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 512eb674b743..d956e9769133 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -107,23 +107,33 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen) static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + pcm &= AC_SUPPCM_RATES; snd_iprintf(buffer, " rates [0x%x]:", pcm); snd_print_pcm_rates(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); } -static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) +void snd_print_pcm_bits(int pcm, char *buf, int buflen) { static unsigned int bits[] = { 8, 16, 20, 24, 32 }; - int i; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) + if (pcm & (1 << i)) + j += snprintf(buf + j, buflen - j, " %d", bits[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) +{ + char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; pcm = (pcm >> 16) & 0xff; snd_iprintf(buffer, " bits [0x%x]:", pcm); - for (i = 0; i < ARRAY_SIZE(bits); i++) - if (pcm & (1 << i)) - snd_iprintf(buffer, " %d", bits[i]); - snd_iprintf(buffer, "\n"); + snd_print_pcm_bits(pcm, buf, sizeof(buf)); + snd_iprintf(buffer, "%s\n", buf); } static void print_pcm_formats(struct snd_info_buffer *buffer, From ae8cb4caa34af20311fcf5ef248afc54407aa9a8 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 19 Nov 2008 15:14:03 +0800 Subject: [PATCH 137/367] ALSA: hda: compact ELD output messages Strip out some ELD printk messages that end user won't care, and make the output compact. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 54 ++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 8e575bb56ff7..e848c30d9bf7 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -389,22 +389,27 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, static void hdmi_show_short_audio_desc(struct cea_sad *a) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; - printk(KERN_INFO "coding type: %s\n", - cea_audio_coding_type_names[a->format]); - printk(KERN_INFO "channels: %d\n", a->channels); + if (!a->format) + return; snd_print_pcm_rates(a->rates, buf, sizeof(buf)); - printk(KERN_INFO "sampling rates: %s\n", buf); if (a->format == AUDIO_CODING_TYPE_LPCM) - printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits); + snd_print_pcm_rates(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); + else if (a->max_bitrate) + snprintf(buf2, sizeof(buf2), + ", max bitrate = %d", a->max_bitrate); + else + buf2[0] = '\0'; - if (a->max_bitrate) - printk(KERN_INFO "max bitrate: %d\n", a->max_bitrate); - - if (a->profile) - printk(KERN_INFO "profile: %d\n", a->profile); + printk(KERN_INFO "supports coding type %s:" + " channels = %d, rates =%s%s\n", + cea_audio_coding_type_names[a->format], + a->channels, + buf, + buf2); } void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) @@ -422,29 +427,16 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) void snd_hdmi_show_eld(struct hdmi_eld *e) { int i; - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - printk(KERN_INFO "ELD buffer size is %d\n", e->eld_size); - printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len); - printk(KERN_INFO "vendor block len is %d\n", - e->eld_size - e->baseline_len * 4 - 4); - printk(KERN_INFO "ELD version is %s\n", - eld_versoin_names[e->eld_ver]); - printk(KERN_INFO "CEA EDID version is %s\n", - cea_edid_version_names[e->cea_edid_ver]); - printk(KERN_INFO "manufacture id is 0x%x\n", e->manufacture_id); - printk(KERN_INFO "product id is 0x%x\n", e->product_id); - printk(KERN_INFO "port id is 0x%llx\n", (long long)e->port_id); - printk(KERN_INFO "HDCP support is %d\n", e->support_hdcp); - printk(KERN_INFO "AI support is %d\n", e->support_ai); - printk(KERN_INFO "SAD count is %d\n", e->sad_count); - printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay); - printk(KERN_INFO "connection type is %s\n", - eld_connection_type_names[e->conn_type]); - printk(KERN_INFO "monitor name is %s\n", e->monitor_name); + printk(KERN_INFO "detected monitor %s at connection type %s\n", + e->monitor_name, + eld_connection_type_names[e->conn_type]); - snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf); + if (e->spk_alloc) { + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + printk(KERN_INFO "available speakers:%s\n", buf); + } for (i = 0; i < e->sad_count; i++) hdmi_show_short_audio_desc(e->sad + i); From 8563964617a6685d790448d9d7e45b49be90a448 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 19 Nov 2008 14:14:50 +0100 Subject: [PATCH 138/367] ALSA: hda - Show missing GPIO unsol bits The GPIO unsolicited event bits are read but not shown in the proc file. Let's fix it. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index d956e9769133..31b49bdc58f5 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -485,12 +485,13 @@ static void print_gpio(struct snd_info_buffer *buffer, for (i = 0; i < max; ++i) snd_iprintf(buffer, " IO[%d]: enable=%d, dir=%d, wake=%d, " - "sticky=%d, data=%d\n", i, + "sticky=%d, data=%d, unsol=%d\n", i, (enable & (1< Date: Wed, 19 Nov 2008 01:37:31 -0500 Subject: [PATCH 139/367] ASoC: Add PCM3008 ALSA SoC driver The PCM3008 is a 16-bit stereo audio codec. It accepts left-justified format for ADC, and right-justified format for DAC. Independent power-down modes for ADC and DAC are provided, as well as a digital de-emphasis filter (4 modes). [Merged Makefile & Kconfig, changed asm/gpio.h to linux/gpio.h -- broonie] Signed-off-by: Hugo Villeneuve Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/pcm3008.c | 201 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/pcm3008.h | 25 +++++ 4 files changed, 232 insertions(+) create mode 100644 sound/soc/codecs/pcm3008.c create mode 100644 sound/soc/codecs/pcm3008.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 04f49f5c3c3d..bf68052d6924 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -5,6 +5,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_AD73311 if I2C select SND_SOC_AK4535 if I2C select SND_SOC_CS4270 if I2C + select SND_SOC_PCM3008 select SND_SOC_SSM2602 if I2C select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC26 if SPI_MASTER @@ -70,6 +71,9 @@ config SND_SOC_CS4270_VD33_ERRATA config SND_SOC_L3 tristate +config SND_SOC_PCM3008 + tristate + config SND_SOC_SSM2602 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index de6572356d1b..9a20fddd09c7 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -4,6 +4,7 @@ snd-soc-ad73311-objs := ad73311.o snd-soc-ak4535-objs := ak4535.o snd-soc-cs4270-objs := cs4270.o snd-soc-l3-objs := l3.o +snd-soc-pcm3008-objs := pcm3008.o snd-soc-ssm2602-objs := ssm2602.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic26-objs := tlv320aic26.o @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o +obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c new file mode 100644 index 000000000000..2b26e1d80c8d --- /dev/null +++ b/sound/soc/codecs/pcm3008.c @@ -0,0 +1,201 @@ +/* + * ALSA Soc PCM3008 codec support + * + * Author: Hugo Villeneuve + * Copyright (C) 2008 Lyrtech inc + * + * Based on AC97 Soc codec, original copyright follow: + * Copyright 2005 Wolfson Microelectronics PLC. + * + * 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. + * + * Generic PCM3008 support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcm3008.h" + +#define PCM3008_VERSION "0.2" + +#define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000) + +struct snd_soc_dai pcm3008_dai = { + .name = "PCM3008 HiFi", + .type = SND_SOC_DAI_I2S, + .playback = { + .stream_name = "PCM3008 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = PCM3008_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "PCM3008 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = PCM3008_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; +EXPORT_SYMBOL_GPL(pcm3008_dai); + +static void pcm3008_gpio_free(struct pcm3008_setup_data *setup) +{ + gpio_free(setup->dem0_pin); + gpio_free(setup->dem1_pin); + gpio_free(setup->pdad_pin); + gpio_free(setup->pdda_pin); +} + +static int pcm3008_soc_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct pcm3008_setup_data *setup = socdev->codec_data; + int ret = 0; + + printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION); + + socdev->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); + if (!socdev->codec) + return -ENOMEM; + + codec = socdev->codec; + mutex_init(&codec->mutex); + + codec->name = "PCM3008"; + codec->owner = THIS_MODULE; + codec->dai = &pcm3008_dai; + codec->num_dai = 1; + codec->write = NULL; + codec->read = NULL; + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + /* Register PCMs. */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + printk(KERN_ERR "pcm3008: failed to create pcms\n"); + goto pcm_err; + } + + /* Register Card. */ + ret = snd_soc_register_card(socdev); + if (ret < 0) { + printk(KERN_ERR "pcm3008: failed to register card\n"); + goto card_err; + } + + /* DEM1 DEM0 DE-EMPHASIS_MODE + * Low Low De-emphasis 44.1 kHz ON + * Low High De-emphasis OFF + * High Low De-emphasis 48 kHz ON + * High High De-emphasis 32 kHz ON + */ + + /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */ + ret = gpio_request(setup->dem0_pin, "codec_dem0"); + if (ret == 0) + ret = gpio_direction_output(setup->dem0_pin, 1); + if (ret != 0) + goto gpio_err; + + /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */ + ret = gpio_request(setup->dem1_pin, "codec_dem1"); + if (ret == 0) + ret = gpio_direction_output(setup->dem1_pin, 0); + if (ret != 0) + goto gpio_err; + + /* Configure PDAD GPIO. */ + ret = gpio_request(setup->pdad_pin, "codec_pdad"); + if (ret == 0) + ret = gpio_direction_output(setup->pdad_pin, 1); + if (ret != 0) + goto gpio_err; + + /* Configure PDDA GPIO. */ + ret = gpio_request(setup->pdda_pin, "codec_pdda"); + if (ret == 0) + ret = gpio_direction_output(setup->pdda_pin, 1); + if (ret != 0) + goto gpio_err; + + return ret; + +gpio_err: + pcm3008_gpio_free(setup); +card_err: + snd_soc_free_pcms(socdev); +pcm_err: + kfree(socdev->codec); + + return ret; +} + +static int pcm3008_soc_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct pcm3008_setup_data *setup = socdev->codec_data; + + if (!codec) + return 0; + + pcm3008_gpio_free(setup); + snd_soc_free_pcms(socdev); + kfree(socdev->codec); + + return 0; +} + +#ifdef CONFIG_PM +static int pcm3008_soc_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct pcm3008_setup_data *setup = socdev->codec_data; + + gpio_set_value(setup->pdad_pin, 0); + gpio_set_value(setup->pdda_pin, 0); + + return 0; +} + +static int pcm3008_soc_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct pcm3008_setup_data *setup = socdev->codec_data; + + gpio_set_value(setup->pdad_pin, 1); + gpio_set_value(setup->pdda_pin, 1); + + return 0; +} +#else +#define pcm3008_soc_suspend NULL +#define pcm3008_soc_resume NULL +#endif + +struct snd_soc_codec_device soc_codec_dev_pcm3008 = { + .probe = pcm3008_soc_probe, + .remove = pcm3008_soc_remove, + .suspend = pcm3008_soc_suspend, + .resume = pcm3008_soc_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008); + +MODULE_DESCRIPTION("Soc PCM3008 driver"); +MODULE_AUTHOR("Hugo Villeneuve"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h new file mode 100644 index 000000000000..d04e87d3c060 --- /dev/null +++ b/sound/soc/codecs/pcm3008.h @@ -0,0 +1,25 @@ +/* + * PCM3008 ALSA SoC Layer + * + * Author: Hugo Villeneuve + * Copyright (C) 2008 Lyrtech inc + * + * 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 __LINUX_SND_SOC_PCM3008_H +#define __LINUX_SND_SOC_PCM3008_H + +struct pcm3008_setup_data { + unsigned dem0_pin; + unsigned dem1_pin; + unsigned pdad_pin; + unsigned pdda_pin; +}; + +extern struct snd_soc_codec_device soc_codec_dev_pcm3008; +extern struct snd_soc_dai pcm3008_dai; + +#endif From 08bd16869645f435eba6a612d166532b3047c5f7 Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Wed, 19 Nov 2008 01:37:32 -0500 Subject: [PATCH 140/367] ASoC: Add driver for the Lyrtech SFFSDR board The PCM3008 is used on the Lyrtech SFFSDR board, in conjunction with an FPGA that generates the bit clock and the master clock [Downgraded the rate debug print to pr_debug() in hw_params, converted asm/gpio.h to linux/gpio.h -- broonie] Signed-off-by: Hugo Villeneuve Signed-off-by: Mark Brown --- sound/soc/davinci/Kconfig | 10 ++ sound/soc/davinci/Makefile | 2 + sound/soc/davinci/davinci-sffsdr.c | 156 +++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 sound/soc/davinci/davinci-sffsdr.c diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 8f7e33834902..b502741692d6 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -17,3 +17,13 @@ config SND_DAVINCI_SOC_EVM help Say Y if you want to add support for SoC audio on TI DaVinci EVM platform. + +config SND_DAVINCI_SOC_SFFSDR + tristate "SoC Audio support for SFFSDR" + depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR + select SND_DAVINCI_SOC_I2S + select SND_SOC_PCM3008 + select SFFSDR_FPGA + help + Say Y if you want to add support for SoC audio on + Lyrtech SFFSDR board. diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index ca772e5b4637..ca8bae1fc3f6 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -7,5 +7,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o # DAVINCI Machine Support snd-soc-evm-objs := davinci-evm.o +snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o +obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c new file mode 100644 index 000000000000..69a8a769f4d8 --- /dev/null +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -0,0 +1,156 @@ +/* + * ASoC driver for Lyrtech SFFSDR board. + * + * Author: Hugo Villeneuve + * Copyright (C) 2008 Lyrtech inc + * + * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow: + * Copyright: (C) 2007 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 version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "../codecs/pcm3008.h" +#include "davinci-pcm.h" +#include "davinci-i2s.h" + +static int sffsdr_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int fs; + int ret = 0; + + /* Set cpu DAI configuration: + * CLKX and CLKR are the inputs for the Sample Rate Generator. + * FSX and FSR are outputs, driven by the sample Rate Generator. */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_RIGHT_J | + SND_SOC_DAIFMT_CBM_CFS | + SND_SOC_DAIFMT_IB_NF); + if (ret < 0) + return ret; + + /* Fsref can be 32000, 44100 or 48000. */ + fs = params_rate(params); + + pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); + + return sffsdr_fpga_set_codec_fs(fs); +} + +static struct snd_soc_ops sffsdr_ops = { + .hw_params = sffsdr_hw_params, +}; + +/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link sffsdr_dai = { + .name = "PCM3008", /* Codec name */ + .stream_name = "PCM3008 HiFi", + .cpu_dai = &davinci_i2s_dai, + .codec_dai = &pcm3008_dai, + .ops = &sffsdr_ops, +}; + +/* davinci-sffsdr audio machine driver */ +static struct snd_soc_machine snd_soc_machine_sffsdr = { + .name = "DaVinci SFFSDR", + .dai_link = &sffsdr_dai, + .num_links = 1, +}; + +/* sffsdr audio private data */ +static struct pcm3008_setup_data sffsdr_pcm3008_setup = { + .dem0_pin = GPIO(45), + .dem1_pin = GPIO(46), + .pdad_pin = GPIO(47), + .pdda_pin = GPIO(38), +}; + +/* sffsdr audio subsystem */ +static struct snd_soc_device sffsdr_snd_devdata = { + .machine = &snd_soc_machine_sffsdr, + .platform = &davinci_soc_platform, + .codec_dev = &soc_codec_dev_pcm3008, + .codec_data = &sffsdr_pcm3008_setup, +}; + +static struct resource sffsdr_snd_resources[] = { + { + .start = DAVINCI_MCBSP_BASE, + .end = DAVINCI_MCBSP_BASE + SZ_8K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct evm_snd_platform_data sffsdr_snd_data = { + .tx_dma_ch = DAVINCI_DMA_MCBSP_TX, + .rx_dma_ch = DAVINCI_DMA_MCBSP_RX, +}; + +static struct platform_device *sffsdr_snd_device; + +static int __init sffsdr_init(void) +{ + int ret; + + sffsdr_snd_device = platform_device_alloc("soc-audio", 0); + if (!sffsdr_snd_device) { + printk(KERN_ERR "platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); + sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; + sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data; + + ret = platform_device_add_resources(sffsdr_snd_device, + sffsdr_snd_resources, + ARRAY_SIZE(sffsdr_snd_resources)); + if (ret) { + printk(KERN_ERR "platform device add ressources failed\n"); + goto error; + } + + ret = platform_device_add(sffsdr_snd_device); + if (ret) + goto error; + + return ret; + +error: + platform_device_put(sffsdr_snd_device); + return ret; +} + +static void __exit sffsdr_exit(void) +{ + platform_device_unregister(sffsdr_snd_device); +} + +module_init(sffsdr_init); +module_exit(sffsdr_exit); + +MODULE_AUTHOR("Hugo Villeneuve"); +MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver"); +MODULE_LICENSE("GPL"); From df573d2fd1b077b98ffc3eb62a9908075e69e578 Mon Sep 17 00:00:00 2001 From: Arun KS Date: Wed, 19 Nov 2008 17:45:19 +0530 Subject: [PATCH 141/367] ASoC: Add support for omap2evm board This patch adds twl4030 audio support on omap2evm Signed-off-by: Arun KS Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 9 +++ sound/soc/omap/Makefile | 2 + sound/soc/omap/omap2evm.c | 150 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 sound/soc/omap/omap2evm.c diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index cf40e42954af..6c56277e160b 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -30,4 +30,13 @@ config SND_OMAP_SOC_OVERO help Say Y if you want to add support for SoC audio on the Gumstix Overo. +config SND_OMAP_SOC_OMAP2EVM + tristate "SoC Audio support for OMAP2EVM board" + depends on SND_OMAP_SOC && MACH_OMAP2EVM + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the omap2evm board. + + diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index fefc9bed053a..f5da3cc764ae 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -9,8 +9,10 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o +snd-soc-omap2evm-objs := omap2evm.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o +obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c new file mode 100644 index 000000000000..c37621357d00 --- /dev/null +++ b/sound/soc/omap/omap2evm.c @@ -0,0 +1,150 @@ +/* + * omap2evm.c -- SoC audio machine driver for omap2evm board + * + * Author: Arun KS + * + * Based on sound/soc/omap/overo.c by Steve Sakoman + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int omap2evm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops omap2evm_ops = { + .hw_params = omap2evm_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap2evm_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap2evm_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_omap2evm = { + .name = "omap2evm", + .dai_link = &omap2evm_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device omap2evm_snd_devdata = { + .machine = &snd_soc_machine_omap2evm, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap2evm_snd_device; + +static int __init omap2evm_soc_init(void) +{ + int ret; + + if (!machine_is_omap2evm()) { + pr_debug("Not omap2evm!\n"); + return -ENODEV; + } + printk(KERN_INFO "omap2evm SoC init\n"); + + omap2evm_snd_device = platform_device_alloc("soc-audio", -1); + if (!omap2evm_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(omap2evm_snd_device, &omap2evm_snd_devdata); + omap2evm_snd_devdata.dev = &omap2evm_snd_device->dev; + *(unsigned int *)omap2evm_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(omap2evm_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(omap2evm_snd_device); + + return ret; +} +module_init(omap2evm_soc_init); + +static void __exit omap2evm_soc_exit(void) +{ + platform_device_unregister(omap2evm_snd_device); +} +module_exit(omap2evm_soc_exit); + +MODULE_AUTHOR("Arun KS "); +MODULE_DESCRIPTION("ALSA SoC omap2evm"); +MODULE_LICENSE("GPL"); From d0c36631bbee9eb89f2fe4251e0e9583f37156cd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 21:57:17 +0000 Subject: [PATCH 142/367] ASoC: s3c24xx_uda134x DAI accessor functions and static cleanup Missed these during review. Signed-off-by: Mark Brown --- sound/soc/s3c24xx/s3c24xx_uda134x.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index 487b010730b8..92d90f2f6901 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -63,7 +63,7 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = { static struct platform_device *s3c24xx_uda134x_snd_device; -int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) +static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) { int ret = 0; #ifdef ENFORCE_RATES @@ -115,7 +115,7 @@ int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) return ret; } -void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) +static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) { mutex_lock(&clk_lock); pr_debug("%s %d\n", __func__, clk_users); @@ -180,39 +180,38 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, clk_source , clk, - SND_SOC_CLOCK_IN); + ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk, + SND_SOC_CLOCK_IN); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, - fs_mode); + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, - S3C2410_IISMOD_32FS); + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, + S3C2410_IISMOD_32FS); if (ret < 0) return ret; - ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, - S3C24XX_PRESCALE(div, div)); + ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, + S3C24XX_PRESCALE(div, div)); if (ret < 0) return ret; /* set the codec system clock for DAC and ADC */ - ret = codec_dai->dai_ops.set_sysclk(codec_dai, 0, clk, - SND_SOC_CLOCK_OUT); + ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, + SND_SOC_CLOCK_OUT); if (ret < 0) return ret; From 9b0db7e7fd20d5a38844e9435f7d4246ea44978a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 22:17:49 +0000 Subject: [PATCH 143/367] ASoC: Convert blackfin machines to use DAI accessor functions Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ad73311.c | 2 +- sound/soc/blackfin/bf5xx-ssm2602.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 622c9b909532..47da49b9aeac 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -168,7 +168,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream, params_format(params)); /* set cpu DAI configuration */ - ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index e15f67fd7769..744a90e765d9 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -92,17 +92,17 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream, */ /* set codec DAI configuration */ - ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; - ret = codec_dai->dai_ops.set_sysclk(codec_dai, SSM2602_SYSCLK, clk, + ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk, SND_SOC_CLOCK_IN); if (ret < 0) return ret; From 41dda0fdd2cb22d989aa76fbbbd5a6514a3e0802 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 20 Nov 2008 09:24:52 +0800 Subject: [PATCH 144/367] ALSA: azx_probe() cleanup Replace 5 free-and-return-err blocks with goto-out-free ones. This makes the main logic more outstanding. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f73c13fdd409..3870ad622da6 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2317,40 +2317,30 @@ static int __devinit azx_probe(struct pci_dev *pci, } err = azx_create(card, pci, dev, pci_id->driver_data, &chip); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; card->private_data = chip; /* create codec instances */ err = azx_codec_create(chip, model[dev], probe_mask[dev]); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; /* create PCM streams */ err = snd_hda_build_pcms(chip->bus); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; /* create mixer controls */ err = azx_mixer_create(chip); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; snd_card_set_dev(card, &pci->dev); err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return err; - } + if (err < 0) + goto out_free; pci_set_drvdata(pci, card); chip->running = 1; @@ -2359,6 +2349,9 @@ static int __devinit azx_probe(struct pci_dev *pci, dev++; return err; +out_free: + snd_card_free(card); + return err; } static void __devexit azx_remove(struct pci_dev *pci) From 5b2d1ecac2a79b9438aed731557b8912564cedfd Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Tue, 18 Nov 2008 22:21:57 +0800 Subject: [PATCH 145/367] ALSA: hda: Added Realtek ALC888 model entry for Acer Aspire 4930G laptop Added Realtek ALC888 model entry for the Acer Aspire 4930G laptop that fixes the following features: - internal microphone - heaphone jack sense - channel mode Signed-off-by: Vincent Petry Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 115 ++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 3ab5fb1357a2..010aa66ab920 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -903,6 +903,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 6stack-dig-demo 6-jack digital for Intel demo board acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) acer-aspire Acer Aspire 9810 + acer-aspire-4930g Acer Aspire 4930G medion Medion Laptops medion-md2 Medion MD2 targa-dig Targa/MSI diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b7d34390eff4..6ec56c62cb18 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -216,6 +216,7 @@ enum { ALC883_TARGA_2ch_DIG, ALC883_ACER, ALC883_ACER_ASPIRE, + ALC888_ACER_ASPIRE_4930G, ALC883_MEDION, ALC883_MEDION_MD2, ALC883_LAPTOP_EAPD, @@ -1154,6 +1155,90 @@ static void alc_fix_pincfg(struct hda_codec *codec, } } +/* + * ALC888 Acer Aspire 4930G model + */ + +static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Unselect Front Mic by default in input mixer 3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, +/* enable unsolicited event fpr HP jack */ + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, +/* Connect Internal HP to front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect HP out to front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +static struct hda_input_mux alc888_acer_aspire_4930g_capture_source[2] = { + /* Front mic only available on one ADC */ + { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + { "Front Mic", 0xb }, + }, + }, + { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, + } +}; + +static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), + HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), + { } /* end */ +}; + +static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) +{ + unsigned int present; + present = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + /* Toggle the internal HP PIN (regular muting doesn't work) */ + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + (present ? 0x0 : PIN_OUT)); +} + +static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if (res >> 26 == ALC880_HP_EVENT) + alc888_acer_aspire_4930g_automute(codec); +} + /* * ALC880 3-stack model * @@ -6887,8 +6972,15 @@ static hda_nid_t alc883_adc_nids_alt[1] = { 0x08, }; +static hda_nid_t alc883_adc_nids_rev[2] = { + /* ADC2-1 */ + 0x09, 0x08 +}; + static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 }; +static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; + /* input MUX */ /* FIXME: should be a matrix-type input source selection */ @@ -8180,6 +8272,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", [ALC883_ACER] = "acer", [ALC883_ACER_ASPIRE] = "acer-aspire", + [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", [ALC883_MEDION] = "medion", [ALC883_MEDION_MD2] = "medion-md2", [ALC883_LAPTOP_EAPD] = "laptop-eapd", @@ -8205,6 +8298,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE), + SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", + ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), @@ -8376,6 +8471,26 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_acer_aspire_unsol_event, .init_hook = alc883_acer_aspire_automute, }, + [ALC888_ACER_ASPIRE_4930G] = { + .mixers = { alc888_acer_aspire_4930g_mixer, + alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, + alc888_acer_aspire_4930g_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), + .channel_mode = alc883_3ST_6ch_modes, + .need_dac_fix = 1, + .num_mux_defs = + ARRAY_SIZE(alc888_acer_aspire_4930g_capture_source), + .input_mux = alc888_acer_aspire_4930g_capture_source, + .unsol_event = alc888_acer_aspire_4930g_unsol_event, + .init_hook = alc888_acer_aspire_4930g_automute, + }, [ALC883_MEDION] = { .mixers = { alc883_fivestack_mixer, alc883_chmode_mixer }, From 1725b82a6e2721612a3572d0336f51f1f1c3cf54 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 02:25:48 +0100 Subject: [PATCH 146/367] ALSA: hda - make laptop-eapd model back for AD1986A The changes specific for Samsung laptops seem unapplicable to other hardware models like ASUS. The mic inputs are lost on such hardware by the change 5d5d5f43f1b835c375de9bd270cce030d16e2871. This patch adds back the old laptop-eapd model, and create a new model "samsung" for the new one specific to Samsung laptops with automatic mic selection feature. Reference: kernel bugzilla #12070 http://bugzilla.kernel.org/show_bug.cgi?id=12070 Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 3 +- sound/pci/hda/patch_analog.c | 49 +++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 010aa66ab920..e55081fdc8ab 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -984,9 +984,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 6stack 6-jack, separate surrounds (default) 3stack 3-stack, shared surrounds laptop 2-channel only (FSC V2060, Samsung M50) - laptop-eapd 2-channel with EAPD (Samsung R65, ASUS A6J) + laptop-eapd 2-channel with EAPD (ASUS A6J) laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) ultra 2-channel with EAPD (Samsung Ultra tablet PC) + samsung 2-channel with EAPD (Samsung R65) AD1988/AD1988B/AD1989A/AD1989B 6stack 6-jack diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 032cbb4bd985..0cc6be12b8b7 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -638,6 +638,36 @@ static struct hda_input_mux ad1986a_automic_capture_source = { }; static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { + HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), + HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), + HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = ad198x_mux_enum_info, + .get = ad198x_mux_enum_get, + .put = ad198x_mux_enum_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "External Amplifier", + .info = ad198x_eapd_info, + .get = ad198x_eapd_get, + .put = ad198x_eapd_put, + .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + }, + { } /* end */ +}; + +static struct snd_kcontrol_new ad1986a_samsung_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), @@ -930,6 +960,7 @@ enum { AD1986A_LAPTOP_EAPD, AD1986A_LAPTOP_AUTOMUTE, AD1986A_ULTRA, + AD1986A_SAMSUNG, AD1986A_MODELS }; @@ -940,6 +971,7 @@ static const char *ad1986a_models[AD1986A_MODELS] = { [AD1986A_LAPTOP_EAPD] = "laptop-eapd", [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", [AD1986A_ULTRA] = "ultra", + [AD1986A_SAMSUNG] = "samsung", }; static struct snd_pci_quirk ad1986a_cfg_tbl[] = { @@ -962,9 +994,9 @@ static struct snd_pci_quirk ad1986a_cfg_tbl[] = { SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG), + SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG), + SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG), SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), @@ -1046,6 +1078,17 @@ static int patch_ad1986a(struct hda_codec *codec) break; case AD1986A_LAPTOP_EAPD: spec->mixers[0] = ad1986a_laptop_eapd_mixers; + spec->num_init_verbs = 2; + spec->init_verbs[1] = ad1986a_eapd_init_verbs; + spec->multiout.max_channels = 2; + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = ad1986a_laptop_dac_nids; + if (!is_jack_available(codec, 0x25)) + spec->multiout.dig_out_nid = 0; + spec->input_mux = &ad1986a_laptop_eapd_capture_source; + break; + case AD1986A_SAMSUNG: + spec->mixers[0] = ad1986a_samsung_mixers; spec->num_init_verbs = 3; spec->init_verbs[1] = ad1986a_eapd_init_verbs; spec->init_verbs[2] = ad1986a_automic_verbs; From 218b5ffc0d3fa852624e67a1bb2528ca29274d6e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 21 Nov 2008 09:42:59 +0800 Subject: [PATCH 147/367] ALSA: hda - properly print ELD sample bits Fix bugs on printing the ELD sample bits. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/hda_proc.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index e848c30d9bf7..9d3e542d74a5 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -397,7 +397,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) snd_print_pcm_rates(a->rates, buf, sizeof(buf)); if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_print_pcm_rates(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); + snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8)); else if (a->max_bitrate) snprintf(buf2, sizeof(buf2), ", max bitrate = %d", a->max_bitrate); diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 31b49bdc58f5..56cee3a22214 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -120,7 +120,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) int i, j; for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) - if (pcm & (1 << i)) + if (pcm & (AC_SUPPCM_BITS_8 << i)) j += snprintf(buf + j, buflen - j, " %d", bits[i]); buf[j] = '\0'; /* necessary when j == 0 */ @@ -130,7 +130,6 @@ static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; - pcm = (pcm >> 16) & 0xff; snd_iprintf(buffer, " bits [0x%x]:", pcm); snd_print_pcm_bits(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); From db742104704cfb047732aa66451c608382da3aee Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 21 Nov 2008 12:34:05 +0800 Subject: [PATCH 148/367] ALSA: hda: modify monitor name to be consistent with other ELD proc items Rename "monitor name" to "monitor_name" to conform with the keyword style. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 9d3e542d74a5..248cddf0ee80 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -477,7 +477,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; - snd_iprintf(buffer, "monitor name\t\t%s\n", e->monitor_name); + snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); snd_iprintf(buffer, "connection_type\t\t%s\n", eld_connection_type_names[e->conn_type]); snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, From acdda7915eb5dae20b6e43b8b772b712b1ed32c3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 21 Nov 2008 11:41:50 +0800 Subject: [PATCH 149/367] ALSA: hda - support writing to the ELD proc file Allow users to fix quicks of ELD ROMs by writing new values to the ELD proc interface. The format is one or more lines of "name hex_value". Users can add/remove/modify up to 32 SAD(Short Audio Descriptor) entries. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 248cddf0ee80..d2b7ccca3bb3 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -500,6 +500,59 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, hdmi_print_sad_info(i, e->sad + i, buffer); } +static void hdmi_write_eld_item(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdmi_eld *e = entry->private_data; + char line[64]; + char name[64]; + char *sname; + long long val; + int n; + + while (!snd_info_get_line(buffer, line, sizeof(line))) { + if (sscanf(line, "%s %llx", name, &val) != 2) + continue; + if (!strcmp(name, "connection_type")) + e->conn_type = val; + else if (!strcmp(name, "port_id")) + e->port_id = val; + else if (!strcmp(name, "support_hdcp")) + e->support_hdcp = val; + else if (!strcmp(name, "support_ai")) + e->support_ai = val; + else if (!strcmp(name, "audio_sync_delay")) + e->aud_synch_delay = val; + else if (!strcmp(name, "speakers")) + e->spk_alloc = val; + else if (!strcmp(name, "sad_count")) + e->sad_count = val; + else if (!strncmp(name, "sad", 3)) { + sname = name + 4; + n = name[3] - '0'; + if (name[4] >= '0' && name[4] <= '9') { + sname++; + n = 10 * n + name[4] - '0'; + } + if (n < 0 || n > 31) /* double the CEA limit */ + continue; + if (!strcmp(sname, "_coding_type")) + e->sad[n].format = val; + else if (!strcmp(sname, "_channels")) + e->sad[n].channels = val; + else if (!strcmp(sname, "_rates")) + e->sad[n].rates = val; + else if (!strcmp(sname, "_bits")) + e->sad[n].sample_bits = val; + else if (!strcmp(sname, "_max_bitrate")) + e->sad[n].max_bitrate = val; + if (n >= e->sad_count) + e->sad_count = n + 1; + } + } +} + + int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) { char name[32]; @@ -512,6 +565,9 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) return err; snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); + entry->c.text.write = hdmi_write_eld_item; + entry->mode |= S_IWUSR; + return 0; } From 0623536ca3e8fd7cb8b7468b0fd4d61d80f0b6ea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 08:54:54 +0100 Subject: [PATCH 150/367] ALSA: hda - Add missing static for snd_hda_eld_proc_new() inline funciton Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_local.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index a2d01a9a0b16..c71505a4f99d 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -490,7 +490,8 @@ void snd_hdmi_show_eld(struct hdmi_eld *eld); #ifdef CONFIG_PROC_FS int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); #else -inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) +static inline int snd_hda_eld_proc_new(struct hda_codec *codec, + struct hdmi_eld *eld) { return 0; } From b94d3539de59ec6481e38f83c455324fd3aeabc1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 09:08:06 +0100 Subject: [PATCH 151/367] ALSA: hda - Fix double free of jack instances The jack instances created in patch_sigmatel.c may be double-freed. The device management code checks the invalid element, and thus there is no real breakage, but it spews annoying warning messages. But, we can't simply remove the release calls of these jack instances because they have to be freed when the codec is re-configured. Now, a new flag, bus->shutdown is introduced to indicate that the bus is really being unloaded, i.e. the objects managed by the device manager will be automatically deleted. We release these objects only when this flag isn't set. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/patch_sigmatel.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5d5e8012d6a5..a98ce5b11188 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -464,6 +464,7 @@ static int snd_hda_bus_free(struct hda_bus *bus) static int snd_hda_bus_dev_free(struct snd_device *device) { struct hda_bus *bus = device->device_data; + bus->shutdown = 1; return snd_hda_bus_free(bus); } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ee122b009fd4..a70b181bbace 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -617,6 +617,7 @@ struct hda_bus { /* misc op flags */ unsigned int needs_damn_long_delay :1; + unsigned int shutdown :1; /* being unloaded */ }; /* diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a501c9121649..4fa5189264b7 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3921,8 +3921,9 @@ static int stac92xx_init(struct hda_codec *codec) static void stac92xx_free_jacks(struct hda_codec *codec) { #ifdef CONFIG_SND_JACK + /* free jack instances manually when clearing/reconfiguring */ struct sigmatel_spec *spec = codec->spec; - if (spec->jacks.list) { + if (!codec->bus->shutdown && spec->jacks.list) { struct sigmatel_jack *jacks = spec->jacks.list; int i; for (i = 0; i < spec->jacks.used; i++) From f208dba97f2f3ff2fbcbe771195061e2a0dac870 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 09:11:50 +0100 Subject: [PATCH 152/367] ALSA: hda - Release ELD proc file Release ELD proc file when reconfigured so that no leak occurs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 11 ++++++++++- sound/pci/hda/hda_local.h | 8 ++++++++ sound/pci/hda/patch_intelhdmi.c | 5 ++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index d2b7ccca3bb3..8740e7be8b24 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -567,8 +567,17 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); entry->c.text.write = hdmi_write_eld_item; entry->mode |= S_IWUSR; + eld->proc_entry = entry; return 0; } -#endif +void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) +{ + if (!codec->bus->shutdown && eld->proc_entry) { + snd_device_free(codec->bus->card, eld->proc_entry); + eld->proc_entry = NULL; + } +} + +#endif /* CONFIG_PROC_FS */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index c71505a4f99d..bf7ba8b62973 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -481,6 +481,9 @@ struct hdmi_eld { int spk_alloc; int sad_count; struct cea_sad sad[ELD_MAX_SAD]; +#ifdef CONFIG_PROC_FS + struct snd_info_entry *proc_entry; +#endif }; int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); @@ -489,12 +492,17 @@ void snd_hdmi_show_eld(struct hdmi_eld *eld); #ifdef CONFIG_PROC_FS int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); +void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); #else static inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) { return 0; } +static inline void snd_hda_eld_proc_free(struct hda_codec *codec, + struct hdmi_eld *eld) +{ +} #endif #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 5393f84f6755..58aaf06589a8 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -637,7 +637,10 @@ static int intel_hdmi_init(struct hda_codec *codec) static void intel_hdmi_free(struct hda_codec *codec) { - kfree(codec->spec); + struct intel_hdmi_spec *spec = codec->spec; + + snd_hda_eld_proc_free(codec, &spec->sink_eld); + kfree(spec); } static struct hda_codec_ops intel_hdmi_patch_ops = { From e7ee058cac89ec2f2c0c9ab0ec92a3776c182642 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 09:26:20 +0100 Subject: [PATCH 153/367] ALSA: hda - Make CONFIG_SND_HDA_RECONFIG for codec reconfiguration Make the codec re-configuration feature selectable via Kconfig, CONFIG_SND_HDA_RECONFIG. Also mark it as experimental (as it really is). Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 9 +++++++++ sound/pci/hda/hda_hwdep.c | 4 ++++ sound/pci/hda/hda_local.h | 10 +++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 157a0a6b10ae..cc6cf89c32e6 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -518,6 +518,15 @@ config SND_HDA_HWDEP This interface can be used for out-of-band communication with codecs for debugging purposes. +config SND_HDA_RECONFIG + bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" + depends on SND_HDA_HWDEP && EXPERIMENTAL + 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 + codec configuration, change the codec setup, add extra verbs, + and re-configure the codec dynamically. + config SND_HDA_INPUT_BEEP bool "Support digital beep via input layer" depends on SND_HDA_INTEL diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 653da1d3e4df..5868bbc131cd 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -145,6 +145,8 @@ int __devinit snd_hda_create_hwdep(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_RECONFIG + /* * sysfs interface */ @@ -347,3 +349,5 @@ int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) hwdep->device, &codec_attrs[i]); return 0; } + +#endif /* CONFIG_SND_HDA_RECONFIG */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index bf7ba8b62973..6f2fe0f9fdd8 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -409,11 +409,19 @@ void snd_hda_ctls_clear(struct hda_codec *codec); */ #ifdef CONFIG_SND_HDA_HWDEP int snd_hda_create_hwdep(struct hda_codec *codec); -int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); #else static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } #endif +#ifdef CONFIG_SND_HDA_RECONFIG +int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); +#else +static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) +{ + return 0; +} +#endif + /* * power-management */ From 11b444d5627d87beb55029601cf8d2c9fa9324fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 09:32:40 +0100 Subject: [PATCH 154/367] ALSA: hda - Move HD-audio Kconfig items to sound/pci/hda/Kconfig Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 146 +----------------------------------------- sound/pci/hda/Kconfig | 139 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 145 deletions(-) create mode 100644 sound/pci/hda/Kconfig diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index cc6cf89c32e6..caebf296b62b 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -497,151 +497,7 @@ config SND_FM801_TEA575X depends on SND_FM801_TEA575X_BOOL default SND_FM801 -config SND_HDA_INTEL - tristate "Intel HD Audio" - select SND_PCM - select SND_VMASTER - select SND_JACK if INPUT=y || INPUT=SND - help - Say Y here to include support for Intel "High Definition - Audio" (Azalia) motherboard devices. - - To compile this driver as a module, choose M here: the module - will be called snd-hda-intel. - -config SND_HDA_HWDEP - bool "Build hwdep interface for HD-audio driver" - depends on SND_HDA_INTEL - select SND_HWDEP - help - Say Y here to build a hwdep interface for HD-audio driver. - This interface can be used for out-of-band communication - with codecs for debugging purposes. - -config SND_HDA_RECONFIG - bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" - depends on SND_HDA_HWDEP && EXPERIMENTAL - 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 - codec configuration, change the codec setup, add extra verbs, - and re-configure the codec dynamically. - -config SND_HDA_INPUT_BEEP - bool "Support digital beep via input layer" - depends on SND_HDA_INTEL - depends on INPUT=y || INPUT=SND_HDA_INTEL - help - Say Y here to build a digital beep interface for HD-audio - driver. This interface is used to generate digital beeps. - -config SND_HDA_CODEC_REALTEK - bool "Build Realtek HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Realtek HD-audio codec support in - snd-hda-intel driver, such as ALC880. - -config SND_HDA_CODEC_ANALOG - bool "Build Analog Device HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Analog Device HD-audio codec support in - snd-hda-intel driver, such as AD1986A. - -config SND_HDA_CODEC_SIGMATEL - bool "Build IDT/Sigmatel HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include IDT (Sigmatel) HD-audio codec support in - snd-hda-intel driver, such as STAC9200. - -config SND_HDA_CODEC_VIA - bool "Build VIA HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include VIA HD-audio codec support in - snd-hda-intel driver, such as VT1708. - -config SND_HDA_CODEC_ATIHDMI - bool "Build ATI HDMI HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include ATI HDMI HD-audio codec support in - snd-hda-intel driver, such as ATI RS600 HDMI. - -config SND_HDA_CODEC_NVHDMI - bool "Build NVIDIA HDMI HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include NVIDIA HDMI HD-audio codec support in - snd-hda-intel driver, such as NVIDIA MCP78 HDMI. - -config SND_HDA_CODEC_INTELHDMI - bool "Build INTEL HDMI HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include INTEL HDMI HD-audio codec support in - snd-hda-intel driver, such as Eaglelake integrated HDMI. - -config SND_HDA_ELD - def_bool y - depends on SND_HDA_CODEC_INTELHDMI - -config SND_HDA_CODEC_CONEXANT - bool "Build Conexant HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Conexant HD-audio codec support in - snd-hda-intel driver, such as CX20549. - -config SND_HDA_CODEC_CMEDIA - bool "Build C-Media HD-audio codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include C-Media HD-audio codec support in - snd-hda-intel driver, such as CMI9880. - -config SND_HDA_CODEC_SI3054 - bool "Build Silicon Labs 3054 HD-modem codec support" - depends on SND_HDA_INTEL - default y - help - Say Y here to include Silicon Labs 3054 HD-modem codec - (and compatibles) support in snd-hda-intel driver. - -config SND_HDA_GENERIC - bool "Enable generic HD-audio codec parser" - depends on SND_HDA_INTEL - default y - help - Say Y here to enable the generic HD-audio codec parser - in snd-hda-intel driver. - -config SND_HDA_POWER_SAVE - bool "Aggressive power-saving on HD-audio" - depends on SND_HDA_INTEL && EXPERIMENTAL - help - Say Y here to enable more aggressive power-saving mode on - HD-audio driver. The power-saving timeout can be configured - via power_save option or over sysfs on-the-fly. - -config SND_HDA_POWER_SAVE_DEFAULT - int "Default time-out for HD-audio power-save mode" - depends on SND_HDA_POWER_SAVE - default 0 - help - The default time-out value in seconds for HD-audio automatic - power-save mode. 0 means to disable the power-save mode. +source "sound/pci/hda/Kconfig" config SND_HDSP tristate "RME Hammerfall DSP Audio" diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig new file mode 100644 index 000000000000..7c60f1a45a8d --- /dev/null +++ b/sound/pci/hda/Kconfig @@ -0,0 +1,139 @@ +menuconfig SND_HDA_INTEL + tristate "Intel HD Audio" + select SND_PCM + select SND_VMASTER + select SND_JACK if INPUT=y || INPUT=SND + help + Say Y here to include support for Intel "High Definition + Audio" (Azalia) and its compatible devices. + + This option enables the HD-audio controller. Don't forget + to choose the appropriate codec options below. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-intel. + +if SND_HDA_INTEL + +config SND_HDA_HWDEP + bool "Build hwdep interface for HD-audio driver" + select SND_HWDEP + help + Say Y here to build a hwdep interface for HD-audio driver. + This interface can be used for out-of-band communication + with codecs for debugging purposes. + +config SND_HDA_RECONFIG + bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" + depends on SND_HDA_HWDEP && EXPERIMENTAL + 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 + codec configuration, change the codec setup, add extra verbs, + and re-configure the codec dynamically. + +config SND_HDA_INPUT_BEEP + bool "Support digital beep via input layer" + depends on INPUT=y || INPUT=SND_HDA_INTEL + help + Say Y here to build a digital beep interface for HD-audio + driver. This interface is used to generate digital beeps. + +config SND_HDA_CODEC_REALTEK + bool "Build Realtek HD-audio codec support" + default y + help + Say Y here to include Realtek HD-audio codec support in + snd-hda-intel driver, such as ALC880. + +config SND_HDA_CODEC_ANALOG + bool "Build Analog Device HD-audio codec support" + default y + help + Say Y here to include Analog Device HD-audio codec support in + snd-hda-intel driver, such as AD1986A. + +config SND_HDA_CODEC_SIGMATEL + bool "Build IDT/Sigmatel HD-audio codec support" + default y + help + Say Y here to include IDT (Sigmatel) HD-audio codec support in + snd-hda-intel driver, such as STAC9200. + +config SND_HDA_CODEC_VIA + bool "Build VIA HD-audio codec support" + default y + help + Say Y here to include VIA HD-audio codec support in + snd-hda-intel driver, such as VT1708. + +config SND_HDA_CODEC_ATIHDMI + bool "Build ATI HDMI HD-audio codec support" + default y + help + Say Y here to include ATI HDMI HD-audio codec support in + snd-hda-intel driver, such as ATI RS600 HDMI. + +config SND_HDA_CODEC_NVHDMI + bool "Build NVIDIA HDMI HD-audio codec support" + default y + help + Say Y here to include NVIDIA HDMI HD-audio codec support in + snd-hda-intel driver, such as NVIDIA MCP78 HDMI. + +config SND_HDA_CODEC_INTELHDMI + bool "Build INTEL HDMI HD-audio codec support" + default y + help + Say Y here to include INTEL HDMI HD-audio codec support in + snd-hda-intel driver, such as Eaglelake integrated HDMI. + +config SND_HDA_ELD + def_bool y + depends on SND_HDA_CODEC_INTELHDMI + +config SND_HDA_CODEC_CONEXANT + bool "Build Conexant HD-audio codec support" + default y + help + Say Y here to include Conexant HD-audio codec support in + snd-hda-intel driver, such as CX20549. + +config SND_HDA_CODEC_CMEDIA + bool "Build C-Media HD-audio codec support" + default y + help + Say Y here to include C-Media HD-audio codec support in + snd-hda-intel driver, such as CMI9880. + +config SND_HDA_CODEC_SI3054 + bool "Build Silicon Labs 3054 HD-modem codec support" + default y + help + Say Y here to include Silicon Labs 3054 HD-modem codec + (and compatibles) support in snd-hda-intel driver. + +config SND_HDA_GENERIC + bool "Enable generic HD-audio codec parser" + default y + help + Say Y here to enable the generic HD-audio codec parser + in snd-hda-intel driver. + +config SND_HDA_POWER_SAVE + bool "Aggressive power-saving on HD-audio" + depends on EXPERIMENTAL + help + Say Y here to enable more aggressive power-saving mode on + HD-audio driver. The power-saving timeout can be configured + via power_save option or over sysfs on-the-fly. + +config SND_HDA_POWER_SAVE_DEFAULT + int "Default time-out for HD-audio power-save mode" + depends on SND_HDA_POWER_SAVE + default 0 + help + The default time-out value in seconds for HD-audio automatic + power-save mode. 0 means to disable the power-save mode. + +endif From 875065491fba8eb13219f16c36e79a6fb4e15c68 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 20:50:34 +0000 Subject: [PATCH 155/367] ASoC: Rename snd_soc_card to snd_soc_machine One of the issues with the ASoC v1 API which has been addressed in the ASoC v2 work that Liam Girdwood has done is that the ALSA card provided by ASoC is distributed around the ASoC structures. For example, machine wide data such as the struct snd_card are maintained as part of the CODEC data structure, preventing the use of multiple codecs. This has been addressed by refactoring the data structures so that all the data for the ALSA card is contained in a single structure snd_soc_card which replaces the existing snd_soc_machine and snd_soc_device. Begin the process of backporting this by renaming struct snd_soc_machine to struct snd_soc_card, better reflecting its function and bringing it closer to standard ALSA terminology. Signed-off-by: Mark Brown --- Documentation/sound/alsa/soc/machine.txt | 8 +-- include/sound/soc.h | 8 +-- sound/soc/atmel/playpaq_wm8510.c | 4 +- sound/soc/atmel/sam9g20_wm8731.c | 4 +- sound/soc/au1x/sample-ac97.c | 4 +- sound/soc/blackfin/bf5xx-ad1980.c | 6 +- sound/soc/blackfin/bf5xx-ad73311.c | 6 +- sound/soc/blackfin/bf5xx-ssm2602.c | 6 +- sound/soc/davinci/davinci-evm.c | 4 +- sound/soc/davinci/davinci-i2s.c | 8 +-- sound/soc/davinci/davinci-sffsdr.c | 4 +- sound/soc/fsl/fsl_dma.c | 2 +- sound/soc/fsl/mpc8610_hpcd.c | 6 +- sound/soc/fsl/soc-of-simple.c | 10 +-- sound/soc/omap/n810.c | 4 +- sound/soc/omap/omap2evm.c | 4 +- sound/soc/omap/omap3beagle.c | 4 +- sound/soc/omap/osk5912.c | 4 +- sound/soc/omap/overo.c | 4 +- sound/soc/pxa/corgi.c | 4 +- sound/soc/pxa/e800_wm9712.c | 6 +- sound/soc/pxa/em-x270.c | 4 +- sound/soc/pxa/palm27x.c | 4 +- sound/soc/pxa/poodle.c | 4 +- sound/soc/pxa/spitz.c | 4 +- sound/soc/pxa/tosa.c | 6 +- sound/soc/s3c24xx/ln2440sbc_alc650.c | 6 +- sound/soc/s3c24xx/neo1973_wm8753.c | 6 +- sound/soc/s3c24xx/s3c24xx_uda134x.c | 4 +- sound/soc/s3c24xx/smdk2443_wm9710.c | 6 +- sound/soc/sh/sh7760-ac97.c | 4 +- sound/soc/soc-core.c | 90 ++++++++++++------------ sound/soc/soc-dapm.c | 6 +- 33 files changed, 127 insertions(+), 127 deletions(-) diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index f370e7db86af..4a9f51e2905c 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -9,7 +9,7 @@ the audio subsystem with the kernel as a platform device and is represented by the following struct:- /* SoC machine */ -struct snd_soc_machine { +struct snd_soc_card {_ char *name; int (*probe)(struct platform_device *pdev); @@ -67,10 +67,10 @@ static struct snd_soc_dai_link corgi_dai = { .ops = &corgi_ops, }; -struct snd_soc_machine then sets up the machine with it's DAIs. e.g. +struct snd_soc_card then sets up the machine with it's DAIs. e.g. /* corgi audio machine driver */ -static struct snd_soc_machine snd_soc_machine_corgi = { +static struct snd_soc_card snd_soc_corgi = { .name = "Corgi", .dai_link = &corgi_dai, .num_links = 1, @@ -90,7 +90,7 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { - .machine = &snd_soc_machine_corgi, + .machine = &snd_soc_corgi, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, diff --git a/include/sound/soc.h b/include/sound/soc.h index 077dfe4e51f0..3be17b3c650c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -482,8 +482,8 @@ struct snd_soc_dai_link { struct snd_pcm *pcm; }; -/* SoC machine */ -struct snd_soc_machine { +/* SoC card */ +struct snd_soc_card { char *name; int (*probe)(struct platform_device *pdev); @@ -497,7 +497,7 @@ struct snd_soc_machine { int (*resume_post)(struct platform_device *pdev); /* callbacks */ - int (*set_bias_level)(struct snd_soc_machine *, + int (*set_bias_level)(struct snd_soc_card *, enum snd_soc_bias_level level); /* CPU <--> Codec DAI links */ @@ -508,7 +508,7 @@ struct snd_soc_machine { /* SoC Device - the audio subsystem */ struct snd_soc_device { struct device *dev; - struct snd_soc_machine *machine; + struct snd_soc_card *card; struct snd_soc_platform *platform; struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index ea7935d2a66d..d40b5a52a8d2 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -361,7 +361,7 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = { -static struct snd_soc_machine snd_soc_machine_playpaq = { +static struct snd_soc_card snd_soc_playpaq = { .name = "LRS_PlayPaq_WM8510", .dai_link = &playpaq_wm8510_dai, .num_links = 1, @@ -377,7 +377,7 @@ static struct wm8510_setup_data playpaq_wm8510_setup = { static struct snd_soc_device playpaq_wm8510_snd_devdata = { - .machine = &snd_soc_machine_playpaq, + .card = &snd_soc_playpaq, .platform = &at32_soc_platform, .codec_dev = &soc_codec_dev_wm8510, .codec_data = &playpaq_wm8510_setup, diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 710addcc66b3..fdc1d0206e0b 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -242,7 +242,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = { .ops = &at91sam9g20ek_ops, }; -static struct snd_soc_machine snd_soc_machine_at91sam9g20ek = { +static struct snd_soc_card snd_soc_at91sam9g20ek = { .name = "WM8731", .dai_link = &at91sam9g20ek_dai, .num_links = 1, @@ -254,7 +254,7 @@ static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { }; static struct snd_soc_device at91sam9g20ek_snd_devdata = { - .machine = &snd_soc_machine_at91sam9g20ek, + .card = &snd_soc_at91sam9g20ek, .platform = &atmel_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &at91sam9g20ek_wm8731_setup, diff --git a/sound/soc/au1x/sample-ac97.c b/sound/soc/au1x/sample-ac97.c index f75ae7f62c3d..27683eb7905e 100644 --- a/sound/soc/au1x/sample-ac97.c +++ b/sound/soc/au1x/sample-ac97.c @@ -42,14 +42,14 @@ static struct snd_soc_dai_link au1xpsc_sample_ac97_dai = { .ops = NULL, }; -static struct snd_soc_machine au1xpsc_sample_ac97_machine = { +static struct snd_soc_card au1xpsc_sample_ac97_machine = { .name = "Au1xxx PSC AC97 Audio", .dai_link = &au1xpsc_sample_ac97_dai, .num_links = 1, }; static struct snd_soc_device au1xpsc_sample_ac97_devdata = { - .machine = &au1xpsc_sample_ac97_machine, + .card = &au1xpsc_sample_ac97_machine, .platform = &au1xpsc_soc_platform, /* see dbdma2.c */ .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index 124425d22320..36c569a43ce1 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c @@ -43,7 +43,7 @@ #include "bf5xx-ac97-pcm.h" #include "bf5xx-ac97.h" -static struct snd_soc_machine bf5xx_board; +static struct snd_soc_card bf5xx_board; static int bf5xx_board_startup(struct snd_pcm_substream *substream) { @@ -67,14 +67,14 @@ static struct snd_soc_dai_link bf5xx_board_dai = { .ops = &bf5xx_board_ops, }; -static struct snd_soc_machine bf5xx_board = { +static struct snd_soc_card bf5xx_board = { .name = "bf5xx-board", .dai_link = &bf5xx_board_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_board_snd_devdata = { - .machine = &bf5xx_board, + .card = &bf5xx_board, .platform = &bf5xx_ac97_soc_platform, .codec_dev = &soc_codec_dev_ad1980, }; diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 47da49b9aeac..57da14799375 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -65,7 +65,7 @@ #define GPIO_SE CONFIG_SND_BFIN_AD73311_SE -static struct snd_soc_machine bf5xx_ad73311; +static struct snd_soc_card bf5xx_ad73311; static int snd_ad73311_startup(void) { @@ -190,7 +190,7 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai = { .ops = &bf5xx_ad73311_ops, }; -static struct snd_soc_machine bf5xx_ad73311 = { +static struct snd_soc_card bf5xx_ad73311 = { .name = "bf5xx_ad73311", .probe = bf5xx_probe, .dai_link = &bf5xx_ad73311_dai, @@ -198,7 +198,7 @@ static struct snd_soc_machine bf5xx_ad73311 = { }; static struct snd_soc_device bf5xx_ad73311_snd_devdata = { - .machine = &bf5xx_ad73311, + .card = &bf5xx_ad73311, .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ad73311, }; diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index 744a90e765d9..0078dfcd95b9 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -44,7 +44,7 @@ #include "bf5xx-i2s-pcm.h" #include "bf5xx-i2s.h" -static struct snd_soc_machine bf5xx_ssm2602; +static struct snd_soc_card bf5xx_ssm2602; static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream) { @@ -135,14 +135,14 @@ static struct ssm2602_setup_data bf5xx_ssm2602_setup = { .i2c_address = 0x1b, }; -static struct snd_soc_machine bf5xx_ssm2602 = { +static struct snd_soc_card bf5xx_ssm2602 = { .name = "bf5xx_ssm2602", .dai_link = &bf5xx_ssm2602_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { - .machine = &bf5xx_ssm2602, + .card = &bf5xx_ssm2602, .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ssm2602, .codec_data = &bf5xx_ssm2602_setup, diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 9e6062cd6b59..2ce34d44b15c 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -128,7 +128,7 @@ static struct snd_soc_dai_link evm_dai = { }; /* davinci-evm audio machine driver */ -static struct snd_soc_machine snd_soc_machine_evm = { +static struct snd_soc_card snd_soc_card_evm = { .name = "DaVinci EVM", .dai_link = &evm_dai, .num_links = 1, @@ -142,7 +142,7 @@ static struct aic3x_setup_data evm_aic3x_setup = { /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { - .machine = &snd_soc_machine_evm, + .card = &snd_soc_card_evm, .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &evm_aic3x_setup, diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 11c20d0b7bcc..95df51e803b4 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -375,8 +375,8 @@ static int davinci_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; + struct snd_soc_card *card = socdev->card; + struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea; struct evm_snd_platform_data *pdata; @@ -437,8 +437,8 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; + struct snd_soc_card *card = socdev->card; + struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev = cpu_dai->private_data; struct resource *mem; diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 69a8a769f4d8..fa38f9cd3506 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -73,7 +73,7 @@ static struct snd_soc_dai_link sffsdr_dai = { }; /* davinci-sffsdr audio machine driver */ -static struct snd_soc_machine snd_soc_machine_sffsdr = { +static struct snd_soc_card snd_soc_sffsdr = { .name = "DaVinci SFFSDR", .dai_link = &sffsdr_dai, .num_links = 1, @@ -89,7 +89,7 @@ static struct pcm3008_setup_data sffsdr_pcm3008_setup = { /* sffsdr audio subsystem */ static struct snd_soc_device sffsdr_snd_devdata = { - .machine = &snd_soc_machine_sffsdr, + .card = &snd_soc_sffsdr, .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_pcm3008, .codec_data = &sffsdr_pcm3008_setup, diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index d2d3da9729f2..bf92331b4768 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -284,7 +284,7 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) * fsl_dma_new: initialize this PCM driver. * * This function is called when the codec driver calls snd_soc_new_pcms(), - * once for each .dai_link in the machine driver's snd_soc_machine + * once for each .dai_link in the machine driver's snd_soc_card * structure. */ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 94f89debde1f..1cf4d6eeb538 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -29,7 +29,7 @@ struct mpc8610_hpcd_data { struct snd_soc_device sound_devdata; struct snd_soc_dai_link dai; - struct snd_soc_machine machine; + struct snd_soc_card machine; unsigned int dai_format; unsigned int codec_clk_direction; unsigned int cpu_clk_direction; @@ -185,7 +185,7 @@ static struct snd_soc_ops mpc8610_hpcd_ops = { /** * mpc8610_hpcd_machine: ASoC machine data */ -static struct snd_soc_machine mpc8610_hpcd_machine = { +static struct snd_soc_card mpc8610_hpcd_machine = { .probe = mpc8610_hpcd_machine_probe, .remove = mpc8610_hpcd_machine_remove, .name = "MPC8610 HPCD", @@ -465,7 +465,7 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, goto error; } - machine_data->sound_devdata.machine = &mpc8610_hpcd_machine; + machine_data->sound_devdata.card = &mpc8610_hpcd_machine; machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; machine_data->sound_devdata.platform = &fsl_soc_platform; diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c index 0382fdac51cd..53be6491320a 100644 --- a/sound/soc/fsl/soc-of-simple.c +++ b/sound/soc/fsl/soc-of-simple.c @@ -31,7 +31,7 @@ struct of_snd_soc_device { int id; struct list_head list; struct snd_soc_device device; - struct snd_soc_machine machine; + struct snd_soc_card card; struct snd_soc_dai_link dai_link; struct platform_device *pdev; struct device_node *platform_node; @@ -58,9 +58,9 @@ of_snd_soc_get_device(struct device_node *codec_node) /* Initialize the structure and add it to the global list */ of_soc->codec_node = codec_node; of_soc->id = of_snd_soc_next_index++; - of_soc->machine.dai_link = &of_soc->dai_link; - of_soc->machine.num_links = 1; - of_soc->device.machine = &of_soc->machine; + of_soc->card.dai_link = &of_soc->dai_link; + of_soc->card.num_links = 1; + of_soc->device.card = &of_soc->card; of_soc->dai_link.ops = &of_snd_soc_ops; list_add(&of_soc->list, &of_snd_soc_device_list); @@ -159,7 +159,7 @@ int of_snd_soc_register_platform(struct snd_soc_platform *platform, of_soc->platform_node = node; of_soc->dai_link.cpu_dai = cpu_dai; of_soc->device.platform = platform; - of_soc->machine.name = of_soc->dai_link.cpu_dai->name; + of_soc->card.name = of_soc->dai_link.cpu_dai->name; /* Now try to register the SoC device */ of_snd_soc_register_device(of_soc); diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index fae3ad36e0bf..d216b4f9e14e 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -282,7 +282,7 @@ static struct snd_soc_dai_link n810_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_n810 = { +static struct snd_soc_card snd_soc_n810 = { .name = "N810", .dai_link = &n810_dai, .num_links = 1, @@ -298,7 +298,7 @@ static struct aic3x_setup_data n810_aic33_setup = { /* Audio subsystem */ static struct snd_soc_device n810_snd_devdata = { - .machine = &snd_soc_machine_n810, + .card = &snd_soc_n810, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &n810_aic33_setup, diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index c37621357d00..5bea31157a94 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -90,7 +90,7 @@ static struct snd_soc_dai_link omap2evm_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_omap2evm = { +static struct snd_soc_card snd_soc_omap2evm = { .name = "omap2evm", .dai_link = &omap2evm_dai, .num_links = 1, @@ -98,7 +98,7 @@ static struct snd_soc_machine snd_soc_machine_omap2evm = { /* Audio subsystem */ static struct snd_soc_device omap2evm_snd_devdata = { - .machine = &snd_soc_machine_omap2evm, + .card = &snd_soc_omap2evm, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index ec84a9bbc563..3ed25464627f 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -88,7 +88,7 @@ static struct snd_soc_dai_link omap3beagle_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_omap3beagle = { +static struct snd_soc_card snd_soc_omap3beagle = { .name = "omap3beagle", .dai_link = &omap3beagle_dai, .num_links = 1, @@ -96,7 +96,7 @@ static struct snd_soc_machine snd_soc_machine_omap3beagle = { /* Audio subsystem */ static struct snd_soc_device omap3beagle_snd_devdata = { - .machine = &snd_soc_machine_omap3beagle, + .card = &snd_soc_omap3beagle, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 0fe733796898..7a8f14d0c772 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -143,7 +143,7 @@ static struct snd_soc_dai_link osk_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_osk = { +static struct snd_soc_card snd_soc_card_osk = { .name = "OSK5912", .dai_link = &osk_dai, .num_links = 1, @@ -151,7 +151,7 @@ static struct snd_soc_machine snd_soc_machine_osk = { /* Audio subsystem */ static struct snd_soc_device osk_snd_devdata = { - .machine = &snd_soc_machine_osk, + .card = &snd_soc_card_osk, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_tlv320aic23, }; diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index c26d1de7da51..eea0c372bb3f 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -88,7 +88,7 @@ static struct snd_soc_dai_link overo_dai = { }; /* Audio machine driver */ -static struct snd_soc_machine snd_soc_machine_overo = { +static struct snd_soc_card snd_soc_card_overo = { .name = "overo", .dai_link = &overo_dai, .num_links = 1, @@ -96,7 +96,7 @@ static struct snd_soc_machine snd_soc_machine_overo = { /* Audio subsystem */ static struct snd_soc_device overo_snd_devdata = { - .machine = &snd_soc_machine_overo, + .card = &snd_soc_card_overo, .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 2718eaf7895f..647f056a3cb3 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -314,7 +314,7 @@ static struct snd_soc_dai_link corgi_dai = { }; /* corgi audio machine driver */ -static struct snd_soc_machine snd_soc_machine_corgi = { +static struct snd_soc_card snd_soc_corgi = { .name = "Corgi", .dai_link = &corgi_dai, .num_links = 1, @@ -328,7 +328,7 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { - .machine = &snd_soc_machine_corgi, + .card = &snd_soc_corgi, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 6781c5be242f..60c64861512a 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -29,7 +29,7 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static struct snd_soc_machine e800; +static struct snd_soc_card e800; static struct snd_soc_dai_link e800_dai[] = { { @@ -40,14 +40,14 @@ static struct snd_soc_dai_link e800_dai[] = { }, }; -static struct snd_soc_machine e800 = { +static struct snd_soc_card e800 = { .name = "Toshiba e800", .dai_link = e800_dai, .num_links = ARRAY_SIZE(e800_dai), }; static struct snd_soc_device e800_snd_devdata = { - .machine = &e800, + .card = &e800, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index e6ff6929ab4b..4a61925c3104 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -53,14 +53,14 @@ static struct snd_soc_dai_link em_x270_dai[] = { }, }; -static struct snd_soc_machine em_x270 = { +static struct snd_soc_card em_x270 = { .name = "EM-X270", .dai_link = em_x270_dai, .num_links = ARRAY_SIZE(em_x270_dai), }; static struct snd_soc_device em_x270_snd_devdata = { - .machine = &em_x270, + .card = &em_x270, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index e364abc700db..3bb8879ac8a2 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -189,14 +189,14 @@ static struct snd_soc_dai_link palm27x_dai[] = { }, }; -static struct snd_soc_machine palm27x_asoc = { +static struct snd_soc_card palm27x_asoc = { .name = "Palm/PXA27x", .dai_link = palm27x_dai, .num_links = ARRAY_SIZE(palm27x_dai), }; static struct snd_soc_device palm27x_snd_devdata = { - .machine = &palm27x_asoc, + .card = &palm27x_asoc, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 4d9930c52789..03b510ab2824 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = { }; /* poodle audio machine driver */ -static struct snd_soc_machine snd_soc_machine_poodle = { +static struct snd_soc_card snd_soc_poodle = { .name = "Poodle", .dai_link = &poodle_dai, .num_links = 1, @@ -290,7 +290,7 @@ static struct wm8731_setup_data poodle_wm8731_setup = { /* poodle audio subsystem */ static struct snd_soc_device poodle_snd_devdata = { - .machine = &snd_soc_machine_poodle, + .card = &snd_soc_poodle, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &poodle_wm8731_setup, diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index d307b6757e95..579d93368f14 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -319,7 +319,7 @@ static struct snd_soc_dai_link spitz_dai = { }; /* spitz audio machine driver */ -static struct snd_soc_machine snd_soc_machine_spitz = { +static struct snd_soc_card snd_soc_spitz = { .name = "Spitz", .dai_link = &spitz_dai, .num_links = 1, @@ -333,7 +333,7 @@ static struct wm8750_setup_data spitz_wm8750_setup = { /* spitz audio subsystem */ static struct snd_soc_device spitz_snd_devdata = { - .machine = &snd_soc_machine_spitz, + .card = &snd_soc_spitz, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8750, .codec_data = &spitz_wm8750_setup, diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index afefe41b8c46..9d9be5a14d14 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -38,7 +38,7 @@ #include "pxa2xx-pcm.h" #include "pxa2xx-ac97.h" -static struct snd_soc_machine tosa; +static struct snd_soc_card tosa; #define TOSA_HP 0 #define TOSA_MIC_INT 1 @@ -230,14 +230,14 @@ static struct snd_soc_dai_link tosa_dai[] = { }, }; -static struct snd_soc_machine tosa = { +static struct snd_soc_card tosa = { .name = "Tosa", .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), }; static struct snd_soc_device tosa_snd_devdata = { - .machine = &tosa, + .card = &tosa, .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index 4eab2c19c454..a70cbc0fa070 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -27,7 +27,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-ac97.h" -static struct snd_soc_machine ln2440sbc; +static struct snd_soc_card ln2440sbc; static struct snd_soc_dai_link ln2440sbc_dai[] = { { @@ -38,14 +38,14 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { }, }; -static struct snd_soc_machine ln2440sbc = { +static struct snd_soc_card ln2440sbc = { .name = "LN2440SBC", .dai_link = ln2440sbc_dai, .num_links = ARRAY_SIZE(ln2440sbc_dai), }; static struct snd_soc_device ln2440sbc_snd_ac97_devdata = { - .machine = &ln2440sbc, + .card = &ln2440sbc, .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 87ddfefcc2fb..528fc3f1b45b 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -59,7 +59,7 @@ #define NEO_CAPTURE_HEADSET 7 #define NEO_CAPTURE_BLUETOOTH 8 -static struct snd_soc_machine neo1973; +static struct snd_soc_card neo1973; static struct i2c_client *i2c; static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, @@ -579,7 +579,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { }, }; -static struct snd_soc_machine neo1973 = { +static struct snd_soc_card neo1973 = { .name = "neo1973", .dai_link = neo1973_dai, .num_links = ARRAY_SIZE(neo1973_dai), @@ -591,7 +591,7 @@ static struct wm8753_setup_data neo1973_wm8753_setup = { }; static struct snd_soc_device neo1973_snd_devdata = { - .machine = &neo1973, + .card = &neo1973, .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_wm8753, .codec_data = &neo1973_wm8753_setup, diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index 92d90f2f6901..23325fca1f64 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -232,7 +232,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { .ops = &s3c24xx_uda134x_ops, }; -static struct snd_soc_machine snd_soc_machine_s3c24xx_uda134x = { +static struct snd_soc_card snd_soc_s3c24xx_uda134x = { .name = "S3C24XX_UDA134X", .dai_link = &s3c24xx_uda134x_dai_link, .num_links = 1, @@ -270,7 +270,7 @@ static struct uda134x_platform_data s3c24xx_uda134x = { }; static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { - .machine = &snd_soc_machine_s3c24xx_uda134x, + .card = &snd_soc_s3c24xx_uda134x, .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_uda134x, .codec_data = &s3c24xx_uda134x, diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index 8515d6ff03f2..3d2e6a0417ec 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -23,7 +23,7 @@ #include "s3c24xx-pcm.h" #include "s3c24xx-ac97.h" -static struct snd_soc_machine smdk2443; +static struct snd_soc_card smdk2443; static struct snd_soc_dai_link smdk2443_dai[] = { { @@ -34,14 +34,14 @@ static struct snd_soc_dai_link smdk2443_dai[] = { }, }; -static struct snd_soc_machine smdk2443 = { +static struct snd_soc_card smdk2443 = { .name = "SMDK2443", .dai_link = smdk2443_dai, .num_links = ARRAY_SIZE(smdk2443_dai), }; static struct snd_soc_device smdk2443_snd_ac97_devdata = { - .machine = &smdk2443, + .card = &smdk2443, .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index 92bfaf4774a7..8b44f9c8a9ff 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c @@ -38,14 +38,14 @@ static struct snd_soc_dai_link sh7760_ac97_dai = { .ops = NULL, }; -static struct snd_soc_machine sh7760_ac97_soc_machine = { +static struct snd_soc_card sh7760_ac97_soc_machine = { .name = "SH7760 AC97", .dai_link = &sh7760_ac97_dai, .num_links = 1, }; static struct snd_soc_device sh7760_ac97_snd_devdata = { - .machine = &sh7760_ac97_soc_machine, + .card = &sh7760_ac97_soc_machine, .platform = &sh7760_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9feaa7b6dc34..c5cb9516fea4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -620,7 +620,7 @@ static struct snd_pcm_ops soc_pcm_ops = { static int soc_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; @@ -644,14 +644,14 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) } /* suspend all pcms */ - for (i = 0; i < machine->num_links; i++) - snd_pcm_suspend_all(machine->dai_link[i].pcm); + for (i = 0; i < card->num_links; i++) + snd_pcm_suspend_all(card->dai_link[i].pcm); - if (machine->suspend_pre) - machine->suspend_pre(pdev, state); + if (card->suspend_pre) + card->suspend_pre(pdev, state); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) @@ -676,14 +676,14 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) if (codec_dev->suspend) codec_dev->suspend(pdev, state); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) cpu_dai->suspend(pdev, cpu_dai); } - if (machine->suspend_post) - machine->suspend_post(pdev, state); + if (card->suspend_post) + card->suspend_post(pdev, state); return 0; } @@ -696,7 +696,7 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_device *socdev = container_of(work, struct snd_soc_device, deferred_resume_work); - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; @@ -709,11 +709,11 @@ static void soc_resume_deferred(struct work_struct *work) dev_info(socdev->dev, "starting resume work\n"); - if (machine->resume_pre) - machine->resume_pre(pdev); + if (card->resume_pre) + card->resume_pre(pdev); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) cpu_dai->resume(pdev, cpu_dai); } @@ -739,16 +739,16 @@ static void soc_resume_deferred(struct work_struct *work) dai->dai_ops.digital_mute(dai, 0); } - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) cpu_dai->resume(pdev, cpu_dai); if (platform->resume) platform->resume(pdev, cpu_dai); } - if (machine->resume_post) - machine->resume_post(pdev); + if (card->resume_post) + card->resume_post(pdev); dev_info(socdev->dev, "resume work completed\n"); @@ -779,18 +779,18 @@ static int soc_probe(struct platform_device *pdev) { int ret = 0, i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - if (machine->probe) { - ret = machine->probe(pdev); + if (card->probe) { + ret = card->probe(pdev); if (ret < 0) return ret; } - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->probe) { ret = cpu_dai->probe(pdev, cpu_dai); if (ret < 0) @@ -825,13 +825,13 @@ platform_err: cpu_dai_err: for (i--; i >= 0; i--) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev, cpu_dai); } - if (machine->remove) - machine->remove(pdev); + if (card->remove) + card->remove(pdev); return ret; } @@ -841,7 +841,7 @@ static int soc_remove(struct platform_device *pdev) { int i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; @@ -853,14 +853,14 @@ static int soc_remove(struct platform_device *pdev) if (codec_dev->remove) codec_dev->remove(pdev); - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *cpu_dai = machine->dai_link[i].cpu_dai; + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->remove) cpu_dai->remove(pdev, cpu_dai); } - if (machine->remove) - machine->remove(pdev); + if (card->remove) + card->remove(pdev); return 0; } @@ -1212,7 +1212,7 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; int ret = 0, i; mutex_lock(&codec->mutex); @@ -1231,11 +1231,11 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver)); /* create the pcms */ - for (i = 0; i < machine->num_links; i++) { - ret = soc_new_pcm(socdev, &machine->dai_link[i], i); + for (i = 0; i < card->num_links; i++) { + ret = soc_new_pcm(socdev, &card->dai_link[i], i); if (ret < 0) { printk(KERN_ERR "asoc: can't create pcm %s\n", - machine->dai_link[i].stream_name); + card->dai_link[i].stream_name); mutex_unlock(&codec->mutex); return ret; } @@ -1258,26 +1258,26 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms); int snd_soc_register_card(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; int ret = 0, i, ac97 = 0, err = 0; - for (i = 0; i < machine->num_links; i++) { - if (socdev->machine->dai_link[i].init) { - err = socdev->machine->dai_link[i].init(codec); + for (i = 0; i < card->num_links; i++) { + if (card->dai_link[i].init) { + err = card->dai_link[i].init(codec); if (err < 0) { printk(KERN_ERR "asoc: failed to init %s\n", - socdev->machine->dai_link[i].stream_name); + card->dai_link[i].stream_name); continue; } } - if (socdev->machine->dai_link[i].codec_dai->type == + if (card->dai_link[i].codec_dai->type == SND_SOC_DAI_AC97_BUS) ac97 = 1; } snprintf(codec->card->shortname, sizeof(codec->card->shortname), - "%s", machine->name); + "%s", card->name); snprintf(codec->card->longname, sizeof(codec->card->longname), - "%s (%s)", machine->name, codec->name); + "%s (%s)", card->name, codec->name); ret = snd_card_register(codec->card); if (ret < 0) { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0fecbb44726b..61d7d85aa578 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1402,11 +1402,11 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, enum snd_soc_bias_level level) { struct snd_soc_codec *codec = socdev->codec; - struct snd_soc_machine *machine = socdev->machine; + struct snd_soc_card *card = socdev->card; int ret = 0; - if (machine->set_bias_level) - ret = machine->set_bias_level(machine, level); + if (card->set_bias_level) + ret = card->set_bias_level(card, level); if (ret == 0 && codec->set_bias_level) ret = codec->set_bias_level(codec, level); From bd903bde7e0ad017cb87a228f451e05011e6d302 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 19 Nov 2008 19:16:05 +0000 Subject: [PATCH 156/367] ASoC: Add abbreviation to maintainers for searchability Signed-off-by: Mark Brown --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 16202c8ac68f..0c71569634d5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3907,7 +3907,7 @@ M: tiwai@suse.de L: alsa-devel@alsa-project.org (subscribers-only) S: Maintained -SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT +SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC) P: Liam Girdwood M: lrg@slimlogic.co.uk P: Mark Brown From faab5a32f4d0784d6bde57963267be0453be3546 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Thu, 20 Nov 2008 15:39:27 +0100 Subject: [PATCH 157/367] ASoC: ssm2602: Fix priv substreams refs Clean up our record of the active streams in shutdown(), fixing subsequent failures of snd_pcm_hw_constraints_complete after closure of a stream. NOTE: - The ssm2602 allows pairs of non-matching PB/REC rates. - This is a fix for less evil: The logic is flawed (e.g. the slave might startup before the master's rate and sample_bits are set). Signed-off-by: Karl Beldan Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 44ef0dacd564..0e522e718dfc 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -292,9 +292,15 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct ssm2602_priv *ssm2602 = codec->private_data; + struct i2c_client *i2c = codec->control_data; u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3; int i = get_coeff(ssm2602->sysclk, params_rate(params)); + if (substream == ssm2602->slave_substream) { + dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); + return 0; + } + /*no match is found*/ if (i == ARRAY_SIZE(coeff_div)) return -EINVAL; @@ -330,13 +336,19 @@ static int ssm2602_startup(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct ssm2602_priv *ssm2602 = codec->private_data; + struct i2c_client *i2c = codec->control_data; struct snd_pcm_runtime *master_runtime; /* The DAI has shared clocks so if we already have a playback or * capture going then constrain this substream to match it. + * TODO: the ssm2602 allows pairs of non-matching PB/REC rates */ if (ssm2602->master_substream) { master_runtime = ssm2602->master_substream->runtime; + dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", + master_runtime->sample_bits, + master_runtime->rate); + snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, master_runtime->rate, @@ -370,9 +382,15 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; + struct ssm2602_priv *ssm2602 = codec->private_data; /* deactivate */ if (!codec->active) ssm2602_write(codec, SSM2602_ACTIVE, 0); + + if (ssm2602->master_substream == substream) + ssm2602->master_substream = ssm2602->slave_substream; + + ssm2602->slave_substream = NULL; } static int ssm2602_mute(struct snd_soc_dai *dai, int mute) From 5de27b6cc0a8a1d27158ec9047cb5981745edfc0 Mon Sep 17 00:00:00 2001 From: Karl Beldan Date: Thu, 20 Nov 2008 15:39:31 +0100 Subject: [PATCH 158/367] ASoC: ssm2602: Update supported stream formats Signed-off-by: Karl Beldan Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 0e522e718dfc..56dc1c9c7c52 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -514,6 +514,9 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000) +#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + struct snd_soc_dai ssm2602_dai = { .name = "SSM2602", .playback = { @@ -521,13 +524,13 @@ struct snd_soc_dai ssm2602_dai = { .channels_min = 2, .channels_max = 2, .rates = SSM2602_RATES, - .formats = SNDRV_PCM_FMTBIT_S32_LE,}, + .formats = SSM2602_FORMATS,}, .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SSM2602_RATES, - .formats = SNDRV_PCM_FMTBIT_S32_LE,}, + .formats = SSM2602_FORMATS,}, .ops = { .startup = ssm2602_startup, .prepare = ssm2602_pcm_prepare, From a47cbe7263236691ee0bbc392f7fd4ec0da1159f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 23 Jul 2008 14:03:07 +0100 Subject: [PATCH 159/367] ASoC: Move DAI structure definitions into new soc-dai.h ASoC v2 factors most of the contents of soc.h out into separate headers, including soc-dai.h for the DAI. Factor the existing DAI API out into this file in order to prepare for backporting of the ASoC v2 DAI API. Also backport some of Liam's improvements to the documentation. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 209 ++++++++++++++++++++++++++++++++++++++++ include/sound/soc.h | 148 +--------------------------- 2 files changed, 211 insertions(+), 146 deletions(-) create mode 100644 include/sound/soc-dai.h diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h new file mode 100644 index 000000000000..08b8f7025c64 --- /dev/null +++ b/include/sound/soc-dai.h @@ -0,0 +1,209 @@ +/* + * linux/sound/soc-dai.h -- ALSA SoC Layer + * + * Copyright: 2005-2008 Wolfson Microelectronics. PLC. + * + * 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. + * + * Digital Audio Interface (DAI) API. + */ + +#ifndef __LINUX_SND_SOC_DAI_H +#define __LINUX_SND_SOC_DAI_H + + +#include + +struct snd_pcm_substream; + +/* + * DAI hardware audio formats. + * + * Describes the physical PCM data formating and clocking. Add new formats + * to the end. + */ +#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ +#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right Justified mode */ +#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ +#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM LRC */ +#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM LRC */ +#define SND_SOC_DAIFMT_AC97 5 /* AC97 */ + +/* left and right justified also known as MSB and LSB respectively */ +#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J +#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J + +/* + * DAI Clock gating. + * + * DAI bit clocks can be be gated (disabled) when not the DAI is not + * sending or receiving PCM data in a frame. This can be used to save power. + */ +#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ +#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated */ + +/* + * DAI Left/Right Clocks. + * + * Specifies whether the DAI can support different samples for similtanious + * playback and capture. This usually requires a seperate physical frame + * clock for playback and capture. + */ +#define SND_SOC_DAIFMT_SYNC (0 << 5) /* Tx FRM = Rx FRM */ +#define SND_SOC_DAIFMT_ASYNC (1 << 5) /* Tx FRM ~ Rx FRM */ + +/* + * TDM + * + * Time Division Multiplexing. Allows PCM data to be multplexed with other + * data on the DAI. + */ +#define SND_SOC_DAIFMT_TDM (1 << 6) + +/* + * DAI hardware signal inversions. + * + * Specifies whether the DAI can also support inverted clocks for the specified + * format. + */ +#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ +#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ +#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ +#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ + +/* + * DAI hardware clock masters. + * + * This is wrt the codec, the inverse is true for the interface + * i.e. if the codec is clk and frm master then the interface is + * clk and frame slave. + */ +#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ +#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ +#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ +#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ + +#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f +#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 +#define SND_SOC_DAIFMT_INV_MASK 0x0f00 +#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 + +/* + * Master Clock Directions + */ +#define SND_SOC_CLOCK_IN 0 +#define SND_SOC_CLOCK_OUT 1 + +struct snd_soc_dai_ops; +struct snd_soc_dai; +struct snd_ac97_bus_ops; + +/* Digital Audio Interface clocking API.*/ +int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir); + +int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, + int div_id, int div); + +int snd_soc_dai_set_pll(struct snd_soc_dai *dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + +/* Digital Audio interface formatting */ +int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); + +int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int mask, int slots); + +int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); + +/* Digital Audio Interface mute */ +int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); + +/* + * Digital Audio Interface. + * + * Describes the Digital Audio Interface in terms of it's ALSA, DAI and AC97 + * operations an capabilities. Codec and platfom drivers will register a this + * structure for every DAI they have. + * + * This structure covers the clocking, formating and ALSA operations for each + * interface a + */ +struct snd_soc_dai_ops { + /* + * DAI clocking configuration, all optional. + * Called by soc_card drivers, normally in their hw_params. + */ + int (*set_sysclk)(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir); + int (*set_pll)(struct snd_soc_dai *dai, + int pll_id, unsigned int freq_in, unsigned int freq_out); + int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); + + /* + * DAI format configuration + * Called by soc_card drivers, normally in their hw_params. + */ + int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); + int (*set_tdm_slot)(struct snd_soc_dai *dai, + unsigned int mask, int slots); + int (*set_tristate)(struct snd_soc_dai *dai, int tristate); + + /* + * DAI digital mute - optional. + * Called by soc-core to minimise any pops. + */ + int (*digital_mute)(struct snd_soc_dai *dai, int mute); +}; + +/* + * Digital Audio Interface runtime data. + * + * Holds runtime data for a DAI. + */ +struct snd_soc_dai { + /* DAI description */ + char *name; + unsigned int id; + unsigned char type; + + /* DAI callbacks */ + int (*probe)(struct platform_device *pdev, + struct snd_soc_dai *dai); + void (*remove)(struct platform_device *pdev, + struct snd_soc_dai *dai); + int (*suspend)(struct platform_device *pdev, + struct snd_soc_dai *dai); + int (*resume)(struct platform_device *pdev, + struct snd_soc_dai *dai); + + /* ops */ + struct snd_soc_ops ops; + struct snd_soc_dai_ops dai_ops; + + /* DAI capabilities */ + struct snd_soc_pcm_stream capture; + struct snd_soc_pcm_stream playback; + + /* DAI runtime info */ + struct snd_pcm_runtime *runtime; + struct snd_soc_codec *codec; + unsigned int active; + unsigned char pop_wait:1; + void *dma_data; + + /* DAI private data */ + void *private_data; + + /* parent codec/platform */ + union { + struct snd_soc_codec *codec; + struct snd_soc_platform *platform; + }; + + struct list_head list; +}; + +#endif diff --git a/include/sound/soc.h b/include/sound/soc.h index 3be17b3c650c..e4465f73aa46 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -151,76 +151,6 @@ enum snd_soc_bias_level { #define SND_SOC_DAI_PCM 0x4 #define SND_SOC_DAI_AC97_BUS 0x8 /* for custom i.e. non ac97_codec.c */ -/* - * DAI hardware audio formats - */ -#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ -#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right justified mode */ -#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ -#define SND_SOC_DAIFMT_DSP_A 3 /* L data msb after FRM or LRC */ -#define SND_SOC_DAIFMT_DSP_B 4 /* L data msb during FRM or LRC */ -#define SND_SOC_DAIFMT_AC97 5 /* AC97 */ - -#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J -#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J - -/* - * DAI Gating - */ -#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ -#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated when not Tx/Rx */ - -/* - * DAI Sync - * Synchronous LR (Left Right) clocks and Frame signals. - */ -#define SND_SOC_DAIFMT_SYNC (0 << 5) /* Tx FRM = Rx FRM */ -#define SND_SOC_DAIFMT_ASYNC (1 << 5) /* Tx FRM ~ Rx FRM */ - -/* - * TDM - */ -#define SND_SOC_DAIFMT_TDM (1 << 6) - -/* - * DAI hardware signal inversions - */ -#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bclk + frm */ -#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal bclk + inv frm */ -#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert bclk + nor frm */ -#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert bclk + frm */ - -/* - * DAI hardware clock masters - * This is wrt the codec, the inverse is true for the interface - * i.e. if the codec is clk and frm master then the interface is - * clk and frame slave. - */ -#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & frm master */ -#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & frm master */ -#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ -#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & frm slave */ - -#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f -#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 -#define SND_SOC_DAIFMT_INV_MASK 0x0f00 -#define SND_SOC_DAIFMT_MASTER_MASK 0xf000 - - -/* - * Master Clock Directions - */ -#define SND_SOC_CLOCK_IN 0 -#define SND_SOC_CLOCK_OUT 1 - -/* - * AC97 codec ID's bitmask - */ -#define SND_SOC_DAI_AC97_ID0 (1 << 0) -#define SND_SOC_DAI_AC97_ID1 (1 << 1) -#define SND_SOC_DAI_AC97_ID2 (1 << 2) -#define SND_SOC_DAI_AC97_ID3 (1 << 3) - struct snd_soc_device; struct snd_soc_pcm_stream; struct snd_soc_ops; @@ -260,27 +190,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, struct snd_ac97_bus_ops *ops, int num); void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); -/* Digital Audio Interface clocking API.*/ -int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, - unsigned int freq, int dir); - -int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, - int div_id, int div); - -int snd_soc_dai_set_pll(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out); - -/* Digital Audio interface formatting */ -int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); - -int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots); - -int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); - -/* Digital Audio Interface mute */ -int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute); - /* *Controls */ @@ -338,61 +247,6 @@ struct snd_soc_ops { int (*trigger)(struct snd_pcm_substream *, int); }; -/* ASoC DAI ops */ -struct snd_soc_dai_ops { - /* DAI clocking configuration */ - int (*set_sysclk)(struct snd_soc_dai *dai, - int clk_id, unsigned int freq, int dir); - int (*set_pll)(struct snd_soc_dai *dai, - int pll_id, unsigned int freq_in, unsigned int freq_out); - int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); - - /* DAI format configuration */ - int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); - int (*set_tdm_slot)(struct snd_soc_dai *dai, - unsigned int mask, int slots); - int (*set_tristate)(struct snd_soc_dai *dai, int tristate); - - /* digital mute */ - int (*digital_mute)(struct snd_soc_dai *dai, int mute); -}; - -/* SoC DAI (Digital Audio Interface) */ -struct snd_soc_dai { - /* DAI description */ - char *name; - unsigned int id; - unsigned char type; - - /* DAI callbacks */ - int (*probe)(struct platform_device *pdev, - struct snd_soc_dai *dai); - void (*remove)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*suspend)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*resume)(struct platform_device *pdev, - struct snd_soc_dai *dai); - - /* ops */ - struct snd_soc_ops ops; - struct snd_soc_dai_ops dai_ops; - - /* DAI capabilities */ - struct snd_soc_pcm_stream capture; - struct snd_soc_pcm_stream playback; - - /* DAI runtime info */ - struct snd_pcm_runtime *runtime; - struct snd_soc_codec *codec; - unsigned int active; - unsigned char pop_wait:1; - void *dma_data; - - /* DAI private data */ - void *private_data; -}; - /* SoC Audio Codec */ struct snd_soc_codec { char *name; @@ -543,4 +397,6 @@ struct soc_enum { void *dapm; }; +#include + #endif From dee89c4d94433520e4e3977ae203d4cfbfe385fb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 18 Nov 2008 22:11:38 +0000 Subject: [PATCH 160/367] ASoC: Merge snd_soc_ops into snd_soc_dai_ops Liam Girdwood's ASoC v2 work avoids having two different ops structures for DAIs by merging the members of struct snd_soc_ops into struct snd_soc_dai_ops, allowing per DAI configuration for everything. Backport this change. This paves the way for future work allowing any combination of DAIs to be connected rather than having fixed purpose CODEC and CPU DAIs and only allowing CODEC<->CPU interconnections. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 20 +++++++- sound/soc/atmel/atmel_ssc_dai.c | 21 +++++---- sound/soc/au1x/psc-ac97.c | 5 +- sound/soc/au1x/psc-i2s.c | 8 ++-- sound/soc/blackfin/bf5xx-i2s.c | 12 +++-- sound/soc/codecs/ac97.c | 3 +- sound/soc/codecs/ak4535.c | 5 +- sound/soc/codecs/cs4270.c | 11 +++-- sound/soc/codecs/ssm2602.c | 14 +++--- sound/soc/codecs/tlv320aic23.c | 19 ++++---- sound/soc/codecs/tlv320aic26.c | 5 +- sound/soc/codecs/tlv320aic3x.c | 5 +- sound/soc/codecs/twl4030.c | 5 +- sound/soc/codecs/uda134x.c | 12 ++--- sound/soc/codecs/uda1380.c | 15 +++--- sound/soc/codecs/wm8510.c | 5 +- sound/soc/codecs/wm8580.c | 12 ++--- sound/soc/codecs/wm8728.c | 5 +- sound/soc/codecs/wm8731.c | 11 +++-- sound/soc/codecs/wm8750.c | 5 +- sound/soc/codecs/wm8753.c | 25 +++++----- sound/soc/codecs/wm8900.c | 5 +- sound/soc/codecs/wm8903.c | 11 +++-- sound/soc/codecs/wm8971.c | 5 +- sound/soc/codecs/wm8990.c | 6 +-- sound/soc/codecs/wm9712.c | 6 ++- sound/soc/codecs/wm9713.c | 21 +++++---- sound/soc/davinci/davinci-i2s.c | 12 +++-- sound/soc/davinci/davinci-sffsdr.c | 3 +- sound/soc/fsl/fsl_ssi.c | 14 +++--- sound/soc/fsl/mpc5200_psc_i2s.c | 17 ++++--- sound/soc/omap/omap-mcbsp.c | 14 +++--- sound/soc/omap/omap2evm.c | 3 +- sound/soc/pxa/pxa-ssp.c | 20 ++++---- sound/soc/pxa/pxa2xx-ac97.c | 9 ++-- sound/soc/pxa/pxa2xx-i2s.c | 15 +++--- sound/soc/s3c24xx/s3c2412-i2s.c | 8 ++-- sound/soc/s3c24xx/s3c2443-ac97.c | 8 ++-- sound/soc/s3c24xx/s3c24xx-i2s.c | 9 ++-- sound/soc/sh/hac.c | 3 +- sound/soc/sh/ssi.c | 16 +++---- sound/soc/soc-core.c | 74 +++++++++++++++--------------- 42 files changed, 265 insertions(+), 237 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 08b8f7025c64..f51cb55902f7 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -156,6 +156,23 @@ struct snd_soc_dai_ops { * Called by soc-core to minimise any pops. */ int (*digital_mute)(struct snd_soc_dai *dai, int mute); + + /* + * ALSA PCM audio operations - all optional. + * Called by soc-core during audio PCM operations. + */ + int (*startup)(struct snd_pcm_substream *, + struct snd_soc_dai *); + void (*shutdown)(struct snd_pcm_substream *, + struct snd_soc_dai *); + int (*hw_params)(struct snd_pcm_substream *, + struct snd_pcm_hw_params *, struct snd_soc_dai *); + int (*hw_free)(struct snd_pcm_substream *, + struct snd_soc_dai *); + int (*prepare)(struct snd_pcm_substream *, + struct snd_soc_dai *); + int (*trigger)(struct snd_pcm_substream *, int, + struct snd_soc_dai *); }; /* @@ -180,8 +197,7 @@ struct snd_soc_dai { struct snd_soc_dai *dai); /* ops */ - struct snd_soc_ops ops; - struct snd_soc_dai_ops dai_ops; + struct snd_soc_dai_ops ops; /* DAI capabilities */ struct snd_soc_pcm_stream capture; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index d290b7894917..916f73b9a18f 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -202,7 +202,8 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id) /* * Startup. Only that one substream allowed in each direction. */ -static int atmel_ssc_startup(struct snd_pcm_substream *substream) +static int atmel_ssc_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; @@ -231,7 +232,8 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream) * Shutdown. Clear DMA parameters and shutdown the SSC if there * are no other substreams open. */ -static void atmel_ssc_shutdown(struct snd_pcm_substream *substream) +static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; @@ -332,7 +334,8 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, * Configure the SSC. */ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); int id = rtd->dai->cpu_dai->id; @@ -600,7 +603,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, } -static int atmel_ssc_prepare(struct snd_pcm_substream *substream) +static int atmel_ssc_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id]; @@ -715,8 +719,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { .startup = atmel_ssc_startup, .shutdown = atmel_ssc_shutdown, .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params,}, - .dai_ops = { + .hw_params = atmel_ssc_hw_params, .set_fmt = atmel_ssc_set_dai_fmt, .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, .private_data = &ssc_info[0], @@ -741,8 +744,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { .startup = atmel_ssc_startup, .shutdown = atmel_ssc_shutdown, .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params,}, - .dai_ops = { + .hw_params = atmel_ssc_hw_params, .set_fmt = atmel_ssc_set_dai_fmt, .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, .private_data = &ssc_info[1], @@ -766,8 +768,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { .startup = atmel_ssc_startup, .shutdown = atmel_ssc_shutdown, .prepare = atmel_ssc_prepare, - .hw_params = atmel_ssc_hw_params,}, - .dai_ops = { + .hw_params = atmel_ssc_hw_params, .set_fmt = atmel_ssc_set_dai_fmt, .set_clkdiv = atmel_ssc_set_dai_clkdiv,}, .private_data = &ssc_info[2], diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 57facbad6825..ad60a6042cad 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -160,7 +160,8 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; @@ -210,7 +211,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, } static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, - int cmd) + int cmd, struct snd_soc_dai *dai) { /* FIXME */ struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 9384702c7ebd..05a5acbb16ae 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -116,7 +116,8 @@ out: } static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; @@ -240,7 +241,8 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype) return 0; } -static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata; int ret, stype = SUBSTREAM_TYPE(substream); @@ -389,8 +391,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = { .ops = { .trigger = au1xpsc_i2s_trigger, .hw_params = au1xpsc_i2s_hw_params, - }, - .dai_ops = { .set_fmt = au1xpsc_i2s_set_fmt, }, }; diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index e020c160ee44..4e675b55b182 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -132,7 +132,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return ret; } -static int bf5xx_i2s_startup(struct snd_pcm_substream *substream) +static int bf5xx_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); @@ -142,7 +143,8 @@ static int bf5xx_i2s_startup(struct snd_pcm_substream *substream) } static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { int ret = 0; @@ -193,7 +195,8 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream) +static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); bf5xx_i2s.counter--; @@ -307,8 +310,7 @@ struct snd_soc_dai bf5xx_i2s_dai = { .ops = { .startup = bf5xx_i2s_startup, .shutdown = bf5xx_i2s_shutdown, - .hw_params = bf5xx_i2s_hw_params,}, - .dai_ops = { + .hw_params = bf5xx_i2s_hw_params, .set_fmt = bf5xx_i2s_set_dai_fmt, }, }; diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index bd1ebdc6c86c..8a93aff359d0 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -24,7 +24,8 @@ #define AC97_VERSION "0.6" -static int ac97_prepare(struct snd_pcm_substream *substream) +static int ac97_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 2a89b5888e11..c742290e5533 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -339,7 +339,8 @@ static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai, } static int ak4535_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -451,8 +452,6 @@ struct snd_soc_dai ak4535_dai = { .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .hw_params = ak4535_hw_params, - }, - .dai_ops = { .set_fmt = ak4535_set_dai_fmt, .digital_mute = ak4535_mute, .set_sysclk = ak4535_set_dai_sysclk, diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 0ff476d7057c..7507d468b200 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -360,13 +360,14 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, /* * Program the CS4270 with the given hardware parameters. * - * The .dai_ops functions are used to provide board-specific data, like + * The .ops functions are used to provide board-specific data, like * input frequencies, to this driver. This function takes that information, * combines it with the hardware parameters provided, and programs the * hardware accordingly. */ static int cs4270_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -710,10 +711,10 @@ static int cs4270_probe(struct platform_device *pdev) if (codec->control_data) { /* Initialize codec ops */ cs4270_dai.ops.hw_params = cs4270_hw_params; - cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk; - cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt; + cs4270_dai.ops.set_sysclk = cs4270_set_dai_sysclk; + cs4270_dai.ops.set_fmt = cs4270_set_dai_fmt; #ifdef CONFIG_SND_SOC_CS4270_HWMUTE - cs4270_dai.dai_ops.digital_mute = cs4270_mute; + cs4270_dai.ops.digital_mute = cs4270_mute; #endif } else printk(KERN_INFO "cs4270: no I2C device found, " diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 56dc1c9c7c52..0c5884ea1b00 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -285,7 +285,8 @@ static inline int get_coeff(int mclk, int rate) } static int ssm2602_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { u16 srate; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -330,7 +331,8 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream, return 0; } -static int ssm2602_startup(struct snd_pcm_substream *substream) +static int ssm2602_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -366,7 +368,8 @@ static int ssm2602_startup(struct snd_pcm_substream *substream) return 0; } -static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) +static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -377,7 +380,8 @@ static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static void ssm2602_shutdown(struct snd_pcm_substream *substream) +static void ssm2602_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -536,8 +540,6 @@ struct snd_soc_dai ssm2602_dai = { .prepare = ssm2602_pcm_prepare, .hw_params = ssm2602_hw_params, .shutdown = ssm2602_shutdown, - }, - .dai_ops = { .digital_mute = ssm2602_mute, .set_sysclk = ssm2602_set_dai_sysclk, .set_fmt = ssm2602_set_dai_fmt, diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index c903e4f48dc4..a4e13d0688c9 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -418,7 +418,8 @@ static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) } static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -465,7 +466,8 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, return 0; } -static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream) +static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -477,7 +479,8 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static void tlv320aic23_shutdown(struct snd_pcm_substream *substream) +static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -613,12 +616,10 @@ struct snd_soc_dai tlv320aic23_dai = { .prepare = tlv320aic23_pcm_prepare, .hw_params = tlv320aic23_hw_params, .shutdown = tlv320aic23_shutdown, - }, - .dai_ops = { - .digital_mute = tlv320aic23_mute, - .set_fmt = tlv320aic23_set_dai_fmt, - .set_sysclk = tlv320aic23_set_dai_sysclk, - } + .digital_mute = tlv320aic23_mute, + .set_fmt = tlv320aic23_set_dai_fmt, + .set_sysclk = tlv320aic23_set_dai_sysclk, + } }; EXPORT_SYMBOL_GPL(tlv320aic23_dai); diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index bed8a9e63ddc..6b7ddfc92573 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -125,7 +125,8 @@ static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg, * Digital Audio Interface Operations */ static int aic26_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -287,8 +288,6 @@ struct snd_soc_dai aic26_dai = { }, .ops = { .hw_params = aic26_hw_params, - }, - .dai_ops = { .digital_mute = aic26_mute, .set_sysclk = aic26_set_sysclk, .set_fmt = aic26_set_fmt, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index cff276ee261e..b76bcc3c4110 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -694,7 +694,8 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) } static int aic3x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1009,8 +1010,6 @@ struct snd_soc_dai aic3x_dai = { .formats = AIC3X_FORMATS,}, .ops = { .hw_params = aic3x_hw_params, - }, - .dai_ops = { .digital_mute = aic3x_mute, .set_sysclk = aic3x_set_dai_sysclk, .set_fmt = aic3x_set_dai_fmt, diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c778eb446a5b..33489515b928 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -343,7 +343,8 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, } static int twl4030_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -523,8 +524,6 @@ struct snd_soc_dai twl4030_dai = { .formats = TWL4030_FORMATS,}, .ops = { .hw_params = twl4030_hw_params, - }, - .dai_ops = { .set_sysclk = twl4030_set_dai_sysclk, .set_fmt = twl4030_set_dai_fmt, } diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 69ef521a2ed1..91f333cdc7cf 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -168,7 +168,8 @@ static int uda134x_mute(struct snd_soc_dai *dai, int mute) return 0; } -static int uda134x_startup(struct snd_pcm_substream *substream) +static int uda134x_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -200,7 +201,8 @@ static int uda134x_startup(struct snd_pcm_substream *substream) return 0; } -static void uda134x_shutdown(struct snd_pcm_substream *substream) +static void uda134x_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -214,7 +216,8 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream) } static int uda134x_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -484,9 +487,6 @@ struct snd_soc_dai uda134x_dai = { .startup = uda134x_startup, .shutdown = uda134x_shutdown, .hw_params = uda134x_hw_params, - }, - /* DAI operations */ - .dai_ops = { .digital_mute = uda134x_mute, .set_sysclk = uda134x_set_dai_sysclk, .set_fmt = uda134x_set_dai_fmt, diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index a69ee72a7af5..330877c70699 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -407,7 +407,8 @@ static int uda1380_set_dai_fmt(struct snd_soc_dai *codec_dai, * when the DAI is being clocked by the CPU DAI. It's up to the * machine and cpu DAI driver to do this before we are called. */ -static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) +static int uda1380_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -439,7 +440,8 @@ static int uda1380_pcm_prepare(struct snd_pcm_substream *substream) } static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -477,7 +479,8 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream) +static void uda1380_pcm_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -560,8 +563,6 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { .digital_mute = uda1380_mute, .set_fmt = uda1380_set_dai_fmt, }, @@ -579,8 +580,6 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { .digital_mute = uda1380_mute, .set_fmt = uda1380_set_dai_fmt, }, @@ -598,8 +597,6 @@ struct snd_soc_dai uda1380_dai[] = { .hw_params = uda1380_pcm_hw_params, .shutdown = uda1380_pcm_shutdown, .prepare = uda1380_pcm_prepare, - }, - .dai_ops = { .set_fmt = uda1380_set_dai_fmt, }, }, diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index d8ca2da8d634..173b66c0c766 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -463,7 +463,8 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -585,8 +586,6 @@ struct snd_soc_dai wm8510_dai = { .formats = WM8510_FORMATS,}, .ops = { .hw_params = wm8510_pcm_hw_params, - }, - .dai_ops = { .digital_mute = wm8510_mute, .set_fmt = wm8510_set_dai_fmt, .set_clkdiv = wm8510_set_dai_clkdiv, diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index cbcd7c324ab9..220d4b68904a 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -548,13 +548,13 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai_link *dai = rtd->dai; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; - u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->codec_dai->id); + u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); paifb &= ~WM8580_AIF_LENGTH_MASK; /* bit size */ @@ -574,7 +574,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - wm8580_write(codec, WM8580_PAIF3 + dai->codec_dai->id, paifb); + wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb); return 0; } @@ -798,8 +798,6 @@ struct snd_soc_dai wm8580_dai[] = { }, .ops = { .hw_params = wm8580_paif_hw_params, - }, - .dai_ops = { .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, @@ -818,8 +816,6 @@ struct snd_soc_dai wm8580_dai[] = { }, .ops = { .hw_params = wm8580_paif_hw_params, - }, - .dai_ops = { .set_fmt = wm8580_set_paif_dai_fmt, .set_clkdiv = wm8580_set_dai_clkdiv, .set_pll = wm8580_set_dai_pll, diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 3e39dea61241..71949bd320d3 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -147,7 +147,8 @@ static int wm8728_mute(struct snd_soc_dai *dai, int mute) } static int wm8728_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -269,8 +270,6 @@ struct snd_soc_dai wm8728_dai = { }, .ops = { .hw_params = wm8728_hw_params, - }, - .dai_ops = { .digital_mute = wm8728_mute, .set_fmt = wm8728_set_dai_fmt, } diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7f8a7e36b33e..c0f277053bb2 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -264,7 +264,8 @@ static inline int get_coeff(int mclk, int rate) } static int wm8731_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -293,7 +294,8 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, return 0; } -static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) +static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -305,7 +307,8 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream) return 0; } -static void wm8731_shutdown(struct snd_pcm_substream *substream) +static void wm8731_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -461,8 +464,6 @@ struct snd_soc_dai wm8731_dai = { .prepare = wm8731_pcm_prepare, .hw_params = wm8731_hw_params, .shutdown = wm8731_shutdown, - }, - .dai_ops = { .digital_mute = wm8731_mute, .set_sysclk = wm8731_set_dai_sysclk, .set_fmt = wm8731_set_dai_fmt, diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 9b7296ee5b08..860a1d56830a 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -614,7 +614,8 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -709,8 +710,6 @@ struct snd_soc_dai wm8750_dai = { .formats = WM8750_FORMATS,}, .ops = { .hw_params = wm8750_pcm_hw_params, - }, - .dai_ops = { .digital_mute = wm8750_mute, .set_fmt = wm8750_set_dai_fmt, .set_sysclk = wm8750_set_dai_sysclk, diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d426eaa22185..5e4cd3bb824a 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -922,7 +922,8 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1155,7 +1156,8 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1323,16 +1325,15 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, + .formats = WM8753_FORMATS}, .capture = { /* dummy for fast DAI switching */ .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = WM8753_RATES, - .formats = WM8753_FORMATS,}, + .formats = WM8753_FORMATS}, .ops = { - .hw_params = wm8753_i2s_hw_params,}, - .dai_ops = { + .hw_params = wm8753_i2s_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode1h_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1356,8 +1357,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_pcm_hw_params,}, - .dai_ops = { + .hw_params = wm8753_pcm_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode1v_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1385,8 +1385,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_pcm_hw_params,}, - .dai_ops = { + .hw_params = wm8753_pcm_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode2_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1410,8 +1409,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params,}, - .dai_ops = { + .hw_params = wm8753_i2s_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode3_4_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, @@ -1439,8 +1437,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { .rates = WM8753_RATES, .formats = WM8753_FORMATS,}, .ops = { - .hw_params = wm8753_i2s_hw_params,}, - .dai_ops = { + .hw_params = wm8753_i2s_hw_params, .digital_mute = wm8753_mute, .set_fmt = wm8753_mode3_4_set_dai_fmt, .set_clkdiv = wm8753_set_dai_clkdiv, diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index de016f41e04c..d1326be91c8b 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -727,7 +727,8 @@ static int wm8900_add_widgets(struct snd_soc_codec *codec) } static int wm8900_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1117,8 +1118,6 @@ struct snd_soc_dai wm8900_dai = { }, .ops = { .hw_params = wm8900_hw_params, - }, - .dai_ops = { .set_clkdiv = wm8900_set_dai_clkdiv, .set_pll = wm8900_set_dai_pll, .set_fmt = wm8900_set_dai_fmt, diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index ce40d7877605..efbe8927b7d2 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1257,7 +1257,8 @@ static struct { { 0, 0 }, }; -static int wm8903_startup(struct snd_pcm_substream *substream) +static int wm8903_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1298,7 +1299,8 @@ static int wm8903_startup(struct snd_pcm_substream *substream) return 0; } -static void wm8903_shutdown(struct snd_pcm_substream *substream) +static void wm8903_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1317,7 +1319,8 @@ static void wm8903_shutdown(struct snd_pcm_substream *substream) } static int wm8903_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1515,8 +1518,6 @@ struct snd_soc_dai wm8903_dai = { .startup = wm8903_startup, .shutdown = wm8903_shutdown, .hw_params = wm8903_hw_params, - }, - .dai_ops = { .digital_mute = wm8903_digital_mute, .set_fmt = wm8903_set_dai_fmt, .set_sysclk = wm8903_set_dai_sysclk diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index f41a578ddd4f..26edcc9d6e87 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -541,7 +541,8 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -634,8 +635,6 @@ struct snd_soc_dai wm8971_dai = { .formats = WM8971_FORMATS,}, .ops = { .hw_params = wm8971_pcm_hw_params, - }, - .dai_ops = { .digital_mute = wm8971_mute, .set_fmt = wm8971_set_dai_fmt, .set_sysclk = wm8971_set_dai_sysclk, diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 2d7b0096d929..13926516d16e 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1172,7 +1172,8 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, * Set PCM DAI bit size and sample rate. */ static int wm8990_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -1362,8 +1363,7 @@ struct snd_soc_dai wm8990_dai = { .rates = WM8990_RATES, .formats = WM8990_FORMATS,}, .ops = { - .hw_params = wm8990_hw_params,}, - .dai_ops = { + .hw_params = wm8990_hw_params, .digital_mute = wm8990_mute, .set_fmt = wm8990_set_dai_fmt, .set_clkdiv = wm8990_set_dai_clkdiv, diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index ffb471e420e2..81c38e7ad344 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -487,7 +487,8 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } -static int ac97_prepare(struct snd_pcm_substream *substream) +static int ac97_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -507,7 +508,8 @@ static int ac97_prepare(struct snd_pcm_substream *substream) return ac97_write(codec, reg, runtime->rate); } -static int ac97_aux_prepare(struct snd_pcm_substream *substream) +static int ac97_aux_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 740bf3cde18d..a0cc5ac969a1 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -928,7 +928,8 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, } static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -954,7 +955,8 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, return 0; } -static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) +static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; @@ -969,7 +971,8 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream) ac97_write(codec, AC97_EXTENDED_MID, status); } -static int ac97_hifi_prepare(struct snd_pcm_substream *substream) +static int ac97_hifi_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -989,7 +992,8 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream) return ac97_write(codec, reg, runtime->rate); } -static int ac97_aux_prepare(struct snd_pcm_substream *substream) +static int ac97_aux_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -1042,8 +1046,7 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { - .prepare = ac97_hifi_prepare,}, - .dai_ops = { + .prepare = ac97_hifi_prepare, .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll,}, }, @@ -1056,8 +1059,7 @@ struct snd_soc_dai wm9713_dai[] = { .rates = WM9713_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { - .prepare = ac97_aux_prepare,}, - .dai_ops = { + .prepare = ac97_aux_prepare, .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll,}, }, @@ -1077,8 +1079,7 @@ struct snd_soc_dai wm9713_dai[] = { .formats = WM9713_PCM_FORMATS,}, .ops = { .hw_params = wm9713_pcm_hw_params, - .shutdown = wm9713_voiceshutdown,}, - .dai_ops = { + .shutdown = wm9713_voiceshutdown, .set_clkdiv = wm9713_set_dai_clkdiv, .set_pll = wm9713_set_dai_pll, .set_fmt = wm9713_set_dai_fmt, diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 95df51e803b4..7a17cd0ecf64 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -188,7 +188,8 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); } -static int davinci_i2s_startup(struct snd_pcm_substream *substream) +static int davinci_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -285,7 +286,8 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, } static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; @@ -349,7 +351,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int ret = 0; @@ -473,8 +476,7 @@ struct snd_soc_dai davinci_i2s_dai = { .ops = { .startup = davinci_i2s_startup, .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params,}, - .dai_ops = { + .hw_params = davinci_i2s_hw_params, .set_fmt = davinci_i2s_set_dai_fmt, }, }; diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index fa38f9cd3506..e95fde1766b5 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -34,7 +34,8 @@ #include "davinci-i2s.h" static int sffsdr_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 157a7895ffa1..52c290bb47bf 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -266,7 +266,8 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) * If this is the first stream open, then grab the IRQ and program most of * the SSI registers. */ -static int fsl_ssi_startup(struct snd_pcm_substream *substream) +static int fsl_ssi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -411,7 +412,8 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream) * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the * clock master. */ -static int fsl_ssi_prepare(struct snd_pcm_substream *substream) +static int fsl_ssi_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -441,7 +443,8 @@ static int fsl_ssi_prepare(struct snd_pcm_substream *substream) * The DMA channel is in external master start and pause mode, which * means the SSI completely controls the flow of data. */ -static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd) +static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -490,7 +493,8 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd) * * Shutdown the SSI if there are no other substreams open. */ -static void fsl_ssi_shutdown(struct snd_pcm_substream *substream) +static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; @@ -578,8 +582,6 @@ static struct snd_soc_dai fsl_ssi_dai_template = { .prepare = fsl_ssi_prepare, .shutdown = fsl_ssi_shutdown, .trigger = fsl_ssi_trigger, - }, - .dai_ops = { .set_sysclk = fsl_ssi_set_sysclk, .set_fmt = fsl_ssi_set_fmt, }, diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 94a02eaa4825..e2c172f38979 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -187,7 +187,8 @@ static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream) * If this is the first stream open, then grab the IRQ and program most of * the PSC registers. */ -static int psc_i2s_startup(struct snd_pcm_substream *substream) +static int psc_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -220,7 +221,8 @@ static int psc_i2s_startup(struct snd_pcm_substream *substream) } static int psc_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -256,7 +258,8 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int psc_i2s_hw_free(struct snd_pcm_substream *substream) +static int psc_i2s_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { snd_pcm_set_runtime_buffer(substream, NULL); return 0; @@ -268,7 +271,8 @@ static int psc_i2s_hw_free(struct snd_pcm_substream *substream) * This function is called by ALSA to start, stop, pause, and resume the DMA * transfer of data. */ -static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -383,7 +387,8 @@ static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd) * * Shutdown the PSC if there are no other substreams open. */ -static void psc_i2s_shutdown(struct snd_pcm_substream *substream) +static void psc_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data; @@ -483,8 +488,6 @@ static struct snd_soc_dai psc_i2s_dai_template = { .hw_free = psc_i2s_hw_free, .shutdown = psc_i2s_shutdown, .trigger = psc_i2s_trigger, - }, - .dai_ops = { .set_sysclk = psc_i2s_set_sysclk, .set_fmt = psc_i2s_set_fmt, }, diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 3d4060b00eb3..6013898f49b4 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -138,7 +138,8 @@ static const unsigned long omap34xx_mcbsp_port[][2] = { static const unsigned long omap34xx_mcbsp_port[][2] = {}; #endif -static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) +static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -151,7 +152,8 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream) return err; } -static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) +static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -163,7 +165,8 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream) } } -static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) +static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -192,7 +195,8 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd) } static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -470,8 +474,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, .shutdown = omap_mcbsp_dai_shutdown, \ .trigger = omap_mcbsp_dai_trigger, \ .hw_params = omap_mcbsp_dai_hw_params, \ - }, \ - .dai_ops = { \ .set_fmt = omap_mcbsp_dai_set_dai_fmt, \ .set_clkdiv = omap_mcbsp_dai_set_clkdiv, \ .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, \ diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index 5bea31157a94..7b160f9d83f9 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -38,7 +38,8 @@ #include "../codecs/twl4030.h" static int omap2evm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index e2b54b88c380..d0dd6245a20a 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -212,7 +212,8 @@ static struct pxa2xx_pcm_dma_params *ssp_dma_params[4][4] = { }, }; -static int pxa_ssp_startup(struct snd_pcm_substream *substream) +static int pxa_ssp_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -228,7 +229,8 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream) return ret; } -static void pxa_ssp_shutdown(struct snd_pcm_substream *substream) +static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -604,7 +606,8 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, * Can be called multiple times by oss emulation. */ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -678,7 +681,8 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, return 0; } -static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd) +static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -806,8 +810,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, .hw_params = pxa_ssp_hw_params, - }, - .dai_ops = { .set_sysclk = pxa_ssp_set_dai_sysclk, .set_clkdiv = pxa_ssp_set_dai_clkdiv, .set_pll = pxa_ssp_set_dai_pll, @@ -840,8 +842,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, .hw_params = pxa_ssp_hw_params, - }, - .dai_ops = { .set_sysclk = pxa_ssp_set_dai_sysclk, .set_clkdiv = pxa_ssp_set_dai_clkdiv, .set_pll = pxa_ssp_set_dai_pll, @@ -875,8 +875,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, .hw_params = pxa_ssp_hw_params, - }, - .dai_ops = { .set_sysclk = pxa_ssp_set_dai_sysclk, .set_clkdiv = pxa_ssp_set_dai_clkdiv, .set_pll = pxa_ssp_set_dai_pll, @@ -910,8 +908,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { .shutdown = pxa_ssp_shutdown, .trigger = pxa_ssp_trigger, .hw_params = pxa_ssp_hw_params, - }, - .dai_ops = { .set_sysclk = pxa_ssp_set_dai_sysclk, .set_clkdiv = pxa_ssp_set_dai_clkdiv, .set_pll = pxa_ssp_set_dai_pll, diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index a7a3a9c5c6ff..86667d2f1b75 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -117,7 +117,8 @@ static void pxa2xx_ac97_remove(struct platform_device *pdev, } static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -131,7 +132,8 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream, } static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -145,7 +147,8 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream, } static int pxa2xx_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index e758034db5c3..9a3e55b48129 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -121,7 +121,8 @@ static struct pxa2xx_gpio gpio_bus[] = { }, }; -static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) +static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -187,7 +188,8 @@ static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, } static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -248,7 +250,8 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int ret = 0; @@ -269,7 +272,8 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream) +static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { SACR1 |= SACR1_DRPL; @@ -353,8 +357,7 @@ struct snd_soc_dai pxa_i2s_dai = { .startup = pxa2xx_i2s_startup, .shutdown = pxa2xx_i2s_shutdown, .trigger = pxa2xx_i2s_trigger, - .hw_params = pxa2xx_i2s_hw_params,}, - .dai_ops = { + .hw_params = pxa2xx_i2s_hw_params, .set_fmt = pxa2xx_i2s_set_dai_fmt, .set_sysclk = pxa2xx_i2s_set_dai_sysclk, }, diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index ded7d995a922..360cc2a49d9d 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -343,7 +343,8 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; @@ -373,7 +374,8 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); unsigned long irqs; @@ -730,8 +732,6 @@ struct snd_soc_dai s3c2412_i2s_dai = { .ops = { .trigger = s3c2412_i2s_trigger, .hw_params = s3c2412_i2s_hw_params, - }, - .dai_ops = { .set_fmt = s3c2412_i2s_set_fmt, .set_clkdiv = s3c2412_i2s_set_clkdiv, .set_sysclk = s3c2412_i2s_set_sysclk, diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 19c5c3cf5d8c..31377821b2c5 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -271,7 +271,8 @@ static void s3c2443_ac97_remove(struct platform_device *pdev, } static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -313,7 +314,8 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd) } static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; @@ -327,7 +329,7 @@ static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream, } static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, - int cmd) + int cmd, struct snd_soc_dai *dai) { u32 ac_glbctrl; diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index c18977bceaf2..1bac9dd3dbd4 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -243,7 +243,8 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, } static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; u32 iismod; @@ -279,7 +280,8 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int ret = 0; @@ -475,8 +477,7 @@ struct snd_soc_dai s3c24xx_i2s_dai = { .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,}, .ops = { .trigger = s3c24xx_i2s_trigger, - .hw_params = s3c24xx_i2s_hw_params,}, - .dai_ops = { + .hw_params = s3c24xx_i2s_hw_params, .set_fmt = s3c24xx_i2s_set_fmt, .set_clkdiv = s3c24xx_i2s_set_clkdiv, .set_sysclk = s3c24xx_i2s_set_sysclk, diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index df7bc345c320..3318071dc80f 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -236,7 +236,8 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); static int hac_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id]; diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 55c3464163ab..52a233840d27 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -89,7 +89,8 @@ struct ssi_priv { * track usage of the SSI; it is simplex-only so prevent attempts of * concurrent playback + capture. FIXME: any locking required? */ -static int ssi_startup(struct snd_pcm_substream *substream) +static int ssi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -101,7 +102,8 @@ static int ssi_startup(struct snd_pcm_substream *substream) return 0; } -static void ssi_shutdown(struct snd_pcm_substream *substream) +static void ssi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -109,7 +111,8 @@ static void ssi_shutdown(struct snd_pcm_substream *substream) ssi->inuse = 0; } -static int ssi_trigger(struct snd_pcm_substream *substream, int cmd) +static int ssi_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -129,7 +132,8 @@ static int ssi_trigger(struct snd_pcm_substream *substream, int cmd) } static int ssi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id]; @@ -354,8 +358,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { .shutdown = ssi_shutdown, .trigger = ssi_trigger, .hw_params = ssi_hw_params, - }, - .dai_ops = { .set_sysclk = ssi_set_sysclk, .set_clkdiv = ssi_set_clkdiv, .set_fmt = ssi_set_fmt, @@ -383,8 +385,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { .shutdown = ssi_shutdown, .trigger = ssi_trigger, .hw_params = ssi_hw_params, - }, - .dai_ops = { .set_sysclk = ssi_set_sysclk, .set_clkdiv = ssi_set_clkdiv, .set_fmt = ssi_set_fmt, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c5cb9516fea4..43f4060dbe75 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -134,7 +134,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) /* startup the audio subsystem */ if (cpu_dai->ops.startup) { - ret = cpu_dai->ops.startup(substream); + ret = cpu_dai->ops.startup(substream, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't open interface %s\n", cpu_dai->name); @@ -151,7 +151,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } if (codec_dai->ops.startup) { - ret = codec_dai->ops.startup(substream); + ret = codec_dai->ops.startup(substream, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't open codec %s\n", codec_dai->name); @@ -248,7 +248,7 @@ codec_dai_err: platform_err: if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream); + cpu_dai->ops.shutdown(substream, cpu_dai); out: mutex_unlock(&pcm_mutex); return ret; @@ -339,10 +339,10 @@ static int soc_codec_close(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(codec_dai, 1); if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream); + cpu_dai->ops.shutdown(substream, cpu_dai); if (codec_dai->ops.shutdown) - codec_dai->ops.shutdown(substream); + codec_dai->ops.shutdown(substream, codec_dai); if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); @@ -406,7 +406,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } if (codec_dai->ops.prepare) { - ret = codec_dai->ops.prepare(substream); + ret = codec_dai->ops.prepare(substream, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: codec DAI prepare error\n"); goto out; @@ -414,7 +414,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } if (cpu_dai->ops.prepare) { - ret = cpu_dai->ops.prepare(substream); + ret = cpu_dai->ops.prepare(substream, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: cpu DAI prepare error\n"); goto out; @@ -491,7 +491,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } if (codec_dai->ops.hw_params) { - ret = codec_dai->ops.hw_params(substream, params); + ret = codec_dai->ops.hw_params(substream, params, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't set codec %s hw params\n", codec_dai->name); @@ -500,7 +500,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } if (cpu_dai->ops.hw_params) { - ret = cpu_dai->ops.hw_params(substream, params); + ret = cpu_dai->ops.hw_params(substream, params, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: interface %s hw params failed\n", cpu_dai->name); @@ -523,11 +523,11 @@ out: platform_err: if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream); + cpu_dai->ops.hw_free(substream, cpu_dai); interface_err: if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream); + codec_dai->ops.hw_free(substream, codec_dai); codec_err: if (machine->ops && machine->ops->hw_free) @@ -566,10 +566,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) /* now free hw params for the DAI's */ if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream); + codec_dai->ops.hw_free(substream, codec_dai); if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream); + cpu_dai->ops.hw_free(substream, cpu_dai); mutex_unlock(&pcm_mutex); return 0; @@ -586,7 +586,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) int ret; if (codec_dai->ops.trigger) { - ret = codec_dai->ops.trigger(substream, cmd); + ret = codec_dai->ops.trigger(substream, cmd, codec_dai); if (ret < 0) return ret; } @@ -598,7 +598,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } if (cpu_dai->ops.trigger) { - ret = cpu_dai->ops.trigger(substream, cmd); + ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai); if (ret < 0) return ret; } @@ -637,10 +637,10 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot); /* mute any active DAC's */ - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; - if (dai->dai_ops.digital_mute && dai->playback.active) - dai->dai_ops.digital_mute(dai, 1); + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *dai = card->dai_link[i].codec_dai; + if (dai->ops.digital_mute && dai->playback.active) + dai->ops.digital_mute(dai, 1); } /* suspend all pcms */ @@ -733,10 +733,10 @@ static void soc_resume_deferred(struct work_struct *work) } /* unmute any active DACs */ - for (i = 0; i < machine->num_links; i++) { - struct snd_soc_dai *dai = machine->dai_link[i].codec_dai; - if (dai->dai_ops.digital_mute && dai->playback.active) - dai->dai_ops.digital_mute(dai, 0); + for (i = 0; i < card->num_links; i++) { + struct snd_soc_dai *dai = card->dai_link[i].codec_dai; + if (dai->ops.digital_mute && dai->playback.active) + dai->ops.digital_mute(dai, 0); } for (i = 0; i < card->num_links; i++) { @@ -1849,8 +1849,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_sysclk(dai, clk_id, freq, dir); + if (dai->ops.set_sysclk) + return dai->ops.set_sysclk(dai, clk_id, freq, dir); else return -EINVAL; } @@ -1869,8 +1869,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - if (dai->dai_ops.set_clkdiv) - return dai->dai_ops.set_clkdiv(dai, div_id, div); + if (dai->ops.set_clkdiv) + return dai->ops.set_clkdiv(dai, div_id, div); else return -EINVAL; } @@ -1888,8 +1888,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { - if (dai->dai_ops.set_pll) - return dai->dai_ops.set_pll(dai, pll_id, freq_in, freq_out); + if (dai->ops.set_pll) + return dai->ops.set_pll(dai, pll_id, freq_in, freq_out); else return -EINVAL; } @@ -1905,8 +1905,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->dai_ops.set_fmt) - return dai->dai_ops.set_fmt(dai, fmt); + if (dai->ops.set_fmt) + return dai->ops.set_fmt(dai, fmt); else return -EINVAL; } @@ -1924,8 +1924,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int mask, int slots) { - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_tdm_slot(dai, mask, slots); + if (dai->ops.set_sysclk) + return dai->ops.set_tdm_slot(dai, mask, slots); else return -EINVAL; } @@ -1940,8 +1940,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); */ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) { - if (dai->dai_ops.set_sysclk) - return dai->dai_ops.set_tristate(dai, tristate); + if (dai->ops.set_sysclk) + return dai->ops.set_tristate(dai, tristate); else return -EINVAL; } @@ -1956,8 +1956,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); */ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) { - if (dai->dai_ops.digital_mute) - return dai->dai_ops.digital_mute(dai, mute); + if (dai->ops.digital_mute) + return dai->ops.digital_mute(dai, mute); else return -EINVAL; } From 2dac9217b26fd0a0a1712386ce2ea1411835ffb7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Nov 2008 14:01:41 +0000 Subject: [PATCH 161/367] ASoC: Add Marvell Zylonite machine support Implement support for the Marvell Zylonite PXA3xx reference platform, supporting standard AC97 stereo and AUX interfaces together with the auxiliary I2S interface of the WM9713. The board has two options for the MCLK of the WM9713: either the standard AC97 system clock can be used or the 13MHz CLK_POUT output of the PXA3xx can be used, selected via SW15 on the board. Currently only the AC97 system clock is supported by this driver. Signed-off-by: Mark Brown --- sound/soc/pxa/Makefile | 2 + sound/soc/pxa/zylonite.c | 219 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 sound/soc/pxa/zylonite.c diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index 1a3a36e75bf0..08a9f2797729 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile @@ -17,6 +17,7 @@ snd-soc-e800-objs := e800_wm9712.o snd-soc-spitz-objs := spitz.o snd-soc-em-x270-objs := em-x270.o snd-soc-palm27x-objs := palm27x.o +snd-soc-zylonite-objs := zylonite.o obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o @@ -25,3 +26,4 @@ obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o +obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c new file mode 100644 index 000000000000..842d6500d61f --- /dev/null +++ b/sound/soc/pxa/zylonite.c @@ -0,0 +1,219 @@ +/* + * zylonite.c -- SoC audio for Zylonite + * + * Copyright 2008 Wolfson Microelectronics PLC. + * Author: Mark Brown + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../codecs/wm9713.h" +#include "pxa2xx-pcm.h" +#include "pxa2xx-ac97.h" +#include "pxa-ssp.h" + +static struct snd_soc_card zylonite; + +static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Microphone", NULL), + SND_SOC_DAPM_MIC("Handset Microphone", NULL), + SND_SOC_DAPM_SPK("Multiactor", NULL), + SND_SOC_DAPM_SPK("Headset Earpiece", NULL), +}; + +/* Currently supported audio map */ +static const struct snd_soc_dapm_route audio_map[] = { + + /* Headphone output connected to HPL/HPR */ + { "Headphone", NULL, "HPL" }, + { "Headphone", NULL, "HPR" }, + + /* On-board earpiece */ + { "Headset Earpiece", NULL, "OUT3" }, + + /* Headphone mic */ + { "MIC2A", NULL, "Mic Bias" }, + { "Mic Bias", NULL, "Headset Microphone" }, + + /* On-board mic */ + { "MIC1", NULL, "Mic Bias" }, + { "Mic Bias", NULL, "Handset Microphone" }, + + /* Multiactor differentially connected over SPKL/SPKR */ + { "Multiactor", NULL, "SPKL" }, + { "Multiactor", NULL, "SPKR" }, +}; + +static int zylonite_wm9713_init(struct snd_soc_codec *codec) +{ + /* Currently we only support use of the AC97 clock here. If + * CLK_POUT is selected by SW15 then the clock API will need + * to be used to request and enable it here. + */ + + snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, + ARRAY_SIZE(zylonite_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + /* Static setup for now */ + snd_soc_dapm_enable_pin(codec, "Headphone"); + snd_soc_dapm_enable_pin(codec, "Headset Earpiece"); + + snd_soc_dapm_sync(codec); + return 0; +} + +static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + unsigned int pll_out = 0; + unsigned int acds = 0; + unsigned int wm9713_div = 0; + int ret = 0; + + switch (params_rate(params)) { + case 8000: + wm9713_div = 12; + pll_out = 2048000; + break; + case 16000: + wm9713_div = 6; + pll_out = 4096000; + break; + case 48000: + default: + wm9713_div = 2; + pll_out = 12288000; + acds = 1; + break; + } + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_tdm_slot(cpu_dai, + params_channels(params), + params_channels(params)); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); + if (ret < 0) + return ret; + + /* Note that if the PLL is in use the WM9713_PCMCLK_PLL_DIV needs + * to be set instead. + */ + ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, + WM9713_PCMDIV(wm9713_div)); + if (ret < 0) + return ret; + + return 0; +} + +static struct snd_soc_ops zylonite_voice_ops = { + .hw_params = zylonite_voice_hw_params, +}; + +static struct snd_soc_dai_link zylonite_dai[] = { +{ + .name = "AC97", + .stream_name = "AC97 HiFi", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], + .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], + .init = zylonite_wm9713_init, +}, +{ + .name = "AC97 Aux", + .stream_name = "AC97 Aux", + .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], + .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX], +}, +{ + .name = "WM9713 Voice", + .stream_name = "WM9713 Voice", + .cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP3], + .codec_dai = &wm9713_dai[WM9713_DAI_PCM_VOICE], + .ops = &zylonite_voice_ops, +}, +}; + +static struct snd_soc_card zylonite = { + .name = "Zylonite", + .dai_link = zylonite_dai, + .num_links = ARRAY_SIZE(zylonite_dai), +}; + +static struct snd_soc_device zylonite_snd_ac97_devdata = { + .card = &zylonite, + .platform = &pxa2xx_soc_platform, + .codec_dev = &soc_codec_dev_wm9713, +}; + +static struct platform_device *zylonite_snd_ac97_device; + +static int __init zylonite_init(void) +{ + int ret; + + zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1); + if (!zylonite_snd_ac97_device) + return -ENOMEM; + + platform_set_drvdata(zylonite_snd_ac97_device, + &zylonite_snd_ac97_devdata); + zylonite_snd_ac97_devdata.dev = &zylonite_snd_ac97_device->dev; + + ret = platform_device_add(zylonite_snd_ac97_device); + if (ret != 0) + platform_device_put(zylonite_snd_ac97_device); + + return ret; +} + +static void __exit zylonite_exit(void) +{ + platform_device_unregister(zylonite_snd_ac97_device); +} + +module_init(zylonite_init); +module_exit(zylonite_exit); + +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite"); +MODULE_LICENSE("GPL"); From 0c758bdd678860fff3c4b600ec6f134e43526850 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 21 Nov 2008 14:31:33 +0200 Subject: [PATCH 162/367] ASoC: OMAP: Fix preprocessor filled DAI name in McBSP DAI Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6013898f49b4..2eeb135c1e4b 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -454,7 +454,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, #define OMAP_MCBSP_DAI_BUILDER(link_id) \ { \ - .name = "omap-mcbsp-dai-(link_id)", \ + .name = "omap-mcbsp-dai-"#link_id, \ .id = (link_id), \ .type = SND_SOC_DAI_I2S, \ .playback = { \ From 0e734ad5d16ad1d87a428a30d117bb3541a8e24d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Nov 2008 14:05:48 +0000 Subject: [PATCH 163/367] ASoC: Staticise pxa2xx_pcm_ops It's not exported. Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index afcd892cd2fa..0f6b7bb2d44b 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -69,7 +69,7 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) return 0; } -struct snd_pcm_ops pxa2xx_pcm_ops = { +static struct snd_pcm_ops pxa2xx_pcm_ops = { .open = __pxa2xx_pcm_open, .close = __pxa2xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, From 39639faba98eafeb327a30bc10b7d921c398a59a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Nov 2008 14:28:49 +0000 Subject: [PATCH 164/367] ASoC: Improve error reporting for AC97 reset failures Print something a bit more verbose to help make errors a little more obvious. Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 2 +- sound/soc/codecs/wm9712.c | 2 +- sound/soc/codecs/wm9713.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 410fed953c54..1a3ea059a6dc 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -238,7 +238,7 @@ static int ad1980_soc_probe(struct platform_device *pdev) ret = ad1980_reset(codec, 0); if (ret < 0) { - printk(KERN_ERR "AC97 link error\n"); + printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); goto reset_err; } diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 81c38e7ad344..6e3e0f340179 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -690,7 +690,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) ret = wm9712_reset(codec, 0); if (ret < 0) { - printk(KERN_ERR "AC97 link error\n"); + printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n"); goto reset_err; } diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index a0cc5ac969a1..7be811a3b02a 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1243,7 +1243,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) wm9713_reset(codec, 0); ret = wm9713_reset(codec, 1); if (ret < 0) { - printk(KERN_ERR "AC97 link error\n"); + printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n"); goto reset_err; } From 42e81c991a71909929f8d0cdcdf8ced68799388a Mon Sep 17 00:00:00 2001 From: Hannes Eder Date: Fri, 21 Nov 2008 16:03:24 +0100 Subject: [PATCH 165/367] ALSA: hda - fix sparse warning Fix the following sparse warning: sound/pci/hda/patch_nvhdmi.c:161:25: warning: symbol 'snd_hda_preset_nvhdmi' was not declared. Should it be static? Signed-off-by: Hannes Eder Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 2eed2c8b98da..1360d54a7d01 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -28,6 +28,7 @@ #include #include "hda_codec.h" #include "hda_local.h" +#include "hda_patch.h" struct nvhdmi_spec { struct hda_multi_out multiout; From 4f904735c809e44c11f57cd4f82446aac1243e0e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Nov 2008 15:08:23 +0000 Subject: [PATCH 166/367] ALSA: ASoC: Fix typo in snd_soc_card update documentation Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/soc/machine.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index 4a9f51e2905c..bab7711ce963 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt @@ -9,7 +9,7 @@ the audio subsystem with the kernel as a platform device and is represented by the following struct:- /* SoC machine */ -struct snd_soc_card {_ +struct snd_soc_card { char *name; int (*probe)(struct platform_device *pdev); From d6752a532c700927fc7586cdd086391bfc50eaa9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 18:01:44 +0100 Subject: [PATCH 167/367] ALSA: hda - mark Dell studio 1535 quirk Fixed the quirk string for Dell studio 1535 (the product name wasn't published at the time the patch was made). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 4fa5189264b7..cf3641f9ebe9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1667,7 +1667,7 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254, - "unknown Dell", STAC_DELL_M6), + "Dell Studio 1535", STAC_DELL_M6), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255, "unknown Dell", STAC_DELL_M6), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256, From b20222667d371bb9ddeadd47d18072efcab3f6d2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 21 Nov 2008 21:24:03 +0100 Subject: [PATCH 168/367] ALSA: hda - Fix build without CONFIG_PROC_FS snd_print_pcm_rates() and snd_print_pcm_bits() are used by both hda_proc.c and hda_eld.c, thus they have to be defined in the common place. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 30 ++++++++++++++++++++++++++++++ sound/pci/hda/hda_proc.c | 27 --------------------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a98ce5b11188..d56d11ab20a3 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3425,3 +3425,33 @@ void snd_array_free(struct snd_array *array) array->alloced = 0; array->list = NULL; } + +/* + * used by hda_proc.c and hda_eld.c + */ +void snd_print_pcm_rates(int pcm, char *buf, int buflen) +{ + static unsigned int rates[] = { + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, + 96000, 176400, 192000, 384000 + }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) + if (pcm & (1 << i)) + j += snprintf(buf + j, buflen - j, " %d", rates[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +void snd_print_pcm_bits(int pcm, char *buf, int buflen) +{ + static unsigned int bits[] = { 8, 16, 20, 24, 32 }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) + if (pcm & (AC_SUPPCM_BITS_8 << i)) + j += snprintf(buf + j, buflen - j, " %d", bits[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 56cee3a22214..e7f91c44e631 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -89,21 +89,6 @@ static void print_amp_vals(struct snd_info_buffer *buffer, snd_iprintf(buffer, "\n"); } -void snd_print_pcm_rates(int pcm, char *buf, int buflen) -{ - static unsigned int rates[] = { - 8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, - 96000, 176400, 192000, 384000 - }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++) - if (pcm & (1 << i)) - j += snprintf(buf + j, buflen - j, " %d", rates[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} - static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; @@ -114,18 +99,6 @@ static void print_pcm_rates(struct snd_info_buffer *buffer, unsigned int pcm) snd_iprintf(buffer, "%s\n", buf); } -void snd_print_pcm_bits(int pcm, char *buf, int buflen) -{ - static unsigned int bits[] = { 8, 16, 20, 24, 32 }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) - if (pcm & (AC_SUPPCM_BITS_8 << i)) - j += snprintf(buf + j, buflen - j, " %d", bits[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} - static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; From b83923a3931a43df7397a7491f0c9d9b9d46624a Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:51 +0800 Subject: [PATCH 169/367] ALSA: hda - minor HDMI code cleanups Some minor code cleanups. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 58aaf06589a8..e10fa1e3dc9b 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -431,7 +431,7 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, * expand ELD's speaker allocation mask * * ELD tells the speaker mask in a compact(paired) form, - * expand ELD's notions to match the ones used by audio infoframe. + * expand ELD's notions to match the ones used by Audio InfoFrame. */ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { if (eld->spk_alloc & (1 << i)) @@ -592,8 +592,8 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { .channels_max = 8, .nid = CVT_NID, /* NID to query formats and rates and setup streams */ .ops = { - .open = intel_hdmi_playback_pcm_open, - .close = intel_hdmi_playback_pcm_close, + .open = intel_hdmi_playback_pcm_open, + .close = intel_hdmi_playback_pcm_close, .prepare = intel_hdmi_playback_pcm_prepare }, }; From cc02b83c904592ce8714787094256a9bf8e24b6f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:52 +0800 Subject: [PATCH 170/367] ALSA: hda - report selected CA index for Audio InfoFrame Print some CA selecting info, which could be valuable for debugging when something goes wrong. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index e10fa1e3dc9b..4a48011ae35b 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -444,14 +444,16 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, (spk_mask & channel_allocations[i].spk_mask) == channel_allocations[i].spk_mask) { ai->CA = channel_allocations[i].ca_index; - return 0; + break; } } snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); - snd_printd(KERN_INFO "failed to setup channel allocation: %d of %s\n", - channels, buf); - return -1; + snd_printdd(KERN_INFO + "HDMI: select CA 0x%x for %d-channel allocation: %s\n", + ai->CA, channels, buf); + + return ai->CA; } static void hdmi_setup_channel_mapping(struct hda_codec *codec, From 03284c8f23440479de79e8cbf368085ea872884e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:53 +0800 Subject: [PATCH 171/367] ALSA: hda - make HDMI messages more user friendly - make some messages more user friendly - add message prefix "HDMI:" to indicate the problem's domain (also easier to do `dmesg | grep HDMI` ;-) Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 30 ++++++++++++++++-------------- sound/pci/hda/patch_intelhdmi.c | 32 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 8740e7be8b24..3f10961a17b4 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -168,11 +168,11 @@ static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid, AC_VERB_GET_HDMI_ELDD, byte_index); #ifdef BE_PARANOID - printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val); + printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); #endif if ((val & AC_ELDD_ELD_VALID) == 0) { - snd_printd(KERN_INFO "Invalid ELD data byte %d\n", + snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", byte_index); val = 0; } @@ -208,7 +208,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER: snd_printd(KERN_INFO - "audio coding type 0 not expected in ELD\n"); + "HDMI: audio coding type 0 not expected\n"); break; case AUDIO_CODING_TYPE_LPCM: @@ -254,7 +254,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { snd_printd(KERN_INFO - "audio coding xtype %d not expected in ELD\n", + "HDMI: audio coding xtype %d not expected\n", a->format); a->format = 0; } else @@ -276,7 +276,8 @@ static int hdmi_update_eld(struct hdmi_eld *e, e->eld_ver = GRAB_BITS(buf, 0, 3, 5); if (e->eld_ver != ELD_VER_CEA_861D && e->eld_ver != ELD_VER_PARTIAL) { - snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver); + snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", + e->eld_ver); goto out_fail; } @@ -300,17 +301,17 @@ static int hdmi_update_eld(struct hdmi_eld *e, e->product_id = get_unaligned_le16(buf + 18); if (mnl > ELD_MAX_MNL) { - snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl); + snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl); goto out_fail; } else if (ELD_FIXED_BYTES + mnl > size) { - snd_printd(KERN_INFO "out of range MNL %d\n", mnl); + snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl); goto out_fail; } else strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl); for (i = 0; i < e->sad_count; i++) { if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - snd_printd(KERN_INFO "out of range SAD %d\n", i); + snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); goto out_fail; } hdmi_update_short_audio_desc(e->sad + i, @@ -339,7 +340,8 @@ static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) present = (present & AC_PINSENSE_PRESENCE); #ifdef CONFIG_SND_DEBUG_VERBOSE - printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv); + printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n", + !!present, !!eldv); #endif return eldv && present; @@ -365,11 +367,11 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, size = snd_hdmi_get_eld_size(codec, nid); if (size == 0) { /* wfg: workaround for ASUS P5E-VM HDMI board */ - snd_printd(KERN_INFO "ELD buf size is 0, force 128\n"); + snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); size = 128; } if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { - snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size); + snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); return -ERANGE; } @@ -404,7 +406,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) else buf2[0] = '\0'; - printk(KERN_INFO "supports coding type %s:" + printk(KERN_INFO "HDMI: supports coding type %s:" " channels = %d, rates =%s%s\n", cea_audio_coding_type_names[a->format], a->channels, @@ -428,14 +430,14 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) { int i; - printk(KERN_INFO "detected monitor %s at connection type %s\n", + printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n", e->monitor_name, eld_connection_type_names[e->conn_type]); if (e->spk_alloc) { char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - printk(KERN_INFO "available speakers:%s\n", buf); + printk(KERN_INFO "HDMI: available speakers:%s\n", buf); } for (i = 0; i < e->sad_count; i++) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 4a48011ae35b..fe08bef897cd 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -286,7 +286,7 @@ static void hdmi_set_channel_count(struct hda_codec *codec, int chs) AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); if (chs != hdmi_get_channel_count(codec)) - snd_printd(KERN_INFO "Channel count expect=%d, real=%d\n", + snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", chs, hdmi_get_channel_count(codec)); } @@ -299,7 +299,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec) for (i = 0; i < 8; i++) { slot = snd_hda_codec_read(codec, CVT_NID, 0, AC_VERB_GET_HDMI_CHAN_SLOT, i); - printk(KERN_DEBUG "ASP channel %d => slot %d\n", + printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", slot >> 4, slot & 0x7); } #endif @@ -326,12 +326,12 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) int size; size = snd_hdmi_get_eld_size(codec, PIN_NID); - printk(KERN_DEBUG "ELD buf size is %d\n", size); + printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); for (i = 0; i < 8; i++) { size = snd_hda_codec_read(codec, PIN_NID, 0, AC_VERB_GET_HDMI_DIP_SIZE, i); - printk(KERN_DEBUG "DIP GP[%d] buf size is %d\n", i, size); + printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); } #endif } @@ -359,8 +359,8 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) break; } snd_printd(KERN_INFO - "DIP GP[%d] buf reported size=%d, written=%d\n", - i, size, j); + "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", + i, size, j); } #endif } @@ -498,7 +498,9 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) int pind = !!(res & AC_UNSOL_RES_PD); int eldv = !!(res & AC_UNSOL_RES_ELDV); - printk(KERN_INFO "HDMI intrinsic event: PD=%d ELDV=%d\n", pind, eldv); + printk(KERN_INFO + "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", + pind, eldv); if (pind && eldv) { hdmi_parse_eld(codec); @@ -512,13 +514,13 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); - printk(KERN_INFO "HDMI non-intrinsic event: " - "SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", - subtag, - cp_state, - cp_ready); + printk(KERN_INFO + "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", + subtag, + cp_state, + cp_ready); - /* who cares? */ + /* TODO */ if (cp_state) ; if (cp_ready) @@ -532,9 +534,7 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; if (tag != INTEL_HDMI_EVENT_TAG) { - snd_printd(KERN_INFO - "Unexpected HDMI unsolicited event tag 0x%x\n", - tag); + snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); return; } From acb05993881005cdaf5f8291491b4edcb8f60ef3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:54 +0800 Subject: [PATCH 172/367] ALSA: hda - ELD proc interface write updates - rename ELD proc write routine to hdmi_write_eld_info() - support modifying WMAPro's profile Write to some ELD fields (monitor_name, manufacture_id, product_id, eld_version, edid_version) are deliberately not supported, since that won't correct wrong behaviors and only leads to confusions. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 3f10961a17b4..3c580ae07bd6 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -502,7 +502,7 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, hdmi_print_sad_info(i, e->sad + i, buffer); } -static void hdmi_write_eld_item(struct snd_info_entry *entry, +static void hdmi_write_eld_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct hdmi_eld *e = entry->private_data; @@ -515,6 +515,11 @@ static void hdmi_write_eld_item(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%s %llx", name, &val) != 2) continue; + /* + * We don't allow modification to these fields: + * monitor_name manufacture_id product_id + * eld_version edid_version + */ if (!strcmp(name, "connection_type")) e->conn_type = val; else if (!strcmp(name, "port_id")) @@ -548,6 +553,8 @@ static void hdmi_write_eld_item(struct snd_info_entry *entry, e->sad[n].sample_bits = val; else if (!strcmp(sname, "_max_bitrate")) e->sad[n].max_bitrate = val; + else if (!strcmp(sname, "_profile")) + e->sad[n].profile = val; if (n >= e->sad_count) e->sad_count = n + 1; } @@ -567,7 +574,7 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld) return err; snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); - entry->c.text.write = hdmi_write_eld_item; + entry->c.text.write = hdmi_write_eld_info; entry->mode |= S_IWUSR; eld->proc_entry = entry; From a5fcf89eff2372b50f2d47fbb3e1f3090f044ee3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:55 +0800 Subject: [PATCH 173/367] ALSA: hda - document the ELD proc interface Describe what ELD proc interface provides and how to fix incorrect values. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/Procfile.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index f738b296440a..bba2dbb79d81 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt @@ -153,6 +153,16 @@ card*/codec#* Shows the general codec information and the attribute of each widget node. +card*/eld#* + Available for HDMI or DisplayPort interfaces. + Shows ELD(EDID Like Data) info retrieved from the attached HDMI sink, + and describes its audio capabilities and configurations. + + Some ELD fields may be modified by doing `echo name hex_value > eld#*`. + Only do this if you are sure the HDMI sink provided value is wrong. + And if that makes your HDMI audio work, please report to us so that we + can fix it in future kernel releases. + Sequencer Information --------------------- From 9415e1c418b33bf9b8d8903fb98876ec72673e3f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:56 +0800 Subject: [PATCH 174/367] ALSA: hda - fix DisplayPort naming DisplayPort is a digital display interface standard put forth by the Video Electronics Standards Association (VESA). It defines a new license-free, royalty-free, digital audio/video interconnect, intended to be used primarily between a computer and its display monitor, or a computer and a home-theater system. - From Wikipedia, the free encyclopedia Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 3c580ae07bd6..aa438562efc7 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -72,7 +72,7 @@ static char *cea_speaker_allocation_names[] = { static char *eld_connection_type_names[4] = { "HDMI", - "Display Port", + "DisplayPort", "2-reserved", "3-reserved" }; From 4805286bffa9d7b85223ab2038f08b4b6322a176 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 22 Nov 2008 09:40:57 +0800 Subject: [PATCH 175/367] ALSA: hda - fix build warning when CONFIG_PROC_FS=n Fix "defined but not used" build warning by moving eld_versoin_names[] and cea_edid_version_names[] into hdmi_print_eld_info(). Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index aa438562efc7..fcad5ec31773 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -32,14 +32,6 @@ enum eld_versions { ELD_VER_PARTIAL = 31, }; -static char *eld_versoin_names[32] = { - "reserved", - "reserved", - "CEA-861D or below", - [3 ... 30] = "reserved", - [31] = "partial" -}; - enum cea_edid_versions { CEA_EDID_VER_NONE = 0, CEA_EDID_VER_CEA861 = 1, @@ -48,14 +40,6 @@ enum cea_edid_versions { CEA_EDID_VER_RESERVED = 4, }; -static char *cea_edid_version_names[8] = { - "no CEA EDID Timing Extension block present", - "CEA-861", - "CEA-861-A", - "CEA-861-B, C or D", - [4 ... 7] = "reserved" -}; - static char *cea_speaker_allocation_names[] = { /* 0 */ "FL/FR", /* 1 */ "LFE", @@ -478,6 +462,20 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, struct hdmi_eld *e = entry->private_data; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; + static char *eld_versoin_names[32] = { + "reserved", + "reserved", + "CEA-861D or below", + [3 ... 30] = "reserved", + [31] = "partial" + }; + static char *cea_edid_version_names[8] = { + "no CEA EDID Timing Extension block present", + "CEA-861", + "CEA-861-A", + "CEA-861-B, C or D", + [4 ... 7] = "reserved" + }; snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); snd_iprintf(buffer, "connection_type\t\t%s\n", From a9cb5c90539dd618029884701760fe79b9b83102 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Nov 2008 07:51:11 +0100 Subject: [PATCH 176/367] ALSA: hda - No 'Headphone as Line-out' swich without line-outs STAC/IDT driver creates "Headphone as Line-Out" switch even if there is no line-out pins on the machine. For devices only with headpohnes and speaker-outs, this switch shouldn't be created. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ce34e4dfe985..7cd395a175ef 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2962,7 +2962,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, cfg->hp_outs && !spec->multiout.hp_nid) spec->multiout.hp_nid = nid; - if (cfg->hp_outs > 1) { + 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", From ef8ef5fb1027b56f867d4b913cf52bfdc610d2a7 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Sun, 23 Nov 2008 11:31:41 +0800 Subject: [PATCH 177/367] ALSA: hda: Added an ALC888 model entry for Fujitsu-Siemens Amilo Xa3530 This patch fixes the bug 0004240: ALC888 - Intel HDA - Headphone Controlling. It is made against the 2008-11-23 snapshot. Added Realtek ALC888 model entry for the Fujitsu-Siemens Amilo Xa3530 laptop. It has 4 jacks: HP out, Mic-in, Line-in and Line-out/Side/SPDIF (this one is on the laptop side, the other ones are on the rear). Model detection works. Headphone jack sense works now. Front mic works now, was same as Acer Aspire 4930G. Added channel mode from 2 to 8 channels. In 2ch and 4ch modes, the front is also sent to the Line-out/side jack for convenience instead of just muting the Line-out/side jack like other models do. When using the Mic-in jack as CLFE, the sound is very low (bug?). To work it around, in 6ch mode the CLFE channel is duplicated to the Line-out/side jack because this one has a better amp. Cc: manu@frogged.de Signed-off-by: Vincent Petry Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 1 + sound/pci/hda/patch_realtek.c | 176 +++++++++++++++++- 2 files changed, 168 insertions(+), 9 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 1b7e36af0f0e..93624e7b4f04 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -919,6 +919,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. mitac Mitac 8252D clevo-m720 Clevo M720 laptop series fujitsu-pi2515 Fujitsu AMILO Pi2515 + fujitsu-xa3530 Fujitsu AMILO XA3530 3stack-6ch-intel Intel DG33* boards auto auto-config reading BIOS (default) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6ec56c62cb18..f52e271edd57 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -230,6 +230,7 @@ enum { ALC883_MITAC, ALC883_CLEVO_M720, ALC883_FUJITSU_PI2515, + ALC888_FUJITSU_XA3530, ALC883_3ST_6ch_INTEL, ALC888_ASUS_M90V, ALC888_ASUS_EEE1601, @@ -1155,6 +1156,141 @@ static void alc_fix_pincfg(struct hda_codec *codec, } } +/* + * ALC888 + */ + +/* + * 2ch mode + */ +static struct hda_verb alc888_4ST_ch2_intel_init[] = { +/* Mic-in jack as mic in */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-in jack as Line in */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-Out as Front */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; + +/* + * 4ch mode + */ +static struct hda_verb alc888_4ST_ch4_intel_init[] = { +/* Mic-in jack as mic in */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as Front */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc888_4ST_ch6_intel_init[] = { +/* Mic-in jack as CLFE */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + { } /* end */ +}; + +/* + * 8ch mode + */ +static struct hda_verb alc888_4ST_ch8_intel_init[] = { +/* Mic-in jack as CLFE */ + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-in jack as Surround */ + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, +/* Line-Out as Side */ + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, + { } /* end */ +}; + +static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = { + { 2, alc888_4ST_ch2_intel_init }, + { 4, alc888_4ST_ch4_intel_init }, + { 6, alc888_4ST_ch6_intel_init }, + { 8, alc888_4ST_ch8_intel_init }, +}; + +/* + * ALC888 Fujitsu Siemens Amillo xa3530 + */ + +static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { +/* Front Mic: set to PIN_IN (empty by default) */ + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +/* Connect Internal HP to Front */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Bass HP to Front */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Connect Line-Out side jack (SPDIF) to Side */ + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, +/* Connect Mic jack to CLFE */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, +/* Connect Line-in jack to Surround */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, +/* Connect HP out jack to Front */ + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, +/* Enable unsolicited event for HP jack and Line-out jack */ + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {} +}; + +static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec) +{ + unsigned int present; + unsigned int bits; + /* Line out presence */ + present = snd_hda_codec_read(codec, 0x17, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + /* HP out presence */ + present = present || snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + bits = present ? HDA_AMP_MUTE : 0; + /* Toggle internal speakers muting */ + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); + /* Toggle internal bass muting */ + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); +} + +static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + if (res >> 26 == ALC880_HP_EVENT) + alc888_fujitsu_xa3530_automute(codec); +} + + /* * ALC888 Acer Aspire 4930G model */ @@ -1164,7 +1300,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Unselect Front Mic by default in input mixer 3 */ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, -/* enable unsolicited event fpr HP jack */ +/* Enable unsolicited event for HP jack */ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, /* Connect Internal HP to front */ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, @@ -1177,7 +1313,7 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { { } }; -static struct hda_input_mux alc888_acer_aspire_4930g_capture_source[2] = { +static struct hda_input_mux alc888_2_capture_sources[2] = { /* Front mic only available on one ADC */ { .num_items = 4, @@ -1198,7 +1334,7 @@ static struct hda_input_mux alc888_acer_aspire_4930g_capture_source[2] = { } }; -static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { +static struct snd_kcontrol_new alc888_base_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), @@ -1225,11 +1361,12 @@ static struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = { static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) { unsigned int present; + unsigned int bits; present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - /* Toggle the internal HP PIN (regular muting doesn't work) */ - snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - (present ? 0x0 : PIN_OUT)); + bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, + HDA_AMP_MUTE, bits); } static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, @@ -8286,6 +8423,7 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC883_MITAC] = "mitac", [ALC883_CLEVO_M720] = "clevo-m720", [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", + [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", [ALC1200_ASUS_P5Q] = "asus-p5q", [ALC883_AUTO] = "auto", @@ -8346,6 +8484,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515), + SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530", + ALC888_FUJITSU_XA3530), SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), @@ -8472,7 +8612,7 @@ static struct alc_config_preset alc883_presets[] = { .init_hook = alc883_acer_aspire_automute, }, [ALC888_ACER_ASPIRE_4930G] = { - .mixers = { alc888_acer_aspire_4930g_mixer, + .mixers = { alc888_base_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, alc888_acer_aspire_4930g_verbs }, @@ -8486,8 +8626,8 @@ static struct alc_config_preset alc883_presets[] = { .channel_mode = alc883_3ST_6ch_modes, .need_dac_fix = 1, .num_mux_defs = - ARRAY_SIZE(alc888_acer_aspire_4930g_capture_source), - .input_mux = alc888_acer_aspire_4930g_capture_source, + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_2_capture_sources, .unsol_event = alc888_acer_aspire_4930g_unsol_event, .init_hook = alc888_acer_aspire_4930g_automute, }, @@ -8634,6 +8774,24 @@ static struct alc_config_preset alc883_presets[] = { .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event, .init_hook = alc883_2ch_fujitsu_pi2515_automute, }, + [ALC888_FUJITSU_XA3530] = { + .mixers = { alc888_base_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, + alc888_fujitsu_xa3530_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), + .adc_nids = alc883_adc_nids_rev, + .capsrc_nids = alc883_capsrc_nids_rev, + .dig_out_nid = ALC883_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes), + .channel_mode = alc888_4ST_8ch_intel_modes, + .num_mux_defs = + ARRAY_SIZE(alc888_2_capture_sources), + .input_mux = alc888_2_capture_sources, + .unsol_event = alc888_fujitsu_xa3530_unsol_event, + .init_hook = alc888_fujitsu_xa3530_automute, + }, [ALC888_LENOVO_SKY] = { .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs}, From 55b8bac50a494871594e81a05b37c15e7283f868 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 14:05:29 +0000 Subject: [PATCH 178/367] ASoC: Use supplied DAI for WM9713 rather than substream Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 7be811a3b02a..a502667fca7a 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -931,9 +931,7 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = dai->codec; u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3; switch (params_format(params)) { @@ -958,9 +956,7 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = dai->codec; u16 status; /* Gracefully shut down the voice interface. */ @@ -974,10 +970,8 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, static int ac97_hifi_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; int reg; u16 vra; @@ -995,10 +989,8 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream, static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->codec; u16 vra, xsle; vra = ac97_read(codec, AC97_EXTENDED_STATUS); From f8d05bdbb07458e5f2c6a8281bde08056836fea6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Nov 2008 08:25:45 +0200 Subject: [PATCH 179/367] ASoC: TWL4030: Disable soft-volume Keep Soft-volume disabled for now, since if it is enabled the FGAIN volume controls are not working in the current configuration: CODEC_MODE:OPT_MODE = 1 OPTION:ARXR2_EN = 1 OPTION:ARXL2_EN = 1 OPTION:ARXR1_EN = 0 OPTION:ARXL1_VRX_EN = 0 RX_PATH_SEL:RXL1_SEL = 0x0 (or 0x1) RX_PATH_SEL:RXR1_SEL = 0x0 (or 0x1) After the patch, FGAIN volume control works. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 33489515b928..49c7da39497e 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -87,7 +87,7 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_ALC_SET1 (0x2C) */ 0x00, /* REG_ALC_SET2 (0x2D) */ 0x00, /* REG_BOOST_CTL (0x2E) */ - 0x01, /* REG_SOFTVOL_CTL (0x2F) */ + 0x00, /* REG_SOFTVOL_CTL (0x2F) */ 0x00, /* REG_DTMF_FREQSEL (0x30) */ 0x00, /* REG_DTMF_TONEXT1H (0x31) */ 0x00, /* REG_DTMF_TONEXT1L (0x32) */ From c10b82cf085c38f2568609ffb10a6d725130f389 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Nov 2008 13:49:35 +0200 Subject: [PATCH 180/367] ASoC: TWL4030: Change the Master volume control to TLV TWL4030 FGAIN volume control has a range: -62 to 0 dB in 1 dB steps, 0 in the FGAIN means mute. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 49c7da39497e..498c42f7c6e0 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "twl4030.h" @@ -189,10 +190,16 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } +/* + * FGAIN volume control: + * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) + */ +static DECLARE_TLV_DB_SCALE(master_tlv, -6300, 100, 1); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { - SOC_DOUBLE_R("Master Playback Volume", + SOC_DOUBLE_R_TLV("Master Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 0, 0x3f, 0), + 0, 0x3f, 0, master_tlv), SOC_DOUBLE_R("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, 0, 0x1f, 0), From 0d33ea0b0f954dddd3996597c663c111249d4df9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Nov 2008 13:49:36 +0200 Subject: [PATCH 181/367] ASoC: TWL4030: Add CGAIN volume control Add CGAIN (Coarse gain control) to TWL4030 codec. The range of the CGAIN is: 0 dB to 12 dB in 6 dB steps. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 498c42f7c6e0..91effd341c0b 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -196,10 +196,20 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) */ static DECLARE_TLV_DB_SCALE(master_tlv, -6300, 100, 1); +/* + * CGAIN volume control: + * 0 dB to 12 dB in 6 dB steps + * value 2 and 3 means 12 dB + */ +static DECLARE_TLV_DB_SCALE(master_coarse_tlv, 0, 600, 0); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("Master Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, 0, 0x3f, 0, master_tlv), + SOC_DOUBLE_R_TLV("Master PCM Playback Volume", + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, + 6, 0x2, 0, master_coarse_tlv), SOC_DOUBLE_R("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, 0, 0x1f, 0), From b0bd53a7399f65e2d1b37cd44c5003e55b886c1e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 24 Nov 2008 13:49:38 +0200 Subject: [PATCH 182/367] ASoC: TWL4030: Add helper function for output gain controls Some of the gain controls in TWL (mostly those which are associated with the outputs) are implemented in an interesting way: 0x0 : Power down (mute) 0x1 : 6dB 0x2 : 0 dB 0x3 : -6 dB Inverting not going to help with these. Custom volsw and volsw_2r get/put functions to handle these gains. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 157 +++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 91effd341c0b..413623147891 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -190,6 +190,163 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } +/* + * Some of the gain controls in TWL (mostly those which are associated with + * the outputs) are implemented in an interesting way: + * 0x0 : Power down (mute) + * 0x1 : 6dB + * 0x2 : 0 dB + * 0x3 : -6 dB + * Inverting not going to help with these. + * Custom volsw and volsw_2r get/put functions to handle these gain bits. + */ +#define SOC_DOUBLE_TLV_TWL4030(xname, xreg, shift_left, shift_right, xmax,\ + xinvert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, \ + .get = snd_soc_get_volsw_twl4030, \ + .put = snd_soc_put_volsw_twl4030, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg, .shift = shift_left, .rshift = shift_right,\ + .max = xmax, .invert = xinvert} } +#define SOC_DOUBLE_R_TLV_TWL4030(xname, reg_left, reg_right, xshift, xmax,\ + xinvert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_2r, \ + .get = snd_soc_get_volsw_r2_twl4030,\ + .put = snd_soc_put_volsw_r2_twl4030, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ + .max = xmax, .invert = xinvert} } +#define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \ + SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \ + xinvert, tlv_array) + +static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int rshift = mc->rshift; + int max = mc->max; + int mask = (1 << fls(max)) - 1; + + ucontrol->value.integer.value[0] = + (snd_soc_read(codec, reg) >> shift) & mask; + if (ucontrol->value.integer.value[0]) + ucontrol->value.integer.value[0] = + max + 1 - ucontrol->value.integer.value[0]; + + if (shift != rshift) { + ucontrol->value.integer.value[1] = + (snd_soc_read(codec, reg) >> rshift) & mask; + if (ucontrol->value.integer.value[1]) + ucontrol->value.integer.value[1] = + max + 1 - ucontrol->value.integer.value[1]; + } + + return 0; +} + +static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int rshift = mc->rshift; + int max = mc->max; + int mask = (1 << fls(max)) - 1; + unsigned short val, val2, val_mask; + + val = (ucontrol->value.integer.value[0] & mask); + + val_mask = mask << shift; + if (val) + val = max + 1 - val; + val = val << shift; + if (shift != rshift) { + val2 = (ucontrol->value.integer.value[1] & mask); + val_mask |= mask << rshift; + if (val2) + val2 = max + 1 - val2; + val |= val2 << rshift; + } + return snd_soc_update_bits(codec, reg, val_mask, val); +} + +static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = mc->reg; + unsigned int reg2 = mc->rreg; + unsigned int shift = mc->shift; + int max = mc->max; + int mask = (1<value.integer.value[0] = + (snd_soc_read(codec, reg) >> shift) & mask; + ucontrol->value.integer.value[1] = + (snd_soc_read(codec, reg2) >> shift) & mask; + + if (ucontrol->value.integer.value[0]) + ucontrol->value.integer.value[0] = + max + 1 - ucontrol->value.integer.value[0]; + if (ucontrol->value.integer.value[1]) + ucontrol->value.integer.value[1] = + max + 1 - ucontrol->value.integer.value[1]; + + return 0; +} + +static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int reg = mc->reg; + unsigned int reg2 = mc->rreg; + unsigned int shift = mc->shift; + int max = mc->max; + int mask = (1 << fls(max)) - 1; + int err; + unsigned short val, val2, val_mask; + + val_mask = mask << shift; + val = (ucontrol->value.integer.value[0] & mask); + val2 = (ucontrol->value.integer.value[1] & mask); + + if (val) + val = max + 1 - val; + if (val2) + val2 = max + 1 - val2; + + val = val << shift; + val2 = val2 << shift; + + err = snd_soc_update_bits(codec, reg, val_mask, val); + if (err < 0) + return err; + + err = snd_soc_update_bits(codec, reg2, val_mask, val2); + return err; +} + /* * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) From ef1681d82f4bc2d9e023519f0bedb86519d10c43 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Nov 2008 17:29:28 +0100 Subject: [PATCH 183/367] ALSA: hda - Add probe_mask quirk for Medion MD96630 Medion MD96630 has ALC268 codec on slot#2 although it's not used for any purpose. This codec conflicts with the primiary codec ALC888 on slot#0, and gives mixer errors. This patch adds a corresponding entry to probe_mask blacklist. Reference: Novell bnc#412528 https://bugzilla.novell.com/show_bug.cgi?id=412528 Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3870ad622da6..6462d758e641 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2073,6 +2073,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X/T/R61", 0x01), /* broken BIOS */ SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01), + /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ + SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), {} }; From 3ba9e10a6d3b6abf5f5952572cff8f8d5a35ae54 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 18:01:05 +0000 Subject: [PATCH 184/367] ASoC: Remove DAI type information DAI type information is only ever used within ASoC in order to special case AC97 and for diagnostic purposes. Since modern CPUs and codecs support multi function DAIs which can be configured for several modes it is more trouble than it's worth to maintain anything other than a flag identifying AC97 DAIs so remove the type field and replace it with an ac97_control flag. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 2 +- include/sound/soc.h | 8 -------- sound/soc/atmel/atmel_ssc_dai.c | 3 --- sound/soc/au1x/psc-ac97.c | 2 +- sound/soc/au1x/psc-i2s.c | 1 - sound/soc/blackfin/bf5xx-ac97.c | 2 +- sound/soc/blackfin/bf5xx-i2s.c | 1 - sound/soc/codecs/ac97.c | 2 +- sound/soc/codecs/pcm3008.c | 1 - sound/soc/codecs/wm9712.c | 2 +- sound/soc/codecs/wm9713.c | 2 +- sound/soc/davinci/davinci-i2s.c | 1 - sound/soc/fsl/mpc5200_psc_i2s.c | 1 - sound/soc/omap/omap-mcbsp.c | 1 - sound/soc/pxa/pxa-ssp.c | 4 ---- sound/soc/pxa/pxa2xx-ac97.c | 6 +++--- sound/soc/pxa/pxa2xx-i2s.c | 1 - sound/soc/s3c24xx/neo1973_wm8753.c | 1 - sound/soc/s3c24xx/s3c2412-i2s.c | 1 - sound/soc/s3c24xx/s3c2443-ac97.c | 4 ++-- sound/soc/s3c24xx/s3c24xx-i2s.c | 1 - sound/soc/sh/hac.c | 4 ++-- sound/soc/sh/ssi.c | 2 -- sound/soc/soc-core.c | 31 ++++++++---------------------- 24 files changed, 21 insertions(+), 63 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index f51cb55902f7..a01a24b10196 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -184,7 +184,7 @@ struct snd_soc_dai { /* DAI description */ char *name; unsigned int id; - unsigned char type; + int ac97_control; /* DAI callbacks */ int (*probe)(struct platform_device *pdev, diff --git a/include/sound/soc.h b/include/sound/soc.h index e4465f73aa46..444f9c211379 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -143,14 +143,6 @@ enum snd_soc_bias_level { SND_SOC_BIAS_OFF, }; -/* - * Digital Audio Interface (DAI) types - */ -#define SND_SOC_DAI_AC97 0x1 -#define SND_SOC_DAI_I2S 0x2 -#define SND_SOC_DAI_PCM 0x4 -#define SND_SOC_DAI_AC97_BUS 0x8 /* for custom i.e. non ac97_codec.c */ - struct snd_soc_device; struct snd_soc_pcm_stream; struct snd_soc_ops; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 916f73b9a18f..0bb18dfa9495 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -702,7 +702,6 @@ static int atmel_ssc_resume(struct platform_device *pdev, struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { { .name = "atmel-ssc0", .id = 0, - .type = SND_SOC_DAI_PCM, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -727,7 +726,6 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { #if NUM_SSC_DEVICES == 3 { .name = "atmel-ssc1", .id = 1, - .type = SND_SOC_DAI_PCM, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { @@ -751,7 +749,6 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { }, { .name = "atmel-ssc2", .id = 2, - .type = SND_SOC_DAI_PCM, .suspend = atmel_ssc_suspend, .resume = atmel_ssc_resume, .playback = { diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index ad60a6042cad..a0bcfeaf5f86 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -346,7 +346,7 @@ static int au1xpsc_ac97_resume(struct platform_device *pdev, struct snd_soc_dai au1xpsc_ac97_dai = { .name = "au1xpsc_ac97", - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .probe = au1xpsc_ac97_probe, .remove = au1xpsc_ac97_remove, .suspend = au1xpsc_ac97_suspend, diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 05a5acbb16ae..f4217e70a787 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -371,7 +371,6 @@ static int au1xpsc_i2s_resume(struct platform_device *pdev, struct snd_soc_dai au1xpsc_i2s_dai = { .name = "au1xpsc_i2s", - .type = SND_SOC_DAI_I2S, .probe = au1xpsc_i2s_probe, .remove = au1xpsc_i2s_remove, .suspend = au1xpsc_i2s_suspend, diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 5dcd3f665ab1..709bdf08e398 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -409,7 +409,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev, struct snd_soc_dai bfin_ac97_dai = { .name = "bf5xx-ac97", .id = 0, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .probe = bf5xx_ac97_probe, .remove = bf5xx_ac97_remove, .suspend = bf5xx_ac97_suspend, diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 4e675b55b182..6e5036bf9245 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -292,7 +292,6 @@ static int bf5xx_i2s_resume(struct platform_device *pdev, struct snd_soc_dai bf5xx_i2s_dai = { .name = "bf5xx-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = bf5xx_i2s_probe, .remove = bf5xx_i2s_remove, .suspend = bf5xx_i2s_suspend, diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 8a93aff359d0..c4208c8210c8 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -43,7 +43,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai ac97_dai = { .name = "AC97 HiFi", - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .playback = { .stream_name = "AC97 Playback", .channels_min = 1, diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 2b26e1d80c8d..651a15eb8c2c 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -33,7 +33,6 @@ struct snd_soc_dai pcm3008_dai = { .name = "PCM3008 HiFi", - .type = SND_SOC_DAI_I2S, .playback = { .stream_name = "PCM3008 Playback", .channels_min = 1, diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 6e3e0f340179..40f14061fb72 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -535,7 +535,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai wm9712_dai[] = { { .name = "AC97 HiFi", - .type = SND_SOC_DAI_AC97_BUS, + .ac97_control = 1, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index a502667fca7a..9dad0bffcb05 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1024,7 +1024,7 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai wm9713_dai[] = { { .name = "AC97 HiFi", - .type = SND_SOC_DAI_AC97_BUS, + .ac97_control = 1, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 7a17cd0ecf64..cf31b3bb96cf 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -460,7 +460,6 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai davinci_i2s_dai = { .name = "davinci-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = davinci_i2s_probe, .remove = davinci_i2s_remove, .playback = { diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index e2c172f38979..9ad8f9a2d8e9 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -469,7 +469,6 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) * psc_i2s_dai_template: template CPU Digital Audio Interface */ static struct snd_soc_dai psc_i2s_dai_template = { - .type = SND_SOC_DAI_I2S, .playback = { .channels_min = 2, .channels_max = 2, diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 2eeb135c1e4b..252bc7ebb194 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -456,7 +456,6 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, { \ .name = "omap-mcbsp-dai-"#link_id, \ .id = (link_id), \ - .type = SND_SOC_DAI_I2S, \ .playback = { \ .channels_min = 2, \ .channels_max = 2, \ diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d0dd6245a20a..402fc5ba65e7 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -788,7 +788,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { { .name = "pxa2xx-ssp1", .id = 0, - .type = SND_SOC_DAI_PCM, .probe = pxa_ssp_probe, .remove = pxa_ssp_remove, .suspend = pxa_ssp_suspend, @@ -820,7 +819,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { }, { .name = "pxa2xx-ssp2", .id = 1, - .type = SND_SOC_DAI_PCM, .probe = pxa_ssp_probe, .remove = pxa_ssp_remove, .suspend = pxa_ssp_suspend, @@ -853,7 +851,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { { .name = "pxa2xx-ssp3", .id = 2, - .type = SND_SOC_DAI_PCM, .probe = pxa_ssp_probe, .remove = pxa_ssp_remove, .suspend = pxa_ssp_suspend, @@ -886,7 +883,6 @@ struct snd_soc_dai pxa_ssp_dai[] = { { .name = "pxa2xx-ssp4", .id = 3, - .type = SND_SOC_DAI_PCM, .probe = pxa_ssp_probe, .remove = pxa_ssp_remove, .suspend = pxa_ssp_suspend, diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 86667d2f1b75..bffbe288634c 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -173,7 +173,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97", .id = 0, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .probe = pxa2xx_ac97_probe, .remove = pxa2xx_ac97_remove, .suspend = pxa2xx_ac97_suspend, @@ -196,7 +196,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97-aux", .id = 1, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .playback = { .stream_name = "AC97 Aux Playback", .channels_min = 1, @@ -215,7 +215,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { { .name = "pxa2xx-ac97-mic", .id = 2, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 9a3e55b48129..f9a9e2ebafa1 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -340,7 +340,6 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev, struct snd_soc_dai pxa_i2s_dai = { .name = "pxa2xx-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .suspend = pxa2xx_i2s_suspend, .resume = pxa2xx_i2s_resume, .playback = { diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 528fc3f1b45b..3df2224a6723 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -548,7 +548,6 @@ static int neo1973_wm8753_init(struct snd_soc_codec *codec) static struct snd_soc_dai bt_dai = { .name = "Bluetooth", .id = 0, - .type = SND_SOC_DAI_PCM, .playback = { .channels_min = 1, .channels_max = 1, diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 360cc2a49d9d..1c741047ae35 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -713,7 +713,6 @@ static int s3c2412_i2s_resume(struct platform_device *pdev, struct snd_soc_dai s3c2412_i2s_dai = { .name = "s3c2412-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = s3c2412_i2s_probe, .suspend = s3c2412_i2s_suspend, .resume = s3c2412_i2s_resume, diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 31377821b2c5..41bde6a3883b 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -358,7 +358,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { { .name = "s3c2443-ac97", .id = 0, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .probe = s3c2443_ac97_probe, .remove = s3c2443_ac97_remove, .playback = { @@ -380,7 +380,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { { .name = "pxa2xx-ac97-mic", .id = 1, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .capture = { .stream_name = "AC97 Mic Capture", .channels_min = 1, diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 1bac9dd3dbd4..8d9135f41bc9 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -461,7 +461,6 @@ static int s3c24xx_i2s_resume(struct platform_device *pdev, struct snd_soc_dai s3c24xx_i2s_dai = { .name = "s3c24xx-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = s3c24xx_i2s_probe, .suspend = s3c24xx_i2s_suspend, .resume = s3c24xx_i2s_resume, diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 3318071dc80f..c435913c60eb 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -271,7 +271,7 @@ struct snd_soc_dai sh4_hac_dai[] = { { .name = "HAC0", .id = 0, - .type = SND_SOC_DAI_AC97, + .ac97_control = 1, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, @@ -291,8 +291,8 @@ struct snd_soc_dai sh4_hac_dai[] = { #ifdef CONFIG_CPU_SUBTYPE_SH7760 { .name = "HAC1", + .ac97_control = 1, .id = 1, - .type = SND_SOC_DAI_AC97, .playback = { .rates = AC97_RATES, .formats = AC97_FMTS, diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 52a233840d27..fed544a3deff 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -340,7 +340,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { { .name = "SSI0", .id = 0, - .type = SND_SOC_DAI_I2S, .playback = { .rates = SSI_RATES, .formats = SSI_FMTS, @@ -367,7 +366,6 @@ struct snd_soc_dai sh4_ssi_dai[] = { { .name = "SSI1", .id = 1, - .type = SND_SOC_DAI_I2S, .playback = { .rates = SSI_RATES, .formats = SSI_FMTS, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 43f4060dbe75..0d47696ccd07 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -100,20 +100,6 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) } #endif -static inline const char *get_dai_name(int type) -{ - switch (type) { - case SND_SOC_DAI_AC97_BUS: - case SND_SOC_DAI_AC97: - return "AC97"; - case SND_SOC_DAI_I2S: - return "I2S"; - case SND_SOC_DAI_PCM: - return "PCM"; - } - return NULL; -} - /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -652,7 +638,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97) + if (cpu_dai->suspend && !cpu_dai->ac97_control) cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) platform->suspend(pdev, cpu_dai); @@ -678,7 +664,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97) + if (cpu_dai->suspend && cpu_dai->ac97_control) cpu_dai->suspend(pdev, cpu_dai); } @@ -714,7 +700,7 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97) + if (cpu_dai->resume && cpu_dai->ac97_control) cpu_dai->resume(pdev, cpu_dai); } @@ -741,7 +727,7 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; - if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97) + if (cpu_dai->resume && !cpu_dai->ac97_control) cpu_dai->resume(pdev, cpu_dai); if (platform->resume) platform->resume(pdev, cpu_dai); @@ -898,8 +884,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, codec_dai->codec = socdev->codec; /* check client and interface hw capabilities */ - sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name, - get_dai_name(cpu_dai->type), num); + sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, + num); if (codec_dai->playback.channels_min) playback = 1; @@ -1270,8 +1256,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) continue; } } - if (card->dai_link[i].codec_dai->type == - SND_SOC_DAI_AC97_BUS) + if (card->dai_link[i].codec_dai->ac97_control) ac97 = 1; } snprintf(codec->card->shortname, sizeof(codec->card->shortname), @@ -1335,7 +1320,7 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) { + if (codec_dai->ac97_control && codec->ac97) { soc_ac97_dev_unregister(codec); goto free_card; } From 67c91513b81a101800f113013234d2ab06bc5e52 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 17:45:26 +0000 Subject: [PATCH 185/367] ASoC: Flag AD1980 as an AC97 interface Special handling is required for suspend and resume of AC97 codecs due to the control path going over the data bus. Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 1a3ea059a6dc..a9a268112d3f 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -145,6 +145,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, struct snd_soc_dai ad1980_dai = { .name = "AC97", + .ac97_control = 1, .playback = { .stream_name = "Playback", .channels_min = 2, From fde22f272dad4fef7ba611e3f75fa94f7b43fae6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 24 Nov 2008 18:08:18 +0000 Subject: [PATCH 186/367] ASoC: Lower priority of resume work logging Now that the ASoC resume has been punted to a workqueue for a release cycle without attracting bug reports it should be safe to make the log messages associated with it debug level, reducing noise and kernel size in production configurations. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0d47696ccd07..dbd92e12e860 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -693,7 +693,7 @@ static void soc_resume_deferred(struct work_struct *work) * so userspace apps are blocked from touching us */ - dev_info(socdev->dev, "starting resume work\n"); + dev_dbg(socdev->dev, "starting resume work\n"); if (card->resume_pre) card->resume_pre(pdev); @@ -736,7 +736,7 @@ static void soc_resume_deferred(struct work_struct *work) if (card->resume_post) card->resume_post(pdev); - dev_info(socdev->dev, "resume work completed\n"); + dev_dbg(socdev->dev, "resume work completed\n"); /* userspace can access us now we are back as we were before */ snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0); @@ -747,10 +747,10 @@ static int soc_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - dev_info(socdev->dev, "scheduling resume work\n"); + dev_dbg(socdev->dev, "scheduling resume work\n"); if (!schedule_work(&socdev->deferred_resume_work)) - dev_err(socdev->dev, "work item may be lost\n"); + dev_err(socdev->dev, "resume work item may be lost\n"); return 0; } From 82894b6f6f109722070d4d78730fe50cdaba9443 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2008 11:42:54 +0100 Subject: [PATCH 187/367] ALSA: hda - Fix proc pcm rate bits Show only the relevant bits in the PCM rate bits as in the earlier version. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index e7f91c44e631..a2eba4f17e9c 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -103,7 +103,7 @@ static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; - snd_iprintf(buffer, " bits [0x%x]:", pcm); + snd_iprintf(buffer, " bits [0x%x]:", (pcm & AC_SUPPCM_RATES) >> 16); snd_print_pcm_bits(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); } From c6e4c66613c2bb040e53bb04006c277992cc8f4b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2008 11:58:19 +0100 Subject: [PATCH 188/367] ALSA: hda - Assign unsol tags dynamically in patch_sigmatel.c Since we need to handle many unsolicited events assigned to different widgets, allocate the event dynamically using the existing events array, and use the tag appropriately instead of combination of fixed number and widget nid. (Note that widget nid can be over 4 bits!) Also, replaced the call of unsol_event handler with a dedicated function to be more readable. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 159 +++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 58 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 09b3f4b1db4d..4b7dda57c0e9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -36,10 +36,12 @@ #include "hda_patch.h" #include "hda_beep.h" -#define STAC_VREF_EVENT 0x00 -#define STAC_INSERT_EVENT 0x10 -#define STAC_PWR_EVENT 0x20 -#define STAC_HP_EVENT 0x30 +enum { + STAC_VREF_EVENT = 1, + STAC_INSERT_EVENT, + STAC_PWR_EVENT, + STAC_HP_EVENT, +}; enum { STAC_REF, @@ -134,6 +136,8 @@ enum { struct sigmatel_event { hda_nid_t nid; + unsigned char type; + unsigned char tag; int data; }; @@ -2549,6 +2553,9 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, return 0; } +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, + unsigned char type); + static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2561,7 +2568,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, /* check to be sure that the ports are upto date with * switch changes */ - codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26); + stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); return 1; } @@ -2601,8 +2608,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ * appropriately according to the pin direction */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | nid) << 26); + stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); return 1; } @@ -3768,8 +3774,8 @@ static int stac92xx_add_jack(struct hda_codec *codec, #endif } -static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, - int data) +static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, + unsigned char type, int data) { struct sigmatel_event *event; @@ -3778,32 +3784,59 @@ static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, if (!event) return -ENOMEM; event->nid = nid; + event->type = type; + event->tag = spec->events.used; event->data = data; - return 0; + return event->tag; } -static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid) +static struct sigmatel_event *stac_get_event(struct hda_codec *codec, + hda_nid_t nid, unsigned char type) { struct sigmatel_spec *spec = codec->spec; - struct sigmatel_event *events = spec->events.list; - if (events) { - int i; - for (i = 0; i < spec->events.used; i++) - if (events[i].nid == nid) - return events[i].data; + struct sigmatel_event *event = spec->events.list; + int i; + + for (i = 0; i < spec->events.used; i++, event++) { + if (event->nid == nid && event->type == type) + return event; } - return 0; + return NULL; +} + +static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec, + unsigned char tag) +{ + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_event *event = spec->events.list; + int i; + + for (i = 0; i < spec->events.used; i++, event++) { + if (event->tag == tag) + return event; + } + return NULL; } static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, - unsigned int event) + unsigned int type) { - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event | nid)); - } + struct sigmatel_event *event; + int tag; + + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + return; + event = stac_get_event(codec, nid, type); + if (event) + tag = event->tag; + else + tag = stac_add_event(codec->spec, nid, type, 0); + if (tag < 0) + return; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | tag); } static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) @@ -3862,7 +3895,7 @@ static int stac92xx_init(struct hda_codec *codec) /* 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 | nid); + enable_pin_detect(codec, nid, STAC_HP_EVENT); } /* force to enable the first line-out; the others are set up * in unsol_event @@ -3870,8 +3903,8 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); /* fake event to set up pins */ - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); + stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], + STAC_HP_EVENT); } else { stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); @@ -3892,7 +3925,7 @@ static int stac92xx_init(struct hda_codec *codec) } pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); - enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid); + enable_pin_detect(codec, nid, STAC_INSERT_EVENT); } } for (i = 0; i < spec->num_dmics; i++) @@ -3907,7 +3940,6 @@ static int stac92xx_init(struct hda_codec *codec) for (i = 0; i < spec->num_pwrs; i++) { hda_nid_t nid = spec->pwr_nids[i]; int pinctl, def_conf; - int event = STAC_PWR_EVENT; if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) continue; /* already has an unsol event */ @@ -3930,8 +3962,8 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } - enable_pin_detect(codec, spec->pwr_nids[i], event | i); - codec->patch_ops.unsol_event(codec, (event | i) << 26); + enable_pin_detect(codec, nid, STAC_PWR_EVENT); + stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); } if (spec->dac_list) stac92xx_power_down(codec); @@ -4059,7 +4091,7 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i) return 0; } -static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) +static void stac92xx_hp_detect(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -4182,33 +4214,43 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) } } +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, + unsigned char type) +{ + struct sigmatel_event *event = stac_get_event(codec, nid, type); + if (!event) + return; + codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); +} + static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; - int event = (res >> 26) & 0x70; - int nid = res >> 26 & 0x0f; + struct sigmatel_event *event; + int tag, data; - switch (event) { + tag = (res >> 26) & 0x7f; + event = stac_get_event_from_tag(codec, tag); + if (!event) + return; + + switch (event->type) { case STAC_HP_EVENT: - stac92xx_hp_detect(codec, res); + stac92xx_hp_detect(codec); /* fallthru */ case STAC_INSERT_EVENT: case STAC_PWR_EVENT: - if (nid) { - if (spec->num_pwrs > 0) - stac92xx_pin_sense(codec, nid); - stac92xx_report_jack(codec, nid); - } + if (spec->num_pwrs > 0) + stac92xx_pin_sense(codec, event->nid); + stac92xx_report_jack(codec, event->nid); break; - case STAC_VREF_EVENT: { - int data = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - int idx = stac92xx_event_data(codec, nid); + 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 << idx))); + !!(data & (1 << event->data))); break; - } } } @@ -4223,8 +4265,8 @@ static int stac92xx_resume(struct hda_codec *codec) snd_hda_codec_resume_cache(codec); /* fake event to set up pins again to override cached values */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); + stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], + STAC_HP_EVENT); return 0; } @@ -4732,14 +4774,15 @@ again: switch (spec->board_config) { case STAC_HP_M4: /* Enable VREF power saving on GPIO1 detect */ + err = stac_add_event(spec, 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_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); - err = stac92xx_add_event(spec, codec->afg, 0x02); - if (err < 0) - return err; + AC_USRSP_EN | err); spec->gpio_mask |= 0x02; break; } @@ -5131,14 +5174,14 @@ static int patch_stac9205(struct hda_codec *codec) stac_change_pin_config(codec, 0x20, 0x1c410030); /* Enable unsol response for GPIO4/Dock HP connection */ + err = stac_add_event(spec, 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_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); - err = stac92xx_add_event(spec, codec->afg, 0x01); - if (err < 0) - return err; + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | err); spec->gpio_dir = 0x0b; spec->eapd_mask = 0x01; From 93bf5d8753b2e3cc9e8982d551d119a54a31a7ec Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Tue, 25 Nov 2008 12:21:05 +0100 Subject: [PATCH 189/367] ALSA: pcxhr - add support for pcxhr stereo sound cards - Add support for pcxhr stereo cards - do some clean up Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr_core.c | 291 ++++++++++++++++++++++------------- sound/pci/pcxhr/pcxhr_core.h | 5 +- 2 files changed, 190 insertions(+), 106 deletions(-) diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 7143259cfe34..d5f18226261d 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -132,13 +132,15 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg, *read = PCXHR_INPB(mgr, reg); if ((*read & mask) == bit) { if (i > 100) - snd_printdd("ATTENTION! check_reg(%x) loopcount=%d\n", + snd_printdd("ATTENTION! check_reg(%x) " + "loopcount=%d\n", reg, i); return 0; } i++; } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=0x%x\n", + snd_printk(KERN_ERR + "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n", reg, mask, *read); return -EIO; } @@ -159,18 +161,22 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg, #define PCXHR_IT_TEST_XILINX (0x0000003C | PCXHR_MASK_IT_HF1 | \ PCXHR_MASK_IT_MANAGE_HF5) #define PCXHR_IT_DOWNLOAD_BOOT (0x0000000C | PCXHR_MASK_IT_HF1 | \ - PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT) + PCXHR_MASK_IT_MANAGE_HF5 | \ + PCXHR_MASK_IT_WAIT) #define PCXHR_IT_RESET_BOARD_FUNC (0x0000000C | PCXHR_MASK_IT_HF0 | \ - PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT_EXTRA) + PCXHR_MASK_IT_MANAGE_HF5 | \ + PCXHR_MASK_IT_WAIT_EXTRA) #define PCXHR_IT_DOWNLOAD_DSP (0x0000000C | \ - PCXHR_MASK_IT_MANAGE_HF5 | PCXHR_MASK_IT_WAIT) + PCXHR_MASK_IT_MANAGE_HF5 | \ + PCXHR_MASK_IT_WAIT) #define PCXHR_IT_DEBUG (0x0000005A | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_RESET_SEMAPHORE (0x0000005C | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_MESSAGE (0x00000074 | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_RESET_CHK (0x00000076 | PCXHR_MASK_IT_NO_HF0_HF1) #define PCXHR_IT_UPDATE_RBUFFER (0x00000078 | PCXHR_MASK_IT_NO_HF0_HF1) -static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atomic) +static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, + unsigned int itdsp, int atomic) { int err; unsigned char reg; @@ -178,17 +184,21 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atom if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) { /* clear hf5 bit */ PCXHR_OUTPL(mgr, PCXHR_PLX_MBOX0, - PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & ~PCXHR_MBOX0_HF5); + PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & + ~PCXHR_MBOX0_HF5); } if ((itdsp & PCXHR_MASK_IT_NO_HF0_HF1) == 0) { - reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ; + reg = (PCXHR_ICR_HI08_RREQ | + PCXHR_ICR_HI08_TREQ | + PCXHR_ICR_HI08_HDRQ); if (itdsp & PCXHR_MASK_IT_HF0) reg |= PCXHR_ICR_HI08_HF0; if (itdsp & PCXHR_MASK_IT_HF1) reg |= PCXHR_ICR_HI08_HF1; PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg); } - reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | PCXHR_CVR_HI08_HC); + reg = (unsigned char)(((itdsp & PCXHR_MASK_EXTRA_INFO) >> 1) | + PCXHR_CVR_HI08_HC); PCXHR_OUTPB(mgr, PCXHR_DSP_CVR, reg); if (itdsp & PCXHR_MASK_IT_WAIT) { if (atomic) @@ -211,10 +221,14 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, unsigned int itdsp, int atom } if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) { /* wait for hf5 bit */ - err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, PCXHR_MBOX0_HF5, - PCXHR_MBOX0_HF5, PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_PLX_MBOX0, + PCXHR_MBOX0_HF5, + PCXHR_MBOX0_HF5, + PCXHR_TIMEOUT_DSP, + ®); if (err) { - snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT HF5\n"); + snd_printk(KERN_ERR + "pcxhr_send_it_dsp : TIMEOUT HF5\n"); return err; } } @@ -263,7 +277,8 @@ void pcxhr_enable_dsp(struct pcxhr_mgr *mgr) /* * load the xilinx image */ -int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilinx, int second) +int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, + const struct firmware *xilinx, int second) { unsigned int i; unsigned int chipsc; @@ -274,7 +289,9 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin /* test first xilinx */ chipsc = PCXHR_INPL(mgr, PCXHR_PLX_CHIPSC); /* REV01 cards do not support the PCXHR_CHIPSC_GPI_USERI bit anymore */ - /* this bit will always be 1; no possibility to test presence of first xilinx */ + /* this bit will always be 1; + * no possibility to test presence of first xilinx + */ if(second) { if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) { snd_printk(KERN_ERR "error loading first xilinx\n"); @@ -290,7 +307,8 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, const struct firmware *xilin data = *image; mask = 0x80; while (mask) { - chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | PCXHR_CHIPSC_DATA_IN); + chipsc &= ~(PCXHR_CHIPSC_DATA_CLK | + PCXHR_CHIPSC_DATA_IN); if (data & mask) chipsc |= PCXHR_CHIPSC_DATA_IN; PCXHR_OUTPL(mgr, PCXHR_PLX_CHIPSC, chipsc); @@ -330,15 +348,20 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp) data = dsp->data + i; if (i == 0) { /* test data header consistency */ - len = (unsigned int)((data[0]<<16) + (data[1]<<8) + data[2]); - if (len && dsp->size != (len + 2) * 3) + len = (unsigned int)((data[0]<<16) + + (data[1]<<8) + + data[2]); + if (len && (dsp->size != (len + 2) * 3)) return -EINVAL; } /* wait DSP ready for new transfer */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, - PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &dummy); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_TRDY, + PCXHR_ISR_HI08_TRDY, + PCXHR_TIMEOUT_DSP, &dummy); if (err) { - snd_printk(KERN_ERR "dsp loading error at position %d\n", i); + snd_printk(KERN_ERR + "dsp loading error at position %d\n", i); return err; } /* send host data */ @@ -357,7 +380,8 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp) /* * load the eeprom image */ -int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eeprom) +int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, + const struct firmware *eeprom) { int err; unsigned char reg; @@ -365,7 +389,9 @@ int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, const struct firmware *eepro /* init value of the ICR register */ reg = PCXHR_ICR_HI08_RREQ | PCXHR_ICR_HI08_TREQ | PCXHR_ICR_HI08_HDRQ; if (PCXHR_INPL(mgr, PCXHR_PLX_MBOX0) & PCXHR_MBOX0_BOOT_HERE) { - /* no need to load the eeprom binary, but init the HI08 interface */ + /* no need to load the eeprom binary, + * but init the HI08 interface + */ PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg | PCXHR_ICR_HI08_INIT); msleep(PCXHR_WAIT_DEFAULT); PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg); @@ -429,8 +455,10 @@ int pcxhr_load_dsp_binary(struct pcxhr_mgr *mgr, const struct firmware *dsp) if (err) return err; /* wait for chk bit */ - return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_CHK, - PCXHR_ISR_HI08_CHK, PCXHR_TIMEOUT_DSP, &dummy); + return pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_CHK, + PCXHR_ISR_HI08_CHK, + PCXHR_TIMEOUT_DSP, &dummy); } @@ -443,8 +471,8 @@ struct pcxhr_cmd_info { /* RMH status type */ enum { RMH_SSIZE_FIXED = 0, /* status size fix (st_length = 0..x) */ - RMH_SSIZE_ARG = 1, /* status size given in the LSB byte (used with st_length = 1) */ - RMH_SSIZE_MASK = 2, /* status size given in bitmask (used with st_length = 1) */ + RMH_SSIZE_ARG = 1, /* status size given in the LSB byte */ + RMH_SSIZE_MASK = 2, /* status size given in bitmask */ }; /* @@ -474,7 +502,7 @@ static struct pcxhr_cmd_info pcxhr_dsp_cmds[] = { [CMD_UPDATE_R_BUFFERS] = { 0x840000, 0, RMH_SSIZE_FIXED }, [CMD_FORMAT_STREAM_OUT] = { 0x860000, 0, RMH_SSIZE_FIXED }, [CMD_FORMAT_STREAM_IN] = { 0x870000, 0, RMH_SSIZE_FIXED }, -[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, /* stat_len = nb_streams * 2 */ +[CMD_STREAM_SAMPLE_COUNT] = { 0x902000, 2, RMH_SSIZE_FIXED }, [CMD_AUDIO_LEVEL_ADJUST] = { 0xc22000, 0, RMH_SSIZE_FIXED }, }; @@ -524,10 +552,13 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) for (i = 0; i < rmh->stat_len; i++) { /* wait for receiver full */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF, - PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_RXDF, + PCXHR_ISR_HI08_RXDF, + PCXHR_TIMEOUT_DSP, ®); if (err) { - snd_printk(KERN_ERR "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n", + snd_printk(KERN_ERR "ERROR RMH stat: " + "ISR:RXDF=1 (ISR = %x; i=%d )\n", reg, i); return err; } @@ -537,10 +568,10 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); /* need to update rmh->stat_len on the fly ?? */ - if (i==0) { + if (!i) { if (rmh->dsp_stat != RMH_SSIZE_FIXED) { if (rmh->dsp_stat == RMH_SSIZE_ARG) { - rmh->stat_len = (u16)(data & 0x0000ff) + 1; + rmh->stat_len = (data & 0x0000ff) + 1; data &= 0xffff00; } else { /* rmh->dsp_stat == RMH_SSIZE_MASK */ @@ -562,7 +593,8 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) rmh->stat[i] = data; } if (rmh->stat_len > max_stat_len) { - snd_printdd("PCXHR : rmh->stat_len=%x too big\n", rmh->stat_len); + snd_printdd("PCXHR : rmh->stat_len=%x too big\n", + rmh->stat_len); rmh->stat_len = max_stat_len; } return 0; @@ -605,7 +637,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ #ifdef CONFIG_SND_DEBUG_VERBOSE if (rmh->cmd_idx < CMD_LAST_INDEX) - snd_printdd("MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); + snd_printdd("MSG cmd[0]=%x (%s)\n", + data, cmd_names[rmh->cmd_idx]); #endif err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, @@ -619,8 +652,10 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) if (rmh->cmd_len > 1) { /* send length */ data = rmh->cmd_len - 1; - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, - PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_TRDY, + PCXHR_ISR_HI08_TRDY, + PCXHR_TIMEOUT_DSP, ®); if (err) return err; PCXHR_OUTPB(mgr, PCXHR_DSP_TXH, (data>>16)&0xFF); @@ -653,8 +688,10 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) /* test status ISR */ if (reg & PCXHR_ISR_HI08_ERR) { /* ERROR, wait for receiver full */ - err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_RXDF, - PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); + err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, + PCXHR_ISR_HI08_RXDF, + PCXHR_ISR_HI08_RXDF, + PCXHR_TIMEOUT_DSP, ®); if (err) { snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg); return err; @@ -663,7 +700,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); - snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", rmh->cmd_idx, data); + snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", + rmh->cmd_idx, data); err = -EINVAL; } else { /* read the response data */ @@ -732,8 +770,9 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr) { int start_mask = PCXHR_INPL(mgr, PCXHR_PLX_MBOX2); - /* least segnificant 12 bits are the pipe states for the playback audios */ - /* next 12 bits are the pipe states for the capture audios + /* least segnificant 12 bits are the pipe states + * for the playback audios + * next 12 bits are the pipe states for the capture audios * (PCXHR_PIPE_STATE_CAPTURE_OFFSET) */ start_mask &= 0xffffff; @@ -744,7 +783,8 @@ static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr) #define PCXHR_PIPE_STATE_CAPTURE_OFFSET 12 #define MAX_WAIT_FOR_DSP 20 -static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int *retry) +static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, + int audio_mask, int *retry) { struct pcxhr_rmh rmh; int err; @@ -760,17 +800,20 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, int audio_mask, int * } else { /* can start capture pipe */ pcxhr_set_pipe_cmd_params(&rmh, 1, audio - - PCXHR_PIPE_STATE_CAPTURE_OFFSET, - 0, 0); + PCXHR_PIPE_STATE_CAPTURE_OFFSET, + 0, 0); } err = pcxhr_send_msg(mgr, &rmh); if (err) { snd_printk(KERN_ERR - "error pipe start (CMD_CAN_START_PIPE) err=%x!\n", + "error pipe start " + "(CMD_CAN_START_PIPE) err=%x!\n", err); return err; } - /* if the pipe couldn't be prepaired for start, retry it later */ + /* if the pipe couldn't be prepaired for start, + * retry it later + */ if (rmh.stat[0] == 0) *retry |= (1<= MAX_WAIT_FOR_DSP * 100) { - snd_printk(KERN_ERR "error pipe start/stop (ED_NO_RESPONSE_AT_IRQA)\n"); + snd_printk(KERN_ERR "error pipe start/stop\n"); return -EBUSY; } udelay(10); /* wait 10 microseconds */ @@ -918,7 +967,8 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, spin_lock_irqsave(&mgr->msg_lock, flags); if ((mgr->io_num_reg_cont & mask) == value) { - snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value); + snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", + mask, value); if (changed) *changed = 0; spin_unlock_irqrestore(&mgr->msg_lock, flags); @@ -971,7 +1021,8 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, err = ((err >> 12) & 0xfff); if (!err) return 0; - snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", err_src_name[err_src], + snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", + err_src_name[err_src], is_capture ? "Record" : "Play", pipe, err); if (err == 0xe01) mgr->async_err_stream_xrun++; @@ -996,6 +1047,13 @@ void pcxhr_msg_tasklet(unsigned long arg) snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occured\n"); if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY) snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occured\n"); + if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) { + /* clear events FREQ_CHANGE and TIME_CODE */ + pcxhr_init_rmh(prmh, CMD_TEST_IT); + err = pcxhr_send_msg(mgr, prmh); + snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n", + err, prmh->stat[0]); + } if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) { snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occured\n"); @@ -1005,18 +1063,22 @@ void pcxhr_msg_tasklet(unsigned long arg) prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS; err = pcxhr_send_msg(mgr, prmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", err); + snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", + err); i = 1; while (i < prmh->stat_len) { - int nb_audio = (prmh->stat[i] >> FIELD_SIZE) & MASK_FIRST_FIELD; - int nb_stream = (prmh->stat[i] >> (2*FIELD_SIZE)) & MASK_FIRST_FIELD; + int nb_audio = ((prmh->stat[i] >> FIELD_SIZE) & + MASK_FIRST_FIELD); + int nb_stream = ((prmh->stat[i] >> (2*FIELD_SIZE)) & + MASK_FIRST_FIELD); int pipe = prmh->stat[i] & MASK_FIRST_FIELD; int is_capture = prmh->stat[i] & 0x400000; u32 err2; if (prmh->stat[i] & 0x800000) { /* if BIT_END */ snd_printdd("TASKLET : End%sPipe %d\n", - is_capture ? "Record" : "Play", pipe); + is_capture ? "Record" : "Play", + pipe); } i++; err2 = prmh->stat[i] ? prmh->stat[i] : prmh->stat[i+1]; @@ -1062,7 +1124,7 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr, pcxhr_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT); pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture, stream->pipe->first_audio, 0, stream_mask); - /* rmh.stat_len = 2; */ /* 2 resp data for each stream of the pipe */ + /* rmh.stat_len = 2; */ /* 2 resp data for each stream of the pipe */ err = pcxhr_send_msg(mgr, &rmh); if (err) @@ -1072,18 +1134,21 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr, hw_sample_count += (u_int64_t)rmh.stat[1]; snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n", - stream->pipe->is_capture ? 'C':'P', stream->substream->number, + stream->pipe->is_capture ? 'C' : 'P', + stream->substream->number, (long unsigned int)hw_sample_count, (long unsigned int)(stream->timer_abs_periods + - stream->timer_period_frag + PCXHR_GRANULARITY)); - + stream->timer_period_frag + + mgr->granularity)); return hw_sample_count; } static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, - struct pcxhr_stream *stream, int samples_to_add) + struct pcxhr_stream *stream, + int samples_to_add) { - if (stream->substream && (stream->status == PCXHR_STREAM_STATUS_RUNNING)) { + if (stream->substream && + (stream->status == PCXHR_STREAM_STATUS_RUNNING)) { u_int64_t new_sample_count; int elapsed = 0; int hardware_read = 0; @@ -1092,20 +1157,22 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, if (samples_to_add < 0) { stream->timer_is_synced = 0; /* add default if no hardware_read possible */ - samples_to_add = PCXHR_GRANULARITY; + samples_to_add = mgr->granularity; } if (!stream->timer_is_synced) { - if (stream->timer_abs_periods != 0 || - stream->timer_period_frag + PCXHR_GRANULARITY >= - runtime->period_size) { - new_sample_count = pcxhr_stream_read_position(mgr, stream); + if ((stream->timer_abs_periods != 0) || + ((stream->timer_period_frag + samples_to_add) >= + runtime->period_size)) { + new_sample_count = + pcxhr_stream_read_position(mgr, stream); hardware_read = 1; - if (new_sample_count >= PCXHR_GRANULARITY_MIN) { - /* sub security offset because of jitter and - * finer granularity of dsp time (MBOX4) + if (new_sample_count >= mgr->granularity) { + /* sub security offset because of + * jitter and finer granularity of + * dsp time (MBOX4) */ - new_sample_count -= PCXHR_GRANULARITY_MIN; + new_sample_count -= mgr->granularity; stream->timer_is_synced = 1; } } @@ -1128,12 +1195,15 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, stream->timer_buf_periods = 0; stream->timer_abs_periods = new_elapse_pos; } - if (new_sample_count >= stream->timer_abs_periods) - stream->timer_period_frag = (u_int32_t)(new_sample_count - - stream->timer_abs_periods); - else - snd_printk(KERN_ERR "ERROR new_sample_count too small ??? %lx\n", + if (new_sample_count >= stream->timer_abs_periods) { + stream->timer_period_frag = + (u_int32_t)(new_sample_count - + stream->timer_abs_periods); + } else { + snd_printk(KERN_ERR + "ERROR new_sample_count too small ??? %ld\n", (long unsigned int)new_sample_count); + } if (elapsed) { spin_unlock(&mgr->lock); @@ -1143,7 +1213,6 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, } } - irqreturn_t pcxhr_interrupt(int irq, void *dev_id) { struct pcxhr_mgr *mgr = dev_id; @@ -1156,7 +1225,8 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS); if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) { spin_unlock(&mgr->lock); - return IRQ_NONE; /* this device did not cause the interrupt */ + /* this device did not cause the interrupt */ + return IRQ_NONE; } /* clear interrupt */ @@ -1167,10 +1237,12 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) if (reg & PCXHR_IRQ_TIMER) { int timer_toggle = reg & PCXHR_IRQ_TIMER; /* is a 24 bit counter */ - int dsp_time_new = PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; + int dsp_time_new = + PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK; int dsp_time_diff = dsp_time_new - mgr->dsp_time_last; - if (dsp_time_diff < 0 && mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID) { + if ((dsp_time_diff < 0) && + (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) { snd_printdd("ERROR DSP TIME old(%d) new(%d) -> " "resynchronize all streams\n", mgr->dsp_time_last, dsp_time_new); @@ -1178,40 +1250,49 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) } #ifdef CONFIG_SND_DEBUG_VERBOSE if (dsp_time_diff == 0) - snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); - else if (dsp_time_diff >= (2*PCXHR_GRANULARITY)) + snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", + dsp_time_new); + else if (dsp_time_diff >= (2*mgr->granularity)) snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n", - mgr->dsp_time_last, dsp_time_new - mgr->dsp_time_last); + mgr->dsp_time_last, + dsp_time_new - mgr->dsp_time_last); + else if (dsp_time_diff % mgr->granularity) + snd_printdd("ERROR DSP TIME increased by %d\n", + dsp_time_diff); #endif mgr->dsp_time_last = dsp_time_new; - if (timer_toggle == mgr->timer_toggle) + if (timer_toggle == mgr->timer_toggle) { snd_printdd("ERROR TIMER TOGGLE\n"); + mgr->dsp_time_err++; + } mgr->timer_toggle = timer_toggle; reg &= ~PCXHR_IRQ_TIMER; for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; for (j = 0; j < chip->nb_streams_capt; j++) - pcxhr_update_timer_pos(mgr, &chip->capture_stream[j], - dsp_time_diff); + pcxhr_update_timer_pos(mgr, + &chip->capture_stream[j], + dsp_time_diff); } for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; for (j = 0; j < chip->nb_streams_play; j++) - pcxhr_update_timer_pos(mgr, &chip->playback_stream[j], - dsp_time_diff); + pcxhr_update_timer_pos(mgr, + &chip->playback_stream[j], + dsp_time_diff); } } /* other irq's handled in the tasklet */ if (reg & PCXHR_IRQ_MASK) { - - /* as we didn't request any notifications, some kind of xrun error - * will probably occured - */ - /* better resynchronize all streams next interrupt : */ - mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; - + if (reg & PCXHR_IRQ_ASYNC) { + /* as we didn't request any async notifications, + * some kind of xrun error will probably occured + */ + /* better resynchronize all streams next interrupt : */ + mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; + } mgr->src_it_dsp = reg; tasklet_hi_schedule(&mgr->msg_taskq); } diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h index d9a4ab609875..bbbd66d13a64 100644 --- a/sound/pci/pcxhr/pcxhr_core.h +++ b/sound/pci/pcxhr/pcxhr_core.h @@ -65,7 +65,7 @@ enum { CMD_RESYNC_AUDIO_INPUTS, /* cmd_len = 1 stat_len = 0 */ CMD_GET_DSP_RESOURCES, /* cmd_len = 1 stat_len = 4 */ CMD_SET_TIMER_INTERRUPT, /* cmd_len = 1 stat_len = 0 */ - CMD_RES_PIPE, /* cmd_len = 2 stat_len = 0 */ + CMD_RES_PIPE, /* cmd_len >=2 stat_len = 0 */ CMD_FREE_PIPE, /* cmd_len = 1 stat_len = 0 */ CMD_CONF_PIPE, /* cmd_len = 2 stat_len = 0 */ CMD_STOP_PIPE, /* cmd_len = 1 stat_len = 0 */ @@ -96,6 +96,8 @@ void pcxhr_init_rmh(struct pcxhr_rmh *rmh, int cmd); void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh* rmh, int capture, unsigned int param1, unsigned int param2, unsigned int param3); +#define DSP_EXT_CMD_SET(x) (x->dsp_version > 0x012800) + /* send the rmh */ @@ -110,6 +112,7 @@ int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh); #define IO_NUM_REG_STATUS 5 #define IO_NUM_REG_CUER 10 #define IO_NUM_UER_CHIP_REG 11 +#define IO_NUM_REG_CONFIG_SRC 12 #define IO_NUM_REG_OUT_ANA_LEVEL 20 #define IO_NUM_REG_IN_ANA_LEVEL 21 From 9d948d270010e3552c94281bab75694580ca23e9 Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Tue, 25 Nov 2008 12:24:54 +0100 Subject: [PATCH 190/367] ALSA: pcxhr - add support for pcxhr stereo sound cards (core change) - Add support for pcxhr stereo cards - minor bugfixes : period and buffer size consraints - fix PLL register values - do some clean up Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr.c | 552 +++++++++++++++++++++++++++------------- sound/pci/pcxhr/pcxhr.h | 76 ++++-- 2 files changed, 433 insertions(+), 195 deletions(-) diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 73de6e989b3d..0327925828d1 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -40,18 +40,20 @@ #include "pcxhr_mixer.h" #include "pcxhr_hwdep.h" #include "pcxhr_core.h" +#include "pcxhr_mix22.h" #define DRIVER_NAME "pcxhr" -MODULE_AUTHOR("Markus Bollinger "); +MODULE_AUTHOR("Markus Bollinger , " + "Marc Titinger "); MODULE_DESCRIPTION("Digigram " DRIVER_NAME " " PCXHR_DRIVER_VERSION_STRING); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Digigram," DRIVER_NAME "}}"); -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int mono[SNDRV_CARDS]; /* capture in mono only */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ +static int mono[SNDRV_CARDS]; /* capture mono only */ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Digigram " DRIVER_NAME " soundcard"); @@ -67,18 +69,58 @@ enum { PCI_ID_PCX882HR, PCI_ID_VX881HR, PCI_ID_PCX881HR, + PCI_ID_VX882E, + PCI_ID_PCX882E, + PCI_ID_VX881E, + PCI_ID_PCX881E, + PCI_ID_VX1222HR, PCI_ID_PCX1222HR, + PCI_ID_VX1221HR, PCI_ID_PCX1221HR, + PCI_ID_VX1222E, + PCI_ID_PCX1222E, + PCI_ID_VX1221E, + PCI_ID_PCX1221E, + PCI_ID_VX222HR, + PCI_ID_VX222E, + PCI_ID_PCX22HR, + PCI_ID_PCX22E, + PCI_ID_VX222HRMIC, + PCI_ID_VX222E_MIC, + PCI_ID_PCX924HR, + PCI_ID_PCX924E, + PCI_ID_PCX924HRMIC, + PCI_ID_PCX924E_MIC, PCI_ID_LAST }; static struct pci_device_id pcxhr_ids[] = { - { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, /* VX882HR */ - { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, /* PCX882HR */ - { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, /* VX881HR */ - { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, }, /* PCX881HR */ - { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, /* PCX1222HR */ - { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, /* PCX1221HR */ + { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb301, 0, 0, PCI_ID_PCX881HR, }, + { 0x10b5, 0x9056, 0x1369, 0xb021, 0, 0, PCI_ID_VX882E, }, + { 0x10b5, 0x9056, 0x1369, 0xb121, 0, 0, PCI_ID_PCX882E, }, + { 0x10b5, 0x9056, 0x1369, 0xb221, 0, 0, PCI_ID_VX881E, }, + { 0x10b5, 0x9056, 0x1369, 0xb321, 0, 0, PCI_ID_PCX881E, }, + { 0x10b5, 0x9656, 0x1369, 0xb401, 0, 0, PCI_ID_VX1222HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb501, 0, 0, PCI_ID_PCX1222HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb601, 0, 0, PCI_ID_VX1221HR, }, + { 0x10b5, 0x9656, 0x1369, 0xb701, 0, 0, PCI_ID_PCX1221HR, }, + { 0x10b5, 0x9056, 0x1369, 0xb421, 0, 0, PCI_ID_VX1222E, }, + { 0x10b5, 0x9056, 0x1369, 0xb521, 0, 0, PCI_ID_PCX1222E, }, + { 0x10b5, 0x9056, 0x1369, 0xb621, 0, 0, PCI_ID_VX1221E, }, + { 0x10b5, 0x9056, 0x1369, 0xb721, 0, 0, PCI_ID_PCX1221E, }, + { 0x10b5, 0x9056, 0x1369, 0xba01, 0, 0, PCI_ID_VX222HR, }, + { 0x10b5, 0x9056, 0x1369, 0xba21, 0, 0, PCI_ID_VX222E, }, + { 0x10b5, 0x9056, 0x1369, 0xbd01, 0, 0, PCI_ID_PCX22HR, }, + { 0x10b5, 0x9056, 0x1369, 0xbd21, 0, 0, PCI_ID_PCX22E, }, + { 0x10b5, 0x9056, 0x1369, 0xbc01, 0, 0, PCI_ID_VX222HRMIC, }, + { 0x10b5, 0x9056, 0x1369, 0xbc21, 0, 0, PCI_ID_VX222E_MIC, }, + { 0x10b5, 0x9056, 0x1369, 0xbb01, 0, 0, PCI_ID_PCX924HR, }, + { 0x10b5, 0x9056, 0x1369, 0xbb21, 0, 0, PCI_ID_PCX924E, }, + { 0x10b5, 0x9056, 0x1369, 0xbf01, 0, 0, PCI_ID_PCX924HRMIC, }, + { 0x10b5, 0x9056, 0x1369, 0xbf21, 0, 0, PCI_ID_PCX924E_MIC, }, { 0, } }; @@ -88,27 +130,55 @@ struct board_parameters { char* board_name; short playback_chips; short capture_chips; + short fw_file_set; short firmware_num; }; static struct board_parameters pcxhr_board_params[] = { -[PCI_ID_VX882HR] = { "VX882HR", 4, 4, 41, }, -[PCI_ID_PCX882HR] = { "PCX882HR", 4, 4, 41, }, -[PCI_ID_VX881HR] = { "VX881HR", 4, 4, 41, }, -[PCI_ID_PCX881HR] = { "PCX881HR", 4, 4, 41, }, -[PCI_ID_PCX1222HR] = { "PCX1222HR", 6, 1, 42, }, -[PCI_ID_PCX1221HR] = { "PCX1221HR", 6, 1, 42, }, +[PCI_ID_VX882HR] = { "VX882HR", 4, 4, 0, 41 }, +[PCI_ID_PCX882HR] = { "PCX882HR", 4, 4, 0, 41 }, +[PCI_ID_VX881HR] = { "VX881HR", 4, 4, 0, 41 }, +[PCI_ID_PCX881HR] = { "PCX881HR", 4, 4, 0, 41 }, +[PCI_ID_VX882E] = { "VX882e", 4, 4, 1, 41 }, +[PCI_ID_PCX882E] = { "PCX882e", 4, 4, 1, 41 }, +[PCI_ID_VX881E] = { "VX881e", 4, 4, 1, 41 }, +[PCI_ID_PCX881E] = { "PCX881e", 4, 4, 1, 41 }, +[PCI_ID_VX1222HR] = { "VX1222HR", 6, 1, 2, 42 }, +[PCI_ID_PCX1222HR] = { "PCX1222HR", 6, 1, 2, 42 }, +[PCI_ID_VX1221HR] = { "VX1221HR", 6, 1, 2, 42 }, +[PCI_ID_PCX1221HR] = { "PCX1221HR", 6, 1, 2, 42 }, +[PCI_ID_VX1222E] = { "VX1222e", 6, 1, 3, 42 }, +[PCI_ID_PCX1222E] = { "PCX1222e", 6, 1, 3, 42 }, +[PCI_ID_VX1221E] = { "VX1221e", 6, 1, 3, 42 }, +[PCI_ID_PCX1221E] = { "PCX1221e", 6, 1, 3, 42 }, +[PCI_ID_VX222HR] = { "VX222HR", 1, 1, 4, 44 }, +[PCI_ID_VX222E] = { "VX222e", 1, 1, 4, 44 }, +[PCI_ID_PCX22HR] = { "PCX22HR", 1, 0, 4, 44 }, +[PCI_ID_PCX22E] = { "PCX22e", 1, 0, 4, 44 }, +[PCI_ID_VX222HRMIC] = { "VX222HR-Mic", 1, 1, 5, 44 }, +[PCI_ID_VX222E_MIC] = { "VX222e-Mic", 1, 1, 5, 44 }, +[PCI_ID_PCX924HR] = { "PCX924HR", 1, 1, 5, 44 }, +[PCI_ID_PCX924E] = { "PCX924e", 1, 1, 5, 44 }, +[PCI_ID_PCX924HRMIC] = { "PCX924HR-Mic", 1, 1, 5, 44 }, +[PCI_ID_PCX924E_MIC] = { "PCX924e-Mic", 1, 1, 5, 44 }, }; +/* boards without hw AES1 and SRC onboard are all using fw_file_set==4 */ +/* VX222HR, VX222e, PCX22HR and PCX22e */ +#define PCXHR_BOARD_HAS_AES1(x) (x->fw_file_set != 4) +/* some boards do not support 192kHz on digital AES input plugs */ +#define PCXHR_BOARD_AESIN_NO_192K(x) ((x->capture_chips == 0) || \ + (x->fw_file_set == 0) || \ + (x->fw_file_set == 2)) static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, unsigned int* realfreq) { unsigned int reg; - if (freq < 6900 || freq > 110250) + if (freq < 6900 || freq > 110000) return -EINVAL; - reg = (28224000 * 10) / freq; - reg = (reg + 5) / 10; + reg = (28224000 * 2) / freq; + reg = (reg - 1) / 2; if (reg < 0x200) *pllreg = reg + 0x800; else if (reg < 0x400) @@ -121,7 +191,7 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, reg &= ~3; } if (realfreq) - *realfreq = ((28224000 * 10) / reg + 5) / 10; + *realfreq = (28224000 / (reg + 1)); return 0; } @@ -151,11 +221,6 @@ static int pcxhr_pll_freq_register(unsigned int freq, unsigned int* pllreg, #define PCXHR_FREQ_AES_3 0x03 #define PCXHR_FREQ_AES_4 0x0d -#define PCXHR_MODIFY_CLOCK_S_BIT 0x04 - -#define PCXHR_IRQ_TIMER_FREQ 92000 -#define PCXHR_IRQ_TIMER_PERIOD 48 - static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, unsigned int *reg, unsigned int *freq) { @@ -196,19 +261,32 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { snd_printk(KERN_ERR - "error CMD_ACCESS_IO_WRITE for PLL register : %x!\n", - err ); + "error CMD_ACCESS_IO_WRITE " + "for PLL register : %x!\n", err); return err; } } break; - case PCXHR_CLOCK_TYPE_WORD_CLOCK : val = PCXHR_FREQ_WORD_CLOCK; break; - case PCXHR_CLOCK_TYPE_AES_SYNC : val = PCXHR_FREQ_SYNC_AES; break; - case PCXHR_CLOCK_TYPE_AES_1 : val = PCXHR_FREQ_AES_1; break; - case PCXHR_CLOCK_TYPE_AES_2 : val = PCXHR_FREQ_AES_2; break; - case PCXHR_CLOCK_TYPE_AES_3 : val = PCXHR_FREQ_AES_3; break; - case PCXHR_CLOCK_TYPE_AES_4 : val = PCXHR_FREQ_AES_4; break; - default : return -EINVAL; + case PCXHR_CLOCK_TYPE_WORD_CLOCK: + val = PCXHR_FREQ_WORD_CLOCK; + break; + case PCXHR_CLOCK_TYPE_AES_SYNC: + val = PCXHR_FREQ_SYNC_AES; + break; + case PCXHR_CLOCK_TYPE_AES_1: + val = PCXHR_FREQ_AES_1; + break; + case PCXHR_CLOCK_TYPE_AES_2: + val = PCXHR_FREQ_AES_2; + break; + case PCXHR_CLOCK_TYPE_AES_3: + val = PCXHR_FREQ_AES_3; + break; + case PCXHR_CLOCK_TYPE_AES_4: + val = PCXHR_FREQ_AES_4; + break; + default: + return -EINVAL; } *reg = val; *freq = realfreq; @@ -216,14 +294,13 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, } -int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) +static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr, + unsigned int rate, + int *changed) { unsigned int val, realfreq, speed; struct pcxhr_rmh rmh; - int err, changed; - - if (rate == 0) - return 0; /* nothing to do */ + int err; err = pcxhr_get_clock_reg(mgr, rate, &val, &realfreq); if (err) @@ -237,13 +314,17 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) else speed = 2; /* quad speed */ if (mgr->codec_speed != speed) { - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* mute outputs */ rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; + if (DSP_EXT_CMD_SET(mgr)) { + rmh.cmd[1] = 1; + rmh.cmd_len = 2; + } err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set speed ratio */ rmh.cmd[0] |= IO_NUM_SPEED_RATIO; rmh.cmd[1] = speed; rmh.cmd_len = 2; @@ -253,25 +334,57 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) } /* set the new frequency */ snd_printdd("clock register : set %x\n", val); - err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, val, &changed); + err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, + val, changed); if (err) return err; + mgr->sample_rate_real = realfreq; mgr->cur_clock_type = mgr->use_clock_type; /* unmute after codec speed modes */ if (mgr->codec_speed != speed) { - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* unmute outputs */ rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; + if (DSP_EXT_CMD_SET(mgr)) { + rmh.cmd[1] = 1; + rmh.cmd_len = 2; + } err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - mgr->codec_speed = speed; /* save new codec speed */ + mgr->codec_speed = speed; /* save new codec speed */ } + snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n", + rate, realfreq); + return 0; +} + +#define PCXHR_MODIFY_CLOCK_S_BIT 0x04 + +#define PCXHR_IRQ_TIMER_FREQ 92000 +#define PCXHR_IRQ_TIMER_PERIOD 48 + +int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) +{ + struct pcxhr_rmh rmh; + int err, changed; + + if (rate == 0) + return 0; /* nothing to do */ + + if (mgr->is_hr_stereo) + err = hr222_sub_set_clock(mgr, rate, &changed); + else + err = pcxhr_sub_set_clock(mgr, rate, &changed); + + if (err) + return err; + if (changed) { pcxhr_init_rmh(&rmh, CMD_MODIFY_CLOCK); - rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos */ + rmh.cmd[0] |= PCXHR_MODIFY_CLOCK_S_BIT; /* resync fifos */ if (rate < PCXHR_IRQ_TIMER_FREQ) rmh.cmd[1] = PCXHR_IRQ_TIMER_PERIOD; else @@ -282,26 +395,39 @@ int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate) if (err) return err; } - snd_printdd("pcxhr_set_clock to %dHz (realfreq=%d)\n", rate, realfreq); return 0; } -int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, - int *sample_rate) +static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate) { struct pcxhr_rmh rmh; unsigned char reg; int err, rate; switch (clock_type) { - case PCXHR_CLOCK_TYPE_WORD_CLOCK : reg = REG_STATUS_WORD_CLOCK; break; - case PCXHR_CLOCK_TYPE_AES_SYNC : reg = REG_STATUS_AES_SYNC; break; - case PCXHR_CLOCK_TYPE_AES_1 : reg = REG_STATUS_AES_1; break; - case PCXHR_CLOCK_TYPE_AES_2 : reg = REG_STATUS_AES_2; break; - case PCXHR_CLOCK_TYPE_AES_3 : reg = REG_STATUS_AES_3; break; - case PCXHR_CLOCK_TYPE_AES_4 : reg = REG_STATUS_AES_4; break; - default : return -EINVAL; + case PCXHR_CLOCK_TYPE_WORD_CLOCK: + reg = REG_STATUS_WORD_CLOCK; + break; + case PCXHR_CLOCK_TYPE_AES_SYNC: + reg = REG_STATUS_AES_SYNC; + break; + case PCXHR_CLOCK_TYPE_AES_1: + reg = REG_STATUS_AES_1; + break; + case PCXHR_CLOCK_TYPE_AES_2: + reg = REG_STATUS_AES_2; + break; + case PCXHR_CLOCK_TYPE_AES_3: + reg = REG_STATUS_AES_3; + break; + case PCXHR_CLOCK_TYPE_AES_4: + reg = REG_STATUS_AES_4; + break; + default: + return -EINVAL; } pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd_len = 2; @@ -311,7 +437,7 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_ err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - udelay(100); /* wait minimum 2 sample_frames at 32kHz ! */ + udelay(100); /* wait minimum 2 sample_frames at 32kHz ! */ mgr->last_reg_stat = reg; } rmh.cmd[1] = REG_STATUS_CURRENT; @@ -336,6 +462,18 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_ } +int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate) +{ + if (mgr->is_hr_stereo) + return hr222_get_external_clock(mgr, clock_type, + sample_rate); + else + return pcxhr_sub_get_external_clock(mgr, clock_type, + sample_rate); +} + /* * start or stop playback/capture substream */ @@ -350,7 +488,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) start = 1; else { if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) { - snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state CANNOT be stopped\n"); + snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state " + "CANNOT be stopped\n"); return -EINVAL; } start = 0; @@ -359,11 +498,12 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) return -EINVAL; stream->timer_abs_periods = 0; - stream->timer_period_frag = 0; /* reset theoretical stream pos */ + stream->timer_period_frag = 0; /* reset theoretical stream pos */ stream->timer_buf_periods = 0; stream->timer_is_synced = 0; - stream_mask = stream->pipe->is_capture ? 1 : 1<substream->number; + stream_mask = + stream->pipe->is_capture ? 1 : 1<substream->number; pcxhr_init_rmh(&rmh, start ? CMD_START_STREAM : CMD_STOP_STREAM); pcxhr_set_pipe_cmd_params(&rmh, stream->pipe->is_capture, @@ -373,8 +513,10 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", err); - stream->status = start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED; + snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", + err); + stream->status = + start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED; return err; } @@ -399,13 +541,15 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) header = HEADER_FMT_BASE_LIN; break; case SNDRV_PCM_FORMAT_S16_LE: - header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS | HEADER_FMT_INTEL; + header = HEADER_FMT_BASE_LIN | + HEADER_FMT_16BITS | HEADER_FMT_INTEL; break; case SNDRV_PCM_FORMAT_S16_BE: header = HEADER_FMT_BASE_LIN | HEADER_FMT_16BITS; break; case SNDRV_PCM_FORMAT_S24_3LE: - header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS | HEADER_FMT_INTEL; + header = HEADER_FMT_BASE_LIN | + HEADER_FMT_24BITS | HEADER_FMT_INTEL; break; case SNDRV_PCM_FORMAT_S24_3BE: header = HEADER_FMT_BASE_LIN | HEADER_FMT_24BITS; @@ -414,7 +558,8 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL; break; default: - snd_printk(KERN_ERR "error pcxhr_set_format() : unknown format\n"); + snd_printk(KERN_ERR + "error pcxhr_set_format() : unknown format\n"); return -EINVAL; } chip = snd_pcm_substream_chip(stream->substream); @@ -432,14 +577,31 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) is_capture = stream->pipe->is_capture; stream_num = is_capture ? 0 : stream->substream->number; - pcxhr_init_rmh(&rmh, is_capture ? CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0); - if (is_capture) - rmh.cmd[0] |= 1<<12; + pcxhr_init_rmh(&rmh, is_capture ? + CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT); + pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, + stream_num, 0); + if (is_capture) { + /* bug with old dsp versions: */ + /* bit 12 also sets the format of the playback stream */ + if (DSP_EXT_CMD_SET(chip->mgr)) + rmh.cmd[0] |= 1<<10; + else + rmh.cmd[0] |= 1<<12; + } rmh.cmd[1] = 0; - rmh.cmd[2] = header >> 8; - rmh.cmd[3] = (header & 0xff) << 16; - rmh.cmd_len = 4; + rmh.cmd_len = 2; + if (DSP_EXT_CMD_SET(chip->mgr)) { + /* add channels and set bit 19 if channels>2 */ + rmh.cmd[1] = stream->channels; + if (!is_capture) { + /* playback : add channel mask to command */ + rmh.cmd[2] = (stream->channels == 1) ? 0x01 : 0x03; + rmh.cmd_len = 3; + } + } + rmh.cmd[rmh.cmd_len++] = header >> 8; + rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err); @@ -456,30 +618,38 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream) is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE); stream_num = is_capture ? 0 : subs->number; - snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n", + snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : " + "addr(%p) bytes(%zx) subs(%d)\n", is_capture ? 'c' : 'p', chip->chip_idx, (void *)(long)subs->runtime->dma_addr, subs->runtime->dma_bytes, subs->number); pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, stream_num, 0); + pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio, + stream_num, 0); /* max buffer size is 2 MByte */ snd_BUG_ON(subs->runtime->dma_bytes >= 0x200000); - rmh.cmd[1] = subs->runtime->dma_bytes * 8; /* size in bits */ - rmh.cmd[2] = subs->runtime->dma_addr >> 24; /* most significant byte */ - rmh.cmd[2] |= 1<<19; /* this is a circular buffer */ - rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD; /* least 3 significant bytes */ + /* size in bits */ + rmh.cmd[1] = subs->runtime->dma_bytes * 8; + /* most significant byte */ + rmh.cmd[2] = subs->runtime->dma_addr >> 24; + /* this is a circular buffer */ + rmh.cmd[2] |= 1<<19; + /* least 3 significant bytes */ + rmh.cmd[3] = subs->runtime->dma_addr & MASK_DSP_WORD; rmh.cmd_len = 4; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err); + snd_printk(KERN_ERR + "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err); return err; } #if 0 -static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, snd_pcm_uframes_t *sample_count) +static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream, + snd_pcm_uframes_t *sample_count) { struct pcxhr_rmh rmh; int err; @@ -533,8 +703,8 @@ static void pcxhr_trigger_tasklet(unsigned long arg) for (j = 0; j < chip->nb_streams_play; j++) { if (pcxhr_stream_scheduled_get_pipe(&chip->playback_stream[j], &pipe)) { playback_mask |= (1 << pipe->first_audio); - break; /* add only once, as all playback streams of - * one chip use the same pipe + break; /* add only once, as all playback + * streams of one chip use the same pipe */ } } @@ -545,19 +715,21 @@ static void pcxhr_trigger_tasklet(unsigned long arg) return; } - snd_printdd("pcxhr_trigger_tasklet : playback_mask=%x capture_mask=%x\n", + snd_printdd("pcxhr_trigger_tasklet : " + "playback_mask=%x capture_mask=%x\n", playback_mask, capture_mask); /* synchronous stop of all the pipes concerned */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n", + snd_printk(KERN_ERR "pcxhr_trigger_tasklet : " + "error stop pipes (P%x C%x)\n", playback_mask, capture_mask); return; } - /* unfortunately the dsp lost format and buffer info with the stop pipe */ + /* the dsp lost format and buffer info with the stop pipe */ for (i = 0; i < mgr->num_cards; i++) { struct pcxhr_stream *stream; chip = mgr->chip[i]; @@ -596,12 +768,15 @@ static void pcxhr_trigger_tasklet(unsigned long arg) err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); if (err) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n", + snd_printk(KERN_ERR "pcxhr_trigger_tasklet : " + "error start pipes (P%x C%x)\n", playback_mask, capture_mask); return; } - /* put the streams into the running state now (increment pointer by interrupt) */ + /* put the streams into the running state now + * (increment pointer by interrupt) + */ spin_lock_irqsave(&mgr->lock, flags); for ( i =0; i < mgr->num_cards; i++) { struct pcxhr_stream *stream; @@ -615,7 +790,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) stream = &chip->playback_stream[j]; if (stream->status == PCXHR_STREAM_STATUS_STARTED) { /* playback will already have advanced ! */ - stream->timer_period_frag += PCXHR_GRANULARITY; + stream->timer_period_frag += mgr->granularity; stream->status = PCXHR_STREAM_STATUS_RUNNING; } } @@ -697,12 +872,14 @@ static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start) pcxhr_init_rmh(&rmh, CMD_SET_TIMER_INTERRUPT); if (start) { - mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; /* last dsp time invalid */ - rmh.cmd[0] |= PCXHR_GRANULARITY; + /* last dsp time invalid */ + mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; + rmh.cmd[0] |= mgr->granularity; } err = pcxhr_send_msg(mgr, &rmh); if (err < 0) - snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", err); + snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", + err); return err; } @@ -713,38 +890,16 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs) { struct snd_pcxhr *chip = snd_pcm_substream_chip(subs); struct pcxhr_mgr *mgr = chip->mgr; - /* - struct pcxhr_stream *stream = (pcxhr_stream_t*)subs->runtime->private_data; - */ int err = 0; snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n", subs->runtime->period_size, subs->runtime->periods, subs->runtime->buffer_size); - /* - if(subs->runtime->period_size <= PCXHR_GRANULARITY) { - snd_printk(KERN_ERR "pcxhr_prepare : error period_size too small (%x)\n", - (unsigned int)subs->runtime->period_size); - return -EINVAL; - } - */ - mutex_lock(&mgr->setup_mutex); do { - /* if the stream was stopped before, format and buffer were reset */ - /* - if(stream->status == PCXHR_STREAM_STATUS_STOPPED) { - err = pcxhr_set_format(stream); - if(err) break; - err = pcxhr_update_r_buffer(stream); - if(err) break; - } - */ - /* only the first stream can choose the sample rate */ - /* the further opened streams will be limited to its frequency (see open) */ /* set the clock only once (first stream) */ if (mgr->sample_rate != subs->runtime->rate) { err = pcxhr_set_clock(mgr, subs->runtime->rate); @@ -787,22 +942,9 @@ static int pcxhr_hw_params(struct snd_pcm_substream *subs, stream->channels = channels; stream->format = format; - /* set the format to the board */ - /* - err = pcxhr_set_format(stream); - if(err) { - mutex_unlock(&mgr->setup_mutex); - return err; - } - */ /* allocate buffer */ err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw)); - /* - if (err > 0) { - err = pcxhr_update_r_buffer(stream); - } - */ mutex_unlock(&mgr->setup_mutex); return err; @@ -820,14 +962,18 @@ static int pcxhr_hw_free(struct snd_pcm_substream *subs) */ static struct snd_pcm_hardware pcxhr_caps = { - .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | - 0 /*SNDRV_PCM_INFO_PAUSE*/), - .formats = ( SNDRV_PCM_FMTBIT_U8 | - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | - SNDRV_PCM_FMTBIT_FLOAT_LE ), - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START), + .formats = (SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S24_3BE | + SNDRV_PCM_FMTBIT_FLOAT_LE), + .rates = (SNDRV_PCM_RATE_CONTINUOUS | + SNDRV_PCM_RATE_8000_192000), .rate_min = 8000, .rate_max = 192000, .channels_min = 1, @@ -847,6 +993,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) struct pcxhr_mgr *mgr = chip->mgr; struct snd_pcm_runtime *runtime = subs->runtime; struct pcxhr_stream *stream; + int err; mutex_lock(&mgr->setup_mutex); @@ -874,6 +1021,18 @@ static int pcxhr_open(struct snd_pcm_substream *subs) return -EBUSY; } + /* float format support is in some cases buggy on stereo cards */ + if (mgr->is_hr_stereo) + runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_FLOAT_LE; + + /* buffer-size should better be multiple of period-size */ + err = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) { + mutex_unlock(&mgr->setup_mutex); + return err; + } + /* if a sample rate is already used or fixed by external clock, * the stream cannot change */ @@ -889,7 +1048,8 @@ static int pcxhr_open(struct snd_pcm_substream *subs) mutex_unlock(&mgr->setup_mutex); return -EBUSY; } - runtime->hw.rate_min = runtime->hw.rate_max = external_rate; + runtime->hw.rate_min = external_rate; + runtime->hw.rate_max = external_rate; } } @@ -899,9 +1059,11 @@ static int pcxhr_open(struct snd_pcm_substream *subs) runtime->private_data = stream; - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); - + /* better get a divisor of granularity values (96 or 192) */ + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); snd_pcm_set_sync(subs); mgr->ref_count_rate++; @@ -919,11 +1081,12 @@ static int pcxhr_close(struct snd_pcm_substream *subs) mutex_lock(&mgr->setup_mutex); - snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number); + snd_printdd("pcxhr_close chip%d subs%d\n", + chip->chip_idx, subs->number); /* sample rate released */ if (--mgr->ref_count_rate == 0) { - mgr->sample_rate = 0; /* the sample rate is no more locked */ + mgr->sample_rate = 0; /* the sample rate is no more locked */ pcxhr_hardware_timer(mgr, 0); /* stop the DSP-timer */ } @@ -1016,7 +1179,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 __devinit pcxhr_create(struct pcxhr_mgr *mgr, + struct snd_card *card, int idx) { int err; struct snd_pcxhr *chip; @@ -1040,7 +1204,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, if (idx < mgr->capture_chips) { if (mgr->mono_capture) - chip->nb_streams_capt = 2; /* 2 mono streams (left+right) */ + chip->nb_streams_capt = 2; /* 2 mono streams */ else chip->nb_streams_capt = 1; /* or 1 stereo stream */ } @@ -1056,7 +1220,8 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, } /* proc interface */ -static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +static void pcxhr_proc_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct snd_pcxhr *chip = entry->private_data; struct pcxhr_mgr *mgr = chip->mgr; @@ -1069,8 +1234,10 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer short ver_maj = (mgr->dsp_version >> 16) & 0xff; short ver_min = (mgr->dsp_version >> 8) & 0xff; short ver_build = mgr->dsp_version & 0xff; - snd_iprintf(buffer, "module version %s\n", PCXHR_DRIVER_VERSION_STRING); - snd_iprintf(buffer, "dsp version %d.%d.%d\n", ver_maj, ver_min, ver_build); + snd_iprintf(buffer, "module version %s\n", + PCXHR_DRIVER_VERSION_STRING); + snd_iprintf(buffer, "dsp version %d.%d.%d\n", + ver_maj, ver_min, ver_build); if (mgr->board_has_analog) snd_iprintf(buffer, "analog io available\n"); else @@ -1084,18 +1251,22 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer if (ref > 0) { if (mgr->sample_rate_real != 0 && mgr->sample_rate_real != 48000) { - ref = (ref * 48000) / mgr->sample_rate_real; - if (mgr->sample_rate_real >= PCXHR_IRQ_TIMER_FREQ) + ref = (ref * 48000) / + mgr->sample_rate_real; + if (mgr->sample_rate_real >= + PCXHR_IRQ_TIMER_FREQ) ref *= 2; } cur = 100 - (100 * cur) / ref; snd_iprintf(buffer, "cpu load %d%%\n", cur); - snd_iprintf(buffer, "buffer pool %d/%d kWords\n", + snd_iprintf(buffer, "buffer pool %d/%d\n", rmh.stat[2], rmh.stat[3]); } } - snd_iprintf(buffer, "dma granularity : %d\n", PCXHR_GRANULARITY); - snd_iprintf(buffer, "dsp time errors : %d\n", mgr->dsp_time_err); + snd_iprintf(buffer, "dma granularity : %d\n", + mgr->granularity); + snd_iprintf(buffer, "dsp time errors : %d\n", + mgr->dsp_time_err); snd_iprintf(buffer, "dsp async pipe xrun errors : %d\n", mgr->async_err_pipe_xrun); snd_iprintf(buffer, "dsp async stream xrun errors : %d\n", @@ -1110,33 +1281,52 @@ static void pcxhr_proc_info(struct snd_info_entry *entry, struct snd_info_buffer rmh.cmd_idx = CMD_LAST_INDEX; if( ! pcxhr_send_msg(mgr, &rmh) ) { int i; + if (rmh.stat_len > 8) + rmh.stat_len = 8; for (i = 0; i < rmh.stat_len; i++) - snd_iprintf(buffer, "debug[%02d] = %06x\n", i, rmh.stat[i]); + snd_iprintf(buffer, "debug[%02d] = %06x\n", + i, rmh.stat[i]); } } else snd_iprintf(buffer, "no firmware loaded\n"); snd_iprintf(buffer, "\n"); } -static void pcxhr_proc_sync(struct snd_info_entry *entry, struct snd_info_buffer *buffer) +static void pcxhr_proc_sync(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct snd_pcxhr *chip = entry->private_data; struct pcxhr_mgr *mgr = chip->mgr; - static char *texts[7] = { - "Internal", "Word", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" + static const char *textsHR22[3] = { + "Internal", "AES Sync", "AES 1" }; + static const char *textsPCXHR[7] = { + "Internal", "Word", "AES Sync", + "AES 1", "AES 2", "AES 3", "AES 4" + }; + const char **texts; + int max_clock; + if (mgr->is_hr_stereo) { + texts = textsHR22; + max_clock = HR22_CLOCK_TYPE_MAX; + } else { + texts = textsPCXHR; + max_clock = PCXHR_CLOCK_TYPE_MAX; + } snd_iprintf(buffer, "\n%s\n", mgr->longname); - snd_iprintf(buffer, "Current Sample Clock\t: %s\n", texts[mgr->cur_clock_type]); - snd_iprintf(buffer, "Current Sample Rate\t= %d\n", mgr->sample_rate_real); - + snd_iprintf(buffer, "Current Sample Clock\t: %s\n", + texts[mgr->cur_clock_type]); + snd_iprintf(buffer, "Current Sample Rate\t= %d\n", + mgr->sample_rate_real); /* commands available when embedded DSP is running */ if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { int i, err, sample_rate; - for (i = PCXHR_CLOCK_TYPE_WORD_CLOCK; i< (3 + mgr->capture_chips); i++) { + for (i = 1; i <= max_clock; i++) { err = pcxhr_get_external_clock(mgr, i, &sample_rate); if (err) break; - snd_iprintf(buffer, "%s Clock\t\t= %d\n", texts[i], sample_rate); + snd_iprintf(buffer, "%s Clock\t\t= %d\n", + texts[i], sample_rate); } } else snd_iprintf(buffer, "no firmware loaded\n"); @@ -1194,7 +1384,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 __devinit pcxhr_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct pcxhr_mgr *mgr; @@ -1217,7 +1408,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id /* check if we can restrict PCI DMA transfers to 32 bits */ if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) { - snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); + snd_printk(KERN_ERR "architecture does not support " + "32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1234,11 +1426,25 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id pci_disable_device(pci); return -ENODEV; } - card_name = pcxhr_board_params[pci_id->driver_data].board_name; - mgr->playback_chips = pcxhr_board_params[pci_id->driver_data].playback_chips; - mgr->capture_chips = pcxhr_board_params[pci_id->driver_data].capture_chips; - mgr->firmware_num = pcxhr_board_params[pci_id->driver_data].firmware_num; + card_name = + pcxhr_board_params[pci_id->driver_data].board_name; + mgr->playback_chips = + pcxhr_board_params[pci_id->driver_data].playback_chips; + mgr->capture_chips = + pcxhr_board_params[pci_id->driver_data].capture_chips; + mgr->fw_file_set = + pcxhr_board_params[pci_id->driver_data].fw_file_set; + mgr->firmware_num = + pcxhr_board_params[pci_id->driver_data].firmware_num; mgr->mono_capture = mono[dev]; + mgr->is_hr_stereo = (mgr->playback_chips == 1); + mgr->board_has_aes1 = PCXHR_BOARD_HAS_AES1(mgr); + mgr->board_aes_in_192k = !PCXHR_BOARD_AESIN_NO_192K(mgr); + + if (mgr->is_hr_stereo) + mgr->granularity = PCXHR_GRANULARITY_HR22; + else + mgr->granularity = PCXHR_GRANULARITY; /* resource assignment */ if ((err = pci_request_regions(pci, card_name)) < 0) { @@ -1261,7 +1467,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id mgr->irq = pci->irq; sprintf(mgr->shortname, "Digigram %s", card_name); - sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", mgr->shortname, + sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, 0x%lx irq %i", + mgr->shortname, mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq); /* ISR spinlock */ @@ -1272,10 +1479,14 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id mutex_init(&mgr->setup_mutex); /* init taslket */ - tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr); - tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, (unsigned long) mgr); + tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, + (unsigned long) mgr); + tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet, + (unsigned long) mgr); + mgr->prmh = kmalloc(sizeof(*mgr->prmh) + - sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - PCXHR_SIZE_MAX_STATUS), + sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS - + PCXHR_SIZE_MAX_STATUS), GFP_KERNEL); if (! mgr->prmh) { pcxhr_free(mgr); @@ -1296,7 +1507,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id else idx = index[dev] + i; - snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : card_name, i); + snprintf(tmpid, sizeof(tmpid), "%s-%d", + id[dev] ? id[dev] : card_name, i); card = snd_card_new(idx, tmpid, THIS_MODULE, 0); if (! card) { diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h index 652064787a55..84131a916c92 100644 --- a/sound/pci/pcxhr/pcxhr.h +++ b/sound/pci/pcxhr/pcxhr.h @@ -27,15 +27,18 @@ #include #include -#define PCXHR_DRIVER_VERSION 0x000804 /* 0.8.4 */ -#define PCXHR_DRIVER_VERSION_STRING "0.8.4" /* 0.8.4 */ +#define PCXHR_DRIVER_VERSION 0x000905 /* 0.9.5 */ +#define PCXHR_DRIVER_VERSION_STRING "0.9.5" /* 0.9.5 */ -#define PCXHR_MAX_CARDS 6 -#define PCXHR_PLAYBACK_STREAMS 4 +#define PCXHR_MAX_CARDS 6 +#define PCXHR_PLAYBACK_STREAMS 4 -#define PCXHR_GRANULARITY 96 /* transfer granularity (should be min 96 and multiple of 48) */ -#define PCXHR_GRANULARITY_MIN 96 /* transfer granularity of pipes and the dsp time (MBOX4) */ +#define PCXHR_GRANULARITY 96 /* min 96 and multiple of 48 */ +/* transfer granularity of pipes and the dsp time (MBOX4) */ +#define PCXHR_GRANULARITY_MIN 96 +/* TODO : granularity could be 64 or 128 */ +#define PCXHR_GRANULARITY_HR22 192 /* granularity for stereo cards */ struct snd_pcxhr; struct pcxhr_mgr; @@ -51,6 +54,11 @@ enum pcxhr_clock_type { PCXHR_CLOCK_TYPE_AES_2, PCXHR_CLOCK_TYPE_AES_3, PCXHR_CLOCK_TYPE_AES_4, + PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, + HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, + HR22_CLOCK_TYPE_AES_SYNC, + HR22_CLOCK_TYPE_AES_1, + HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, }; struct pcxhr_mgr { @@ -61,6 +69,8 @@ struct pcxhr_mgr { int irq; + int granularity; + /* card access with 1 mem bar and 2 io bar's */ unsigned long port[3]; @@ -83,11 +93,16 @@ struct pcxhr_mgr { /* hardware interface */ unsigned int dsp_loaded; /* bit flags of loaded dsp indices */ unsigned int dsp_version; /* read from embedded once firmware is loaded */ - int board_has_analog; /* if 0 the board is digital only */ - int mono_capture; /* if 1 the board does mono capture */ - int playback_chips; /* 4 or 6 */ - int capture_chips; /* 4 or 1 */ - int firmware_num; /* 41 or 42 */ + int playback_chips; + int capture_chips; + int fw_file_set; + int firmware_num; + int is_hr_stereo:1; + int board_has_aes1:1; /* if 1 board has AES1 plug and SRC */ + int board_has_analog:1; /* if 0 the board is digital only */ + int board_has_mic:1; /* if 1 the board has microphone input */ + int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */ + int mono_capture:1; /* if 1 the board does mono capture */ struct snd_dma_buffer hostport; @@ -106,6 +121,9 @@ struct pcxhr_mgr { int async_err_stream_xrun; int async_err_pipe_xrun; int async_err_other_last; + + unsigned char xlx_cfg; /* copy of PCXHR_XLX_CFG register */ + unsigned char xlx_selmic; /* copy of PCXHR_XLX_SELMIC register */ }; @@ -155,24 +173,30 @@ struct snd_pcxhr { struct snd_pcm *pcm; /* PCM */ - struct pcxhr_pipe playback_pipe; /* 1 stereo pipe only */ - struct pcxhr_pipe capture_pipe[2]; /* 1 stereo pipe or 2 mono pipes */ + struct pcxhr_pipe playback_pipe; /* 1 stereo pipe only */ + struct pcxhr_pipe capture_pipe[2]; /* 1 stereo or 2 mono pipes */ struct pcxhr_stream playback_stream[PCXHR_PLAYBACK_STREAMS]; - struct pcxhr_stream capture_stream[2]; /* 1 stereo stream or 2 mono streams */ + struct pcxhr_stream capture_stream[2]; /* 1 stereo or 2 mono streams */ int nb_streams_play; int nb_streams_capt; - int analog_playback_active[2]; /* Mixer : Master Playback active (!mute) */ - int analog_playback_volume[2]; /* Mixer : Master Playback Volume */ - int analog_capture_volume[2]; /* Mixer : Master Capture Volume */ - int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [streams][stereo]*/ - int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [streams][stereo]*/ - int digital_capture_volume[2]; /* Mixer : Digital Capture Volume [stereo] */ - int monitoring_active[2]; /* Mixer : Monitoring Active */ - int monitoring_volume[2]; /* Mixer : Monitoring Volume */ - int audio_capture_source; /* Mixer : Audio Capture Source */ - unsigned char aes_bits[5]; /* Mixer : IEC958_AES bits */ + int analog_playback_active[2]; /* Mixer : Master Playback !mute */ + int analog_playback_volume[2]; /* Mixer : Master Playback Volume */ + int analog_capture_volume[2]; /* Mixer : Master Capture Volume */ + int digital_playback_active[PCXHR_PLAYBACK_STREAMS][2]; + int digital_playback_volume[PCXHR_PLAYBACK_STREAMS][2]; + int digital_capture_volume[2]; /* Mixer : Digital Capture Volume */ + int monitoring_active[2]; /* Mixer : Monitoring Active */ + int monitoring_volume[2]; /* Mixer : Monitoring Volume */ + int audio_capture_source; /* Mixer : Audio Capture Source */ + int mic_volume; /* used by cards with MIC only */ + int mic_boost; /* used by cards with MIC only */ + int mic_active; /* used by cards with MIC only */ + int analog_capture_active; /* used by cards with MIC only */ + int phantom_power; /* used by cards with MIC only */ + + unsigned char aes_bits[5]; /* Mixer : IEC958_AES bits */ }; struct pcxhr_hostport @@ -184,6 +208,8 @@ struct pcxhr_hostport /* exported */ int pcxhr_create_pcm(struct snd_pcxhr *chip); int pcxhr_set_clock(struct pcxhr_mgr *mgr, unsigned int rate); -int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, enum pcxhr_clock_type clock_type, int *sample_rate); +int pcxhr_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate); #endif /* __SOUND_PCXHR_H */ From 7628700e08403618b0b07bd25b6456d8b2d074ef Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Tue, 25 Nov 2008 12:28:06 +0100 Subject: [PATCH 191/367] ALSA: pcxhr - add support for pcxhr stereo sound cards (firmware support) - Add support for pcxhr stereo cards and their firmware - autorize sound cards without analog IO - do some cleanup Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr_hwdep.c | 148 +++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 40 deletions(-) diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index 96640d9c227d..ea50018d785b 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -31,6 +31,7 @@ #include "pcxhr_mixer.h" #include "pcxhr_hwdep.h" #include "pcxhr_core.h" +#include "pcxhr_mix22.h" #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) @@ -40,10 +41,10 @@ #endif +static int pcxhr_sub_init(struct pcxhr_mgr *mgr); /* * get basic information and init pcxhr card */ - static int pcxhr_init_board(struct pcxhr_mgr *mgr) { int err; @@ -68,7 +69,7 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) if ((rmh.stat[0] & MASK_FIRST_FIELD) != mgr->playback_chips * 2) return -EINVAL; /* test 8 or 2 phys in */ - if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) != + if (((rmh.stat[0] >> (2 * FIELD_SIZE)) & MASK_FIRST_FIELD) < mgr->capture_chips * 2) return -EINVAL; /* test max nb substream per board */ @@ -77,20 +78,34 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) /* test max nb substream per pipe */ if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS) return -EINVAL; + snd_printdd("supported formats : playback=%x capture=%x\n", + rmh.stat[2], rmh.stat[3]); pcxhr_init_rmh(&rmh, CMD_VERSION); /* firmware num for DSP */ rmh.cmd[0] |= mgr->firmware_num; /* transfer granularity in samples (should be multiple of 48) */ - rmh.cmd[1] = (1<<23) + PCXHR_GRANULARITY; + rmh.cmd[1] = (1<<23) + mgr->granularity; rmh.cmd_len = 2; err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - snd_printdd("PCXHR DSP version is %d.%d.%d\n", - (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); + snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff, + (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); mgr->dsp_version = rmh.stat[0]; + if (mgr->is_hr_stereo) + err = hr222_sub_init(mgr); + else + err = pcxhr_sub_init(mgr); + return err; +} + +static int pcxhr_sub_init(struct pcxhr_mgr *mgr) +{ + int err; + struct pcxhr_rmh rmh; + /* get options */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_REG_STATUS; @@ -100,20 +115,22 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) if (err) return err; - if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == REG_STATUS_OPT_ANALOG_BOARD) - mgr->board_has_analog = 1; /* analog addon board available */ - else - /* analog addon board not available -> no support for instance */ - return -EINVAL; + if ((rmh.stat[1] & REG_STATUS_OPT_DAUGHTER_MASK) == + REG_STATUS_OPT_ANALOG_BOARD) + mgr->board_has_analog = 1; /* analog addon board found */ /* unmute inputs */ err = pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, REG_CONT_UNMUTE_INPUTS, NULL); if (err) return err; - /* unmute outputs */ - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); /* a write to IO_NUM_REG_MUTE_OUT mutes! */ + /* unmute outputs (a write to IO_NUM_REG_MUTE_OUT mutes!) */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; + if (DSP_EXT_CMD_SET(mgr)) { + rmh.cmd[1] = 1; /* unmute digital plugs */ + rmh.cmd_len = 2; + } err = pcxhr_send_msg(mgr, &rmh); return err; } @@ -124,19 +141,25 @@ void pcxhr_reset_board(struct pcxhr_mgr *mgr) if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) { /* mute outputs */ + if (!mgr->is_hr_stereo) { /* a read to IO_NUM_REG_MUTE_OUT register unmutes! */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_MUTE_OUT; pcxhr_send_msg(mgr, &rmh); /* mute inputs */ - pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, 0, NULL); + pcxhr_write_io_num_reg_cont(mgr, REG_CONT_UNMUTE_INPUTS, + 0, NULL); + } + /* stereo cards mute with reset of dsp */ } /* reset pcxhr dsp */ - if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) + if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_EPRM_INDEX)) pcxhr_reset_dsp(mgr); /* reset second xilinx */ - if (mgr->dsp_loaded & ( 1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) + if (mgr->dsp_loaded & (1 << PCXHR_FIRMWARE_XLX_COM_INDEX)) { pcxhr_reset_xilinx_com(mgr); + mgr->dsp_loaded = 1; + } return; } @@ -144,8 +167,9 @@ void pcxhr_reset_board(struct pcxhr_mgr *mgr) /* * allocate a playback/capture pipe (pcmp0/pcmc0) */ -static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe, - int is_capture, int pin) +static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr, + struct pcxhr_pipe *pipe, + int is_capture, int pin) { int stream_count, audio_count; int err; @@ -161,15 +185,23 @@ static int pcxhr_dsp_allocate_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pi stream_count = PCXHR_PLAYBACK_STREAMS; audio_count = 2; /* always stereo */ } - snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p'); + snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", + pin, is_capture ? 'c' : 'p'); pipe->is_capture = is_capture; pipe->first_audio = pin; /* define pipe (P_PCM_ONLY_MASK (0x020000) is not necessary) */ pcxhr_init_rmh(&rmh, CMD_RES_PIPE); - pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, audio_count, stream_count); + pcxhr_set_pipe_cmd_params(&rmh, is_capture, pin, + audio_count, stream_count); + rmh.cmd[1] |= 0x020000; /* add P_PCM_ONLY_MASK */ + if (DSP_EXT_CMD_SET(mgr)) { + /* add channel mask to command */ + rmh.cmd[rmh.cmd_len++] = (audio_count == 1) ? 0x01 : 0x03; + } err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { - snd_printk(KERN_ERR "error pipe allocation (CMD_RES_PIPE) err=%x!\n", err ); + snd_printk(KERN_ERR "error pipe allocation " + "(CMD_RES_PIPE) err=%x!\n", err); return err; } pipe->status = PCXHR_PIPE_DEFINED; @@ -199,10 +231,12 @@ static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe) snd_printk(KERN_ERR "error stopping pipe!\n"); /* release the pipe */ pcxhr_init_rmh(&rmh, CMD_FREE_PIPE); - pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0); + pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, + 0, 0); err = pcxhr_send_msg(mgr, &rmh); if (err < 0) - snd_printk(KERN_ERR "error pipe release (CMD_FREE_PIPE) err(%x)\n", err); + snd_printk(KERN_ERR "error pipe release " + "(CMD_FREE_PIPE) err(%x)\n", err); pipe->status = PCXHR_PIPE_UNDEFINED; return err; } @@ -248,15 +282,16 @@ static int pcxhr_start_pipes(struct pcxhr_mgr *mgr) for (i = 0; i < mgr->num_cards; i++) { chip = mgr->chip[i]; if (chip->nb_streams_play) - playback_mask |= (1 << chip->playback_pipe.first_audio); + playback_mask |= 1 << chip->playback_pipe.first_audio; for (j = 0; j < chip->nb_streams_capt; j++) - capture_mask |= (1 << chip->capture_pipe[j].first_audio); + capture_mask |= 1 << chip->capture_pipe[j].first_audio; } return pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); } -static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmware *dsp) +static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, + const struct firmware *dsp) { int err, card_index; @@ -330,22 +365,33 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, const struct firmwar int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) { - static char *fw_files[5] = { - "xi_1_882.dat", - "xc_1_882.dat", - "e321_512.e56", - "b321_512.b56", - "d321_512.d56" + static char *fw_files[][5] = { + [0] = { "xi_1_882.dat", "xc_1_882.dat", + "e321_512.e56", "b321_512.b56", "d321_512.d56" }, + [1] = { "xi_1_882.dat", "xc_882e.dat", + "e321_512.e56", "b882e.b56", "d321_512.d56" }, + [2] = { "xi_1_882.dat", "xc_1222.dat", + "e321_512.e56", "b1222.b56", "d1222.d56" }, + [3] = { "xi_1_882.dat", "xc_1222e.dat", + "e321_512.e56", "b1222e.b56", "d1222.d56" }, + [4] = { NULL, "x1_222hr.dat", + "e924.e56", "b924.b56", "l_1_222.d56" }, + [5] = { NULL, "x1_924hr.dat", + "e924.e56", "b924.b56", "l_1_222.d56" }, }; char path[32]; const struct firmware *fw_entry; int i, err; + int fw_set = mgr->fw_file_set; - for (i = 0; i < ARRAY_SIZE(fw_files); i++) { - sprintf(path, "pcxhr/%s", fw_files[i]); + for (i = 0; i < 5; i++) { + if (!fw_files[fw_set][i]) + continue; + sprintf(path, "pcxhr/%s", fw_files[fw_set][i]); if (request_firmware(&fw_entry, path, &mgr->pci->dev)) { - snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", path); + snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", + path); return -ENOENT; } /* fake hwdep dsp record */ @@ -360,10 +406,25 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) MODULE_FIRMWARE("pcxhr/xi_1_882.dat"); MODULE_FIRMWARE("pcxhr/xc_1_882.dat"); +MODULE_FIRMWARE("pcxhr/xc_882e.dat"); MODULE_FIRMWARE("pcxhr/e321_512.e56"); MODULE_FIRMWARE("pcxhr/b321_512.b56"); +MODULE_FIRMWARE("pcxhr/b882e.b56"); MODULE_FIRMWARE("pcxhr/d321_512.d56"); +MODULE_FIRMWARE("pcxhr/xc_1222.dat"); +MODULE_FIRMWARE("pcxhr/xc_1222e.dat"); +MODULE_FIRMWARE("pcxhr/b1222.b56"); +MODULE_FIRMWARE("pcxhr/b1222e.b56"); +MODULE_FIRMWARE("pcxhr/d1222.d56"); + +MODULE_FIRMWARE("pcxhr/x1_222hr.dat"); +MODULE_FIRMWARE("pcxhr/x1_924hr.dat"); +MODULE_FIRMWARE("pcxhr/e924.e56"); +MODULE_FIRMWARE("pcxhr/b924.b56"); +MODULE_FIRMWARE("pcxhr/l_1_222.d56"); + + #else /* old style firmware loading */ /* pcxhr hwdep interface id string */ @@ -373,7 +434,8 @@ MODULE_FIRMWARE("pcxhr/d321_512.d56"); static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw, struct snd_hwdep_dsp_status *info) { - strcpy(info->id, "pcxhr"); + 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)) @@ -393,8 +455,8 @@ static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw, 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); + 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)) { @@ -424,8 +486,11 @@ 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)*/ - if ((err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw)) < 0) + /* 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; @@ -435,10 +500,13 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *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); - if ((err = snd_card_register(mgr->chip[0]->card)) < 0) + err = snd_card_register(mgr->chip[0]->card); + if (err < 0) return err; return 0; } From c0193f39f43c79bde6c1c5804f5315f3983152b5 Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Tue, 25 Nov 2008 12:37:52 +0100 Subject: [PATCH 192/367] ALSA: pcxhr - add support for pcxhr stereo sound cards (mixer part) - add support for pcxhr stereo cards mixer controls - adjust tlv db scales to real dBu values - fix bug with monitoring volume control pcxhr_monitor_vol_put - do some cleanup Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/Makefile | 2 +- sound/pci/pcxhr/pcxhr_mix22.c | 820 ++++++++++++++++++++++++++++++++++ sound/pci/pcxhr/pcxhr_mix22.h | 56 +++ sound/pci/pcxhr/pcxhr_mixer.c | 556 +++++++++++++++-------- 4 files changed, 1259 insertions(+), 175 deletions(-) create mode 100644 sound/pci/pcxhr/pcxhr_mix22.c create mode 100644 sound/pci/pcxhr/pcxhr_mix22.h diff --git a/sound/pci/pcxhr/Makefile b/sound/pci/pcxhr/Makefile index 10473c05918d..b06128e918ca 100644 --- a/sound/pci/pcxhr/Makefile +++ b/sound/pci/pcxhr/Makefile @@ -1,2 +1,2 @@ -snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o +snd-pcxhr-objs := pcxhr.o pcxhr_hwdep.o pcxhr_mixer.o pcxhr_core.o pcxhr_mix22.o obj-$(CONFIG_SND_PCXHR) += snd-pcxhr.o diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c new file mode 100644 index 000000000000..ff019126b672 --- /dev/null +++ b/sound/pci/pcxhr/pcxhr_mix22.c @@ -0,0 +1,820 @@ +/* + * Driver for Digigram pcxhr compatible soundcards + * + * mixer interface for stereo cards + * + * Copyright (c) 2004 by Digigram + * + * 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 +#include +#include +#include +#include +#include +#include "pcxhr.h" +#include "pcxhr_core.h" +#include "pcxhr_mix22.h" + + +/* registers used on the DSP and Xilinx (port 2) : HR stereo cards only */ +#define PCXHR_DSP_RESET 0x20 +#define PCXHR_XLX_CFG 0x24 +#define PCXHR_XLX_RUER 0x28 +#define PCXHR_XLX_DATA 0x2C +#define PCXHR_XLX_STATUS 0x30 +#define PCXHR_XLX_LOFREQ 0x34 +#define PCXHR_XLX_HIFREQ 0x38 +#define PCXHR_XLX_CSUER 0x3C +#define PCXHR_XLX_SELMIC 0x40 + +#define PCXHR_DSP 2 + +/* byte access only ! */ +#define PCXHR_INPB(mgr, x) inb((mgr)->port[PCXHR_DSP] + (x)) +#define PCXHR_OUTPB(mgr, x, data) outb((data), (mgr)->port[PCXHR_DSP] + (x)) + + +/* values for PCHR_DSP_RESET register */ +#define PCXHR_DSP_RESET_DSP 0x01 +#define PCXHR_DSP_RESET_MUTE 0x02 +#define PCXHR_DSP_RESET_CODEC 0x08 + +/* values for PCHR_XLX_CFG register */ +#define PCXHR_CFG_SYNCDSP_MASK 0x80 +#define PCXHR_CFG_DEPENDENCY_MASK 0x60 +#define PCXHR_CFG_INDEPENDANT_SEL 0x00 +#define PCXHR_CFG_MASTER_SEL 0x40 +#define PCXHR_CFG_SLAVE_SEL 0x20 +#define PCXHR_CFG_DATA_UER1_SEL_MASK 0x10 /* 0 (UER0), 1(UER1) */ +#define PCXHR_CFG_DATAIN_SEL_MASK 0x08 /* 0 (ana), 1 (UER) */ +#define PCXHR_CFG_SRC_MASK 0x04 /* 0 (Bypass), 1 (SRC Actif) */ +#define PCXHR_CFG_CLOCK_UER1_SEL_MASK 0x02 /* 0 (UER0), 1(UER1) */ +#define PCXHR_CFG_CLOCKIN_SEL_MASK 0x01 /* 0 (internal), 1 (AES/EBU) */ + +/* values for PCHR_XLX_DATA register */ +#define PCXHR_DATA_CODEC 0x80 +#define AKM_POWER_CONTROL_CMD 0xA007 +#define AKM_RESET_ON_CMD 0xA100 +#define AKM_RESET_OFF_CMD 0xA103 +#define AKM_CLOCK_INF_55K_CMD 0xA240 +#define AKM_CLOCK_SUP_55K_CMD 0xA24D +#define AKM_MUTE_CMD 0xA38D +#define AKM_UNMUTE_CMD 0xA30D +#define AKM_LEFT_LEVEL_CMD 0xA600 +#define AKM_RIGHT_LEVEL_CMD 0xA700 + +/* values for PCHR_XLX_STATUS register - READ */ +#define PCXHR_STAT_SRC_LOCK 0x01 +#define PCXHR_STAT_LEVEL_IN 0x02 +#define PCXHR_STAT_MIC_CAPS 0x10 +/* values for PCHR_XLX_STATUS register - WRITE */ +#define PCXHR_STAT_FREQ_SYNC_MASK 0x01 +#define PCXHR_STAT_FREQ_UER1_MASK 0x02 +#define PCXHR_STAT_FREQ_SAVE_MASK 0x80 + +/* values for PCHR_XLX_CSUER register */ +#define PCXHR_SUER1_BIT_U_READ_MASK 0x80 +#define PCXHR_SUER1_BIT_C_READ_MASK 0x40 +#define PCXHR_SUER1_DATA_PRESENT_MASK 0x20 +#define PCXHR_SUER1_CLOCK_PRESENT_MASK 0x10 +#define PCXHR_SUER_BIT_U_READ_MASK 0x08 +#define PCXHR_SUER_BIT_C_READ_MASK 0x04 +#define PCXHR_SUER_DATA_PRESENT_MASK 0x02 +#define PCXHR_SUER_CLOCK_PRESENT_MASK 0x01 + +#define PCXHR_SUER_BIT_U_WRITE_MASK 0x02 +#define PCXHR_SUER_BIT_C_WRITE_MASK 0x01 + +/* values for PCXHR_XLX_SELMIC register - WRITE */ +#define PCXHR_SELMIC_PREAMPLI_OFFSET 2 +#define PCXHR_SELMIC_PREAMPLI_MASK 0x0C +#define PCXHR_SELMIC_PHANTOM_ALIM 0x80 + + +static const unsigned char g_hr222_p_level[] = { + 0x00, /* [000] -49.5 dB: AKM[000] = -1.#INF dB (mute) */ + 0x01, /* [001] -49.0 dB: AKM[001] = -48.131 dB (diff=0.86920 dB) */ + 0x01, /* [002] -48.5 dB: AKM[001] = -48.131 dB (diff=0.36920 dB) */ + 0x01, /* [003] -48.0 dB: AKM[001] = -48.131 dB (diff=0.13080 dB) */ + 0x01, /* [004] -47.5 dB: AKM[001] = -48.131 dB (diff=0.63080 dB) */ + 0x01, /* [005] -46.5 dB: AKM[001] = -48.131 dB (diff=1.63080 dB) */ + 0x01, /* [006] -47.0 dB: AKM[001] = -48.131 dB (diff=1.13080 dB) */ + 0x01, /* [007] -46.0 dB: AKM[001] = -48.131 dB (diff=2.13080 dB) */ + 0x01, /* [008] -45.5 dB: AKM[001] = -48.131 dB (diff=2.63080 dB) */ + 0x02, /* [009] -45.0 dB: AKM[002] = -42.110 dB (diff=2.88980 dB) */ + 0x02, /* [010] -44.5 dB: AKM[002] = -42.110 dB (diff=2.38980 dB) */ + 0x02, /* [011] -44.0 dB: AKM[002] = -42.110 dB (diff=1.88980 dB) */ + 0x02, /* [012] -43.5 dB: AKM[002] = -42.110 dB (diff=1.38980 dB) */ + 0x02, /* [013] -43.0 dB: AKM[002] = -42.110 dB (diff=0.88980 dB) */ + 0x02, /* [014] -42.5 dB: AKM[002] = -42.110 dB (diff=0.38980 dB) */ + 0x02, /* [015] -42.0 dB: AKM[002] = -42.110 dB (diff=0.11020 dB) */ + 0x02, /* [016] -41.5 dB: AKM[002] = -42.110 dB (diff=0.61020 dB) */ + 0x02, /* [017] -41.0 dB: AKM[002] = -42.110 dB (diff=1.11020 dB) */ + 0x02, /* [018] -40.5 dB: AKM[002] = -42.110 dB (diff=1.61020 dB) */ + 0x03, /* [019] -40.0 dB: AKM[003] = -38.588 dB (diff=1.41162 dB) */ + 0x03, /* [020] -39.5 dB: AKM[003] = -38.588 dB (diff=0.91162 dB) */ + 0x03, /* [021] -39.0 dB: AKM[003] = -38.588 dB (diff=0.41162 dB) */ + 0x03, /* [022] -38.5 dB: AKM[003] = -38.588 dB (diff=0.08838 dB) */ + 0x03, /* [023] -38.0 dB: AKM[003] = -38.588 dB (diff=0.58838 dB) */ + 0x03, /* [024] -37.5 dB: AKM[003] = -38.588 dB (diff=1.08838 dB) */ + 0x04, /* [025] -37.0 dB: AKM[004] = -36.090 dB (diff=0.91040 dB) */ + 0x04, /* [026] -36.5 dB: AKM[004] = -36.090 dB (diff=0.41040 dB) */ + 0x04, /* [027] -36.0 dB: AKM[004] = -36.090 dB (diff=0.08960 dB) */ + 0x04, /* [028] -35.5 dB: AKM[004] = -36.090 dB (diff=0.58960 dB) */ + 0x05, /* [029] -35.0 dB: AKM[005] = -34.151 dB (diff=0.84860 dB) */ + 0x05, /* [030] -34.5 dB: AKM[005] = -34.151 dB (diff=0.34860 dB) */ + 0x05, /* [031] -34.0 dB: AKM[005] = -34.151 dB (diff=0.15140 dB) */ + 0x05, /* [032] -33.5 dB: AKM[005] = -34.151 dB (diff=0.65140 dB) */ + 0x06, /* [033] -33.0 dB: AKM[006] = -32.568 dB (diff=0.43222 dB) */ + 0x06, /* [034] -32.5 dB: AKM[006] = -32.568 dB (diff=0.06778 dB) */ + 0x06, /* [035] -32.0 dB: AKM[006] = -32.568 dB (diff=0.56778 dB) */ + 0x07, /* [036] -31.5 dB: AKM[007] = -31.229 dB (diff=0.27116 dB) */ + 0x07, /* [037] -31.0 dB: AKM[007] = -31.229 dB (diff=0.22884 dB) */ + 0x08, /* [038] -30.5 dB: AKM[008] = -30.069 dB (diff=0.43100 dB) */ + 0x08, /* [039] -30.0 dB: AKM[008] = -30.069 dB (diff=0.06900 dB) */ + 0x09, /* [040] -29.5 dB: AKM[009] = -29.046 dB (diff=0.45405 dB) */ + 0x09, /* [041] -29.0 dB: AKM[009] = -29.046 dB (diff=0.04595 dB) */ + 0x0a, /* [042] -28.5 dB: AKM[010] = -28.131 dB (diff=0.36920 dB) */ + 0x0a, /* [043] -28.0 dB: AKM[010] = -28.131 dB (diff=0.13080 dB) */ + 0x0b, /* [044] -27.5 dB: AKM[011] = -27.303 dB (diff=0.19705 dB) */ + 0x0b, /* [045] -27.0 dB: AKM[011] = -27.303 dB (diff=0.30295 dB) */ + 0x0c, /* [046] -26.5 dB: AKM[012] = -26.547 dB (diff=0.04718 dB) */ + 0x0d, /* [047] -26.0 dB: AKM[013] = -25.852 dB (diff=0.14806 dB) */ + 0x0e, /* [048] -25.5 dB: AKM[014] = -25.208 dB (diff=0.29176 dB) */ + 0x0e, /* [049] -25.0 dB: AKM[014] = -25.208 dB (diff=0.20824 dB) */ + 0x0f, /* [050] -24.5 dB: AKM[015] = -24.609 dB (diff=0.10898 dB) */ + 0x10, /* [051] -24.0 dB: AKM[016] = -24.048 dB (diff=0.04840 dB) */ + 0x11, /* [052] -23.5 dB: AKM[017] = -23.522 dB (diff=0.02183 dB) */ + 0x12, /* [053] -23.0 dB: AKM[018] = -23.025 dB (diff=0.02535 dB) */ + 0x13, /* [054] -22.5 dB: AKM[019] = -22.556 dB (diff=0.05573 dB) */ + 0x14, /* [055] -22.0 dB: AKM[020] = -22.110 dB (diff=0.11020 dB) */ + 0x15, /* [056] -21.5 dB: AKM[021] = -21.686 dB (diff=0.18642 dB) */ + 0x17, /* [057] -21.0 dB: AKM[023] = -20.896 dB (diff=0.10375 dB) */ + 0x18, /* [058] -20.5 dB: AKM[024] = -20.527 dB (diff=0.02658 dB) */ + 0x1a, /* [059] -20.0 dB: AKM[026] = -19.831 dB (diff=0.16866 dB) */ + 0x1b, /* [060] -19.5 dB: AKM[027] = -19.504 dB (diff=0.00353 dB) */ + 0x1d, /* [061] -19.0 dB: AKM[029] = -18.883 dB (diff=0.11716 dB) */ + 0x1e, /* [062] -18.5 dB: AKM[030] = -18.588 dB (diff=0.08838 dB) */ + 0x20, /* [063] -18.0 dB: AKM[032] = -18.028 dB (diff=0.02780 dB) */ + 0x22, /* [064] -17.5 dB: AKM[034] = -17.501 dB (diff=0.00123 dB) */ + 0x24, /* [065] -17.0 dB: AKM[036] = -17.005 dB (diff=0.00475 dB) */ + 0x26, /* [066] -16.5 dB: AKM[038] = -16.535 dB (diff=0.03513 dB) */ + 0x28, /* [067] -16.0 dB: AKM[040] = -16.090 dB (diff=0.08960 dB) */ + 0x2b, /* [068] -15.5 dB: AKM[043] = -15.461 dB (diff=0.03857 dB) */ + 0x2d, /* [069] -15.0 dB: AKM[045] = -15.067 dB (diff=0.06655 dB) */ + 0x30, /* [070] -14.5 dB: AKM[048] = -14.506 dB (diff=0.00598 dB) */ + 0x33, /* [071] -14.0 dB: AKM[051] = -13.979 dB (diff=0.02060 dB) */ + 0x36, /* [072] -13.5 dB: AKM[054] = -13.483 dB (diff=0.01707 dB) */ + 0x39, /* [073] -13.0 dB: AKM[057] = -13.013 dB (diff=0.01331 dB) */ + 0x3c, /* [074] -12.5 dB: AKM[060] = -12.568 dB (diff=0.06778 dB) */ + 0x40, /* [075] -12.0 dB: AKM[064] = -12.007 dB (diff=0.00720 dB) */ + 0x44, /* [076] -11.5 dB: AKM[068] = -11.481 dB (diff=0.01937 dB) */ + 0x48, /* [077] -11.0 dB: AKM[072] = -10.984 dB (diff=0.01585 dB) */ + 0x4c, /* [078] -10.5 dB: AKM[076] = -10.515 dB (diff=0.01453 dB) */ + 0x51, /* [079] -10.0 dB: AKM[081] = -9.961 dB (diff=0.03890 dB) */ + 0x55, /* [080] -9.5 dB: AKM[085] = -9.542 dB (diff=0.04243 dB) */ + 0x5a, /* [081] -9.0 dB: AKM[090] = -9.046 dB (diff=0.04595 dB) */ + 0x60, /* [082] -8.5 dB: AKM[096] = -8.485 dB (diff=0.01462 dB) */ + 0x66, /* [083] -8.0 dB: AKM[102] = -7.959 dB (diff=0.04120 dB) */ + 0x6c, /* [084] -7.5 dB: AKM[108] = -7.462 dB (diff=0.03767 dB) */ + 0x72, /* [085] -7.0 dB: AKM[114] = -6.993 dB (diff=0.00729 dB) */ + 0x79, /* [086] -6.5 dB: AKM[121] = -6.475 dB (diff=0.02490 dB) */ + 0x80, /* [087] -6.0 dB: AKM[128] = -5.987 dB (diff=0.01340 dB) */ + 0x87, /* [088] -5.5 dB: AKM[135] = -5.524 dB (diff=0.02413 dB) */ + 0x8f, /* [089] -5.0 dB: AKM[143] = -5.024 dB (diff=0.02408 dB) */ + 0x98, /* [090] -4.5 dB: AKM[152] = -4.494 dB (diff=0.00607 dB) */ + 0xa1, /* [091] -4.0 dB: AKM[161] = -3.994 dB (diff=0.00571 dB) */ + 0xaa, /* [092] -3.5 dB: AKM[170] = -3.522 dB (diff=0.02183 dB) */ + 0xb5, /* [093] -3.0 dB: AKM[181] = -2.977 dB (diff=0.02277 dB) */ + 0xbf, /* [094] -2.5 dB: AKM[191] = -2.510 dB (diff=0.01014 dB) */ + 0xcb, /* [095] -2.0 dB: AKM[203] = -1.981 dB (diff=0.01912 dB) */ + 0xd7, /* [096] -1.5 dB: AKM[215] = -1.482 dB (diff=0.01797 dB) */ + 0xe3, /* [097] -1.0 dB: AKM[227] = -1.010 dB (diff=0.01029 dB) */ + 0xf1, /* [098] -0.5 dB: AKM[241] = -0.490 dB (diff=0.00954 dB) */ + 0xff, /* [099] +0.0 dB: AKM[255] = +0.000 dB (diff=0.00000 dB) */ +}; + + +static void hr222_config_akm(struct pcxhr_mgr *mgr, unsigned short data) +{ + unsigned short mask = 0x8000; + /* activate access to codec registers */ + PCXHR_INPB(mgr, PCXHR_XLX_HIFREQ); + + while (mask) { + PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, + data & mask ? PCXHR_DATA_CODEC : 0); + mask >>= 1; + } + /* termiate access to codec registers */ + PCXHR_INPB(mgr, PCXHR_XLX_RUER); +} + + +static int hr222_set_hw_playback_level(struct pcxhr_mgr *mgr, + int idx, int level) +{ + unsigned short cmd; + if (idx > 1 || + level < 0 || + level >= ARRAY_SIZE(g_hr222_p_level)) + return -EINVAL; + + if (idx == 0) + cmd = AKM_LEFT_LEVEL_CMD; + else + cmd = AKM_RIGHT_LEVEL_CMD; + + /* conversion from PmBoardCodedLevel to AKM nonlinear programming */ + cmd += g_hr222_p_level[level]; + + hr222_config_akm(mgr, cmd); + return 0; +} + + +static int hr222_set_hw_capture_level(struct pcxhr_mgr *mgr, + int level_l, int level_r, int level_mic) +{ + /* program all input levels at the same time */ + unsigned int data; + int i; + + if (!mgr->capture_chips) + return -EINVAL; /* no PCX22 */ + + data = ((level_mic & 0xff) << 24); /* micro is mono, but apply */ + data |= ((level_mic & 0xff) << 16); /* level on both channels */ + data |= ((level_r & 0xff) << 8); /* line input right channel */ + data |= (level_l & 0xff); /* line input left channel */ + + PCXHR_INPB(mgr, PCXHR_XLX_DATA); /* activate input codec */ + /* send 32 bits (4 x 8 bits) */ + for (i = 0; i < 32; i++, data <<= 1) { + PCXHR_OUTPB(mgr, PCXHR_XLX_DATA, + (data & 0x80000000) ? PCXHR_DATA_CODEC : 0); + } + PCXHR_INPB(mgr, PCXHR_XLX_RUER); /* close input level codec */ + return 0; +} + +static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level); + +int hr222_sub_init(struct pcxhr_mgr *mgr) +{ + unsigned char reg; + + mgr->board_has_analog = 1; /* analog always available */ + mgr->xlx_cfg = PCXHR_CFG_SYNCDSP_MASK; + + reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); + if (reg & PCXHR_STAT_MIC_CAPS) + mgr->board_has_mic = 1; /* microphone available */ + snd_printdd("MIC input available = %d\n", mgr->board_has_mic); + + /* reset codec */ + PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, + PCXHR_DSP_RESET_DSP); + msleep(5); + PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, + PCXHR_DSP_RESET_DSP | + PCXHR_DSP_RESET_MUTE | + PCXHR_DSP_RESET_CODEC); + msleep(5); + + /* config AKM */ + hr222_config_akm(mgr, AKM_POWER_CONTROL_CMD); + hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); + hr222_config_akm(mgr, AKM_UNMUTE_CMD); + hr222_config_akm(mgr, AKM_RESET_OFF_CMD); + + /* init micro boost */ + hr222_micro_boost(mgr, 0); + + return 0; +} + + +/* calc PLL register */ +/* TODO : there is a very similar fct in pcxhr.c */ +static int hr222_pll_freq_register(unsigned int freq, + unsigned int *pllreg, + unsigned int *realfreq) +{ + unsigned int reg; + + if (freq < 6900 || freq > 219000) + return -EINVAL; + reg = (28224000 * 2) / freq; + reg = (reg - 1) / 2; + if (reg < 0x100) + *pllreg = reg + 0xC00; + else if (reg < 0x200) + *pllreg = reg + 0x800; + else if (reg < 0x400) + *pllreg = reg & 0x1ff; + else if (reg < 0x800) { + *pllreg = ((reg >> 1) & 0x1ff) + 0x200; + reg &= ~1; + } else { + *pllreg = ((reg >> 2) & 0x1ff) + 0x400; + reg &= ~3; + } + if (realfreq) + *realfreq = (28224000 / (reg + 1)); + return 0; +} + +int hr222_sub_set_clock(struct pcxhr_mgr *mgr, + unsigned int rate, + int *changed) +{ + unsigned int speed, pllreg = 0; + int err; + unsigned realfreq = rate; + + switch (mgr->use_clock_type) { + case HR22_CLOCK_TYPE_INTERNAL: + err = hr222_pll_freq_register(rate, &pllreg, &realfreq); + if (err) + return err; + + mgr->xlx_cfg &= ~(PCXHR_CFG_CLOCKIN_SEL_MASK | + PCXHR_CFG_CLOCK_UER1_SEL_MASK); + break; + case HR22_CLOCK_TYPE_AES_SYNC: + mgr->xlx_cfg |= PCXHR_CFG_CLOCKIN_SEL_MASK; + mgr->xlx_cfg &= ~PCXHR_CFG_CLOCK_UER1_SEL_MASK; + break; + case HR22_CLOCK_TYPE_AES_1: + if (!mgr->board_has_aes1) + return -EINVAL; + + mgr->xlx_cfg |= (PCXHR_CFG_CLOCKIN_SEL_MASK | + PCXHR_CFG_CLOCK_UER1_SEL_MASK); + break; + default: + return -EINVAL; + } + hr222_config_akm(mgr, AKM_MUTE_CMD); + + if (mgr->use_clock_type == HR22_CLOCK_TYPE_INTERNAL) { + PCXHR_OUTPB(mgr, PCXHR_XLX_HIFREQ, pllreg >> 8); + PCXHR_OUTPB(mgr, PCXHR_XLX_LOFREQ, pllreg & 0xff); + } + + /* set clock source */ + PCXHR_OUTPB(mgr, PCXHR_XLX_CFG, mgr->xlx_cfg); + + /* codec speed modes */ + speed = rate < 55000 ? 0 : 1; + if (mgr->codec_speed != speed) { + mgr->codec_speed = speed; + if (speed == 0) + hr222_config_akm(mgr, AKM_CLOCK_INF_55K_CMD); + else + hr222_config_akm(mgr, AKM_CLOCK_SUP_55K_CMD); + } + + mgr->sample_rate_real = realfreq; + mgr->cur_clock_type = mgr->use_clock_type; + + if (changed) + *changed = 1; + + hr222_config_akm(mgr, AKM_UNMUTE_CMD); + + snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n", + rate, realfreq, pllreg); + return 0; +} + +int hr222_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate) +{ + int rate, calc_rate = 0; + unsigned int ticks; + unsigned char mask, reg; + + if (clock_type == HR22_CLOCK_TYPE_AES_SYNC) { + + mask = (PCXHR_SUER_CLOCK_PRESENT_MASK | + PCXHR_SUER_DATA_PRESENT_MASK); + reg = PCXHR_STAT_FREQ_SYNC_MASK; + + } else if (clock_type == HR22_CLOCK_TYPE_AES_1 && mgr->board_has_aes1) { + + mask = (PCXHR_SUER1_CLOCK_PRESENT_MASK | + PCXHR_SUER1_DATA_PRESENT_MASK); + reg = PCXHR_STAT_FREQ_UER1_MASK; + + } else { + snd_printdd("get_external_clock : type %d not supported\n", + clock_type); + return -EINVAL; /* other clocks not supported */ + } + + if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) { + snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type); + *sample_rate = 0; + return 0; /* no external clock locked */ + } + + PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* calculate freq */ + + /* save the measured clock frequency */ + reg |= PCXHR_STAT_FREQ_SAVE_MASK; + + if (mgr->last_reg_stat != reg) { + udelay(500); /* wait min 2 cycles of lowest freq (8000) */ + mgr->last_reg_stat = reg; + } + + PCXHR_OUTPB(mgr, PCXHR_XLX_STATUS, reg); /* save */ + + /* get the frequency */ + ticks = (unsigned int)PCXHR_INPB(mgr, PCXHR_XLX_CFG); + ticks = (ticks & 0x03) << 8; + ticks |= (unsigned int)PCXHR_INPB(mgr, PCXHR_DSP_RESET); + + if (ticks != 0) + calc_rate = 28224000 / ticks; + /* rounding */ + if (calc_rate > 184200) + rate = 192000; + else if (calc_rate > 152200) + rate = 176400; + else if (calc_rate > 112000) + rate = 128000; + else if (calc_rate > 92100) + rate = 96000; + else if (calc_rate > 76100) + rate = 88200; + else if (calc_rate > 56000) + rate = 64000; + else if (calc_rate > 46050) + rate = 48000; + else if (calc_rate > 38050) + rate = 44100; + else if (calc_rate > 28000) + rate = 32000; + else if (calc_rate > 23025) + rate = 24000; + else if (calc_rate > 19025) + rate = 22050; + else if (calc_rate > 14000) + rate = 16000; + else if (calc_rate > 11512) + rate = 12000; + else if (calc_rate > 9512) + rate = 11025; + else if (calc_rate > 7000) + rate = 8000; + else + rate = 0; + + snd_printdd("External clock is at %d Hz (measured %d Hz)\n", + rate, calc_rate); + *sample_rate = rate; + return 0; +} + + +int hr222_update_analog_audio_level(struct snd_pcxhr *chip, + int is_capture, int channel) +{ + snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n", + is_capture ? "capture" : "playback", channel); + if (is_capture) { + int level_l, level_r, level_mic; + /* we have to update all levels */ + if (chip->analog_capture_active) { + level_l = chip->analog_capture_volume[0]; + level_r = chip->analog_capture_volume[1]; + } else { + level_l = HR222_LINE_CAPTURE_LEVEL_MIN; + level_r = HR222_LINE_CAPTURE_LEVEL_MIN; + } + if (chip->mic_active) + level_mic = chip->mic_volume; + else + level_mic = HR222_MICRO_CAPTURE_LEVEL_MIN; + return hr222_set_hw_capture_level(chip->mgr, + level_l, level_r, level_mic); + } else { + int vol; + if (chip->analog_playback_active[channel]) + vol = chip->analog_playback_volume[channel]; + else + vol = HR222_LINE_PLAYBACK_LEVEL_MIN; + return hr222_set_hw_playback_level(chip->mgr, channel, vol); + } +} + + +/*texts[5] = {"Line", "Digital", "Digi+SRC", "Mic", "Line+Mic"}*/ +#define SOURCE_LINE 0 +#define SOURCE_DIGITAL 1 +#define SOURCE_DIGISRC 2 +#define SOURCE_MIC 3 +#define SOURCE_LINEMIC 4 + +int hr222_set_audio_source(struct snd_pcxhr *chip) +{ + int digital = 0; + /* default analog source */ + chip->mgr->xlx_cfg &= ~(PCXHR_CFG_SRC_MASK | + PCXHR_CFG_DATAIN_SEL_MASK | + PCXHR_CFG_DATA_UER1_SEL_MASK); + + if (chip->audio_capture_source == SOURCE_DIGISRC) { + chip->mgr->xlx_cfg |= PCXHR_CFG_SRC_MASK; + digital = 1; + } else { + if (chip->audio_capture_source == SOURCE_DIGITAL) + digital = 1; + } + if (digital) { + chip->mgr->xlx_cfg |= PCXHR_CFG_DATAIN_SEL_MASK; + if (chip->mgr->board_has_aes1) { + /* get data from the AES1 plug */ + chip->mgr->xlx_cfg |= PCXHR_CFG_DATA_UER1_SEL_MASK; + } + /* chip->mic_active = 0; */ + /* chip->analog_capture_active = 0; */ + } else { + int update_lvl = 0; + chip->analog_capture_active = 0; + chip->mic_active = 0; + if (chip->audio_capture_source == SOURCE_LINE || + chip->audio_capture_source == SOURCE_LINEMIC) { + if (chip->analog_capture_active == 0) + update_lvl = 1; + chip->analog_capture_active = 1; + } + if (chip->audio_capture_source == SOURCE_MIC || + chip->audio_capture_source == SOURCE_LINEMIC) { + if (chip->mic_active == 0) + update_lvl = 1; + chip->mic_active = 1; + } + if (update_lvl) { + /* capture: update all 3 mutes/unmutes with one call */ + hr222_update_analog_audio_level(chip, 1, 0); + } + } + /* set the source infos (max 3 bits modified) */ + PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CFG, chip->mgr->xlx_cfg); + return 0; +} + + +int hr222_iec958_capture_byte(struct snd_pcxhr *chip, + int aes_idx, unsigned char *aes_bits) +{ + unsigned char idx = (unsigned char)(aes_idx * 8); + unsigned char temp = 0; + unsigned char mask = chip->mgr->board_has_aes1 ? + PCXHR_SUER1_BIT_C_READ_MASK : PCXHR_SUER_BIT_C_READ_MASK; + int i; + for (i = 0; i < 8; i++) { + PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx++); /* idx < 192 */ + temp <<= 1; + if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask) + temp |= 1; + } + snd_printdd("read iec958 AES %d byte %d = 0x%x\n", + chip->chip_idx, aes_idx, temp); + *aes_bits = temp; + return 0; +} + + +int hr222_iec958_update_byte(struct snd_pcxhr *chip, + int aes_idx, unsigned char aes_bits) +{ + int i; + unsigned char new_bits = aes_bits; + unsigned char old_bits = chip->aes_bits[aes_idx]; + unsigned char idx = (unsigned char)(aes_idx * 8); + for (i = 0; i < 8; i++) { + if ((old_bits & 0x01) != (new_bits & 0x01)) { + /* idx < 192 */ + PCXHR_OUTPB(chip->mgr, PCXHR_XLX_RUER, idx); + /* write C and U bit */ + PCXHR_OUTPB(chip->mgr, PCXHR_XLX_CSUER, new_bits&0x01 ? + PCXHR_SUER_BIT_C_WRITE_MASK : 0); + } + idx++; + old_bits >>= 1; + new_bits >>= 1; + } + chip->aes_bits[aes_idx] = aes_bits; + return 0; +} + +static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level) +{ + unsigned char boost_mask; + boost_mask = (unsigned char) (level << PCXHR_SELMIC_PREAMPLI_OFFSET); + if (boost_mask & (~PCXHR_SELMIC_PREAMPLI_MASK)) + return; /* only values form 0 to 3 accepted */ + + mgr->xlx_selmic &= ~PCXHR_SELMIC_PREAMPLI_MASK; + mgr->xlx_selmic |= boost_mask; + + PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); + + snd_printdd("hr222_micro_boost : set %x\n", boost_mask); +} + +static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power) +{ + if (power) + mgr->xlx_selmic |= PCXHR_SELMIC_PHANTOM_ALIM; + else + mgr->xlx_selmic &= ~PCXHR_SELMIC_PHANTOM_ALIM; + + PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); + + snd_printdd("hr222_phantom_power : set %d\n", power); +} + + +/* mic level */ +static const DECLARE_TLV_DB_SCALE(db_scale_mic_hr222, -9850, 50, 650); + +static int hr222_mic_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = HR222_MICRO_CAPTURE_LEVEL_MIN; /* -98 dB */ + /* gains from 9 dB to 31.5 dB not recommended; use micboost instead */ + uinfo->value.integer.max = HR222_MICRO_CAPTURE_LEVEL_MAX; /* +7 dB */ + return 0; +} + +static int hr222_mic_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + mutex_lock(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->mic_volume; + mutex_unlock(&chip->mgr->mixer_mutex); + return 0; +} + +static int hr222_mic_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + mutex_lock(&chip->mgr->mixer_mutex); + if (chip->mic_volume != ucontrol->value.integer.value[0]) { + changed = 1; + chip->mic_volume = ucontrol->value.integer.value[0]; + hr222_update_analog_audio_level(chip, 1, 0); + } + mutex_unlock(&chip->mgr->mixer_mutex); + return changed; +} + +static struct snd_kcontrol_new hr222_control_mic_level = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .name = "Mic Capture Volume", + .info = hr222_mic_vol_info, + .get = hr222_mic_vol_get, + .put = hr222_mic_vol_put, + .tlv = { .p = db_scale_mic_hr222 }, +}; + + +/* mic boost level */ +static const DECLARE_TLV_DB_SCALE(db_scale_micboost_hr222, 0, 1800, 5400); + +static int hr222_mic_boost_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* 0 dB */ + uinfo->value.integer.max = 3; /* 54 dB */ + return 0; +} + +static int hr222_mic_boost_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + mutex_lock(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->mic_boost; + mutex_unlock(&chip->mgr->mixer_mutex); + return 0; +} + +static int hr222_mic_boost_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + mutex_lock(&chip->mgr->mixer_mutex); + if (chip->mic_boost != ucontrol->value.integer.value[0]) { + changed = 1; + chip->mic_boost = ucontrol->value.integer.value[0]; + hr222_micro_boost(chip->mgr, chip->mic_boost); + } + mutex_unlock(&chip->mgr->mixer_mutex); + return changed; +} + +static struct snd_kcontrol_new hr222_control_mic_boost = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ), + .name = "MicBoost Capture Volume", + .info = hr222_mic_boost_info, + .get = hr222_mic_boost_get, + .put = hr222_mic_boost_put, + .tlv = { .p = db_scale_micboost_hr222 }, +}; + + +/******************* Phantom power switch *******************/ +#define hr222_phantom_power_info snd_ctl_boolean_mono_info + +static int hr222_phantom_power_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + mutex_lock(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->phantom_power; + mutex_unlock(&chip->mgr->mixer_mutex); + return 0; +} + +static int hr222_phantom_power_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + int power, changed = 0; + + mutex_lock(&chip->mgr->mixer_mutex); + power = !!ucontrol->value.integer.value[0]; + if (chip->phantom_power != power) { + hr222_phantom_power(chip->mgr, power); + chip->phantom_power = power; + changed = 1; + } + mutex_unlock(&chip->mgr->mixer_mutex); + return changed; +} + +static struct snd_kcontrol_new hr222_phantom_power_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Phantom Power Switch", + .info = hr222_phantom_power_info, + .get = hr222_phantom_power_get, + .put = hr222_phantom_power_put, +}; + + +int hr222_add_mic_controls(struct snd_pcxhr *chip) +{ + int err; + if (!chip->mgr->board_has_mic) + return 0; + + /* controls */ + err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_level, + chip)); + if (err < 0) + return err; + + err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_control_mic_boost, + chip)); + if (err < 0) + return err; + + err = snd_ctl_add(chip->card, snd_ctl_new1(&hr222_phantom_power_switch, + chip)); + return err; +} diff --git a/sound/pci/pcxhr/pcxhr_mix22.h b/sound/pci/pcxhr/pcxhr_mix22.h new file mode 100644 index 000000000000..6b318b2f0100 --- /dev/null +++ b/sound/pci/pcxhr/pcxhr_mix22.h @@ -0,0 +1,56 @@ +/* + * Driver for Digigram pcxhr compatible soundcards + * + * low level interface with interrupt ans message handling + * + * Copyright (c) 2004 by Digigram + * + * 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 + */ + +#ifndef __SOUND_PCXHR_MIX22_H +#define __SOUND_PCXHR_MIX22_H + +struct pcxhr_mgr; + +int hr222_sub_init(struct pcxhr_mgr *mgr); +int hr222_sub_set_clock(struct pcxhr_mgr *mgr, unsigned int rate, + int *changed); +int hr222_get_external_clock(struct pcxhr_mgr *mgr, + enum pcxhr_clock_type clock_type, + int *sample_rate); + +#define HR222_LINE_PLAYBACK_LEVEL_MIN 0 /* -25.5 dB */ +#define HR222_LINE_PLAYBACK_ZERO_LEVEL 51 /* 0.0 dB */ +#define HR222_LINE_PLAYBACK_LEVEL_MAX 99 /* +24.0 dB */ + +#define HR222_LINE_CAPTURE_LEVEL_MIN 0 /* -111.5 dB */ +#define HR222_LINE_CAPTURE_ZERO_LEVEL 223 /* 0.0 dB */ +#define HR222_LINE_CAPTURE_LEVEL_MAX 255 /* +16 dB */ +#define HR222_MICRO_CAPTURE_LEVEL_MIN 0 /* -98.5 dB */ +#define HR222_MICRO_CAPTURE_LEVEL_MAX 210 /* +6.5 dB */ + +int hr222_update_analog_audio_level(struct snd_pcxhr *chip, + int is_capture, + int channel); +int hr222_set_audio_source(struct snd_pcxhr *chip); +int hr222_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, + unsigned char *aes_bits); +int hr222_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, + unsigned char aes_bits); + +int hr222_add_mic_controls(struct snd_pcxhr *chip); + +#endif /* __SOUND_PCXHR_MIX22_H */ diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index aabc7bc5321e..2436e374586f 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -33,20 +33,24 @@ #include #include #include "pcxhr_mixer.h" +#include "pcxhr_mix22.h" +#define PCXHR_LINE_CAPTURE_LEVEL_MIN 0 /* -112.0 dB */ +#define PCXHR_LINE_CAPTURE_LEVEL_MAX 255 /* +15.5 dB */ +#define PCXHR_LINE_CAPTURE_ZERO_LEVEL 224 /* 0.0 dB ( 0 dBu -> 0 dBFS ) */ -#define PCXHR_ANALOG_CAPTURE_LEVEL_MIN 0 /* -96.0 dB */ -#define PCXHR_ANALOG_CAPTURE_LEVEL_MAX 255 /* +31.5 dB */ -#define PCXHR_ANALOG_CAPTURE_ZERO_LEVEL 224 /* +16.0 dB ( +31.5 dB - fix level +15.5 dB ) */ +#define PCXHR_LINE_PLAYBACK_LEVEL_MIN 0 /* -104.0 dB */ +#define PCXHR_LINE_PLAYBACK_LEVEL_MAX 128 /* +24.0 dB */ +#define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104 /* 0.0 dB ( 0 dBFS -> 0 dBu ) */ -#define PCXHR_ANALOG_PLAYBACK_LEVEL_MIN 0 /* -128.0 dB */ -#define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ -#define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ - -static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -9600, 50, 3150); +static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550); static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); -static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) +static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600); +static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400); + +static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, + int is_capture, int channel) { int err, vol; struct pcxhr_rmh rmh; @@ -60,15 +64,17 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_captur if (chip->analog_playback_active[channel]) vol = chip->analog_playback_volume[channel]; else - vol = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; - rmh.cmd[2] = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX - vol; /* playback analog levels are inversed */ + vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN; + /* playback analog levels are inversed */ + rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol; } rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { - snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d) " - "is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err); + snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)" + " is_capture(%d) err(%x)\n", + chip->chip_idx, is_capture, err); return -EINVAL; } return 0; @@ -80,14 +86,34 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_captur static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; if (kcontrol->private_value == 0) { /* playback */ - uinfo->value.integer.min = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; /* -128 dB */ - uinfo->value.integer.max = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX; /* 0 dB */ + if (chip->mgr->is_hr_stereo) { + uinfo->value.integer.min = + HR222_LINE_PLAYBACK_LEVEL_MIN; /* -25 dB */ + uinfo->value.integer.max = + HR222_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ + } else { + uinfo->value.integer.min = + PCXHR_LINE_PLAYBACK_LEVEL_MIN; /*-104 dB */ + uinfo->value.integer.max = + PCXHR_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ + } } else { /* capture */ - uinfo->value.integer.min = PCXHR_ANALOG_CAPTURE_LEVEL_MIN; /* -96 dB */ - uinfo->value.integer.max = PCXHR_ANALOG_CAPTURE_LEVEL_MAX; /* 31.5 dB */ + if (chip->mgr->is_hr_stereo) { + uinfo->value.integer.min = + HR222_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ + uinfo->value.integer.max = + HR222_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ + } else { + uinfo->value.integer.min = + PCXHR_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ + uinfo->value.integer.max = + PCXHR_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ + } } return 0; } @@ -98,11 +124,11 @@ static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); mutex_lock(&chip->mgr->mixer_mutex); if (kcontrol->private_value == 0) { /* playback */ - ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; - ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; + ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; + ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; } else { /* capture */ - ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; - ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; + ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; + ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; } mutex_unlock(&chip->mgr->mixer_mutex); return 0; @@ -123,18 +149,35 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i]; if (is_capture) { - if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN || - new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX) - continue; + if (chip->mgr->is_hr_stereo) { + if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN || + new_volume > HR222_LINE_CAPTURE_LEVEL_MAX) + continue; + } else { + if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN || + new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX) + continue; + } } else { - if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN || - new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX) - continue; + if (chip->mgr->is_hr_stereo) { + if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN || + new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX) + continue; + } else { + if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN || + new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX) + continue; + } } if (*stored_volume != new_volume) { *stored_volume = new_volume; changed = 1; - pcxhr_update_analog_audio_level(chip, is_capture, i); + if (chip->mgr->is_hr_stereo) + hr222_update_analog_audio_level(chip, + is_capture, i); + else + pcxhr_update_analog_audio_level(chip, + is_capture, i); } } mutex_unlock(&chip->mgr->mixer_mutex); @@ -153,6 +196,7 @@ static struct snd_kcontrol_new pcxhr_control_analog_level = { }; /* shared */ + #define pcxhr_sw_info snd_ctl_boolean_stereo_info static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, @@ -180,7 +224,10 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, !!ucontrol->value.integer.value[i]; changed = 1; /* update playback levels */ - pcxhr_update_analog_audio_level(chip, 0, i); + if (chip->mgr->is_hr_stereo) + hr222_update_analog_audio_level(chip, 0, i); + else + pcxhr_update_analog_audio_level(chip, 0, i); } } mutex_unlock(&chip->mgr->mixer_mutex); @@ -251,7 +298,8 @@ static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) #define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 #define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 -static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, int channel) +static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, + int capture, int channel) { int err; struct pcxhr_rmh rmh; @@ -264,18 +312,20 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, in pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); /* add channel mask */ - pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio)); - /* TODO : if mask (3 << pipe->first_audio) is used, left and right channel - * will be programmed to the same params - */ + pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, + 1 << (channel + pipe->first_audio)); + /* TODO : if mask (3 << pipe->first_audio) is used, left and right + * channel will be programmed to the same params */ if (capture) { rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; - /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled (capture pipe level) */ + /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled + * (capture pipe level) */ rmh.cmd[2] = chip->digital_capture_volume[channel]; } else { - rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1; - /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL not yet - * handled (playback pipe level) + rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | + VALID_AUDIO_IO_MUTE_MONITOR_1; + /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL + * not yet handled (playback pipe level) */ rmh.cmd[2] = chip->monitoring_volume[channel] << 10; if (chip->monitoring_active[channel] == 0) @@ -284,8 +334,8 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, in rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); - if(err<0) { - snd_printk(KERN_DEBUG "error update_audio_level card(%d) err(%x)\n", + if (err < 0) { + snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n", chip->chip_idx, err); return -EINVAL; } @@ -309,15 +359,15 @@ static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int *stored_volume; int is_capture = kcontrol->private_value; mutex_lock(&chip->mgr->mixer_mutex); - if (is_capture) - stored_volume = chip->digital_capture_volume; /* digital capture */ - else - stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ + if (is_capture) /* digital capture */ + stored_volume = chip->digital_capture_volume; + else /* digital playback */ + stored_volume = chip->digital_playback_volume[idx]; ucontrol->value.integer.value[0] = stored_volume[0]; ucontrol->value.integer.value[1] = stored_volume[1]; mutex_unlock(&chip->mgr->mixer_mutex); @@ -328,7 +378,7 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); - int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ int changed = 0; int is_capture = kcontrol->private_value; int *stored_volume; @@ -384,7 +434,8 @@ static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, return 0; } -static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int changed = 0; @@ -444,8 +495,8 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { chip->monitoring_volume[i] = - !!ucontrol->value.integer.value[i]; - if(chip->monitoring_active[i]) + ucontrol->value.integer.value[i]; + if (chip->monitoring_active[i]) /* update monitoring volume and mute */ /* do only when monitoring is unmuted */ pcxhr_update_audio_pipe_level(chip, 0, i); @@ -460,7 +511,7 @@ static struct snd_kcontrol_new pcxhr_control_monitor_vol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), - .name = "Monitoring Volume", + .name = "Monitoring Playback Volume", .info = pcxhr_digital_vol_info, /* shared */ .get = pcxhr_monitor_vol_get, .put = pcxhr_monitor_vol_put, @@ -511,7 +562,7 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new pcxhr_control_monitor_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Monitoring Switch", + .name = "Monitoring Playback Switch", .info = pcxhr_sw_info, /* shared */ .get = pcxhr_monitor_sw_get, .put = pcxhr_monitor_sw_put @@ -533,7 +584,7 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) struct pcxhr_rmh rmh; unsigned int mask, reg; unsigned int codec; - int err, use_src, changed; + int err, changed; switch (chip->chip_idx) { case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; @@ -542,13 +593,10 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; default: return -EINVAL; } - reg = 0; /* audio source from analog plug */ - use_src = 0; /* do not activate codec SRC */ - if (chip->audio_capture_source != 0) { reg = mask; /* audio source from digital plug */ - if (chip->audio_capture_source == 2) - use_src = 1; + } else { + reg = 0; /* audio source from analog plug */ } /* set the input source */ pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); @@ -560,29 +608,61 @@ static int pcxhr_set_audio_source(struct snd_pcxhr* chip) if (err) return err; } - pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set codec SRC on off */ - rmh.cmd_len = 3; - rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; - rmh.cmd[1] = codec; - rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54); - err = pcxhr_send_msg(chip->mgr, &rmh); - if(err) - return err; - rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49); - err = pcxhr_send_msg(chip->mgr, &rmh); + if (chip->mgr->board_aes_in_192k) { + int i; + unsigned int src_config = 0xC0; + /* update all src configs with one call */ + for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) { + if (chip->mgr->chip[i]->audio_capture_source == 2) + src_config |= (1 << (3 - i)); + } + /* set codec SRC on off */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); + rmh.cmd_len = 2; + rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC; + rmh.cmd[1] = src_config; + err = pcxhr_send_msg(chip->mgr, &rmh); + } else { + int use_src = 0; + if (chip->audio_capture_source == 2) + use_src = 1; + /* set codec SRC on off */ + pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); + rmh.cmd_len = 3; + rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; + rmh.cmd[1] = codec; + rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | + (use_src ? 0x41 : 0x54)); + err = pcxhr_send_msg(chip->mgr, &rmh); + if (err) + return err; + rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | + (use_src ? 0x41 : 0x49)); + err = pcxhr_send_msg(chip->mgr, &rmh); + } return err; } static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = {"Analog", "Digital", "Digi+SRC"}; + static const char *texts[5] = { + "Line", "Digital", "Digi+SRC", "Mic", "Line+Mic" + }; + int i; + struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); + i = 2; /* no SRC, no Mic available */ + if (chip->mgr->board_has_aes1) { + i = 3; /* SRC available */ + if (chip->mgr->board_has_mic) + i = 5; /* Mic and MicroMix available */ + } uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; + uinfo->value.enumerated.items = i; + if (uinfo->value.enumerated.item > (i-1)) + uinfo->value.enumerated.item = i-1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0; @@ -601,13 +681,21 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); int ret = 0; - - if (ucontrol->value.enumerated.item[0] >= 3) + int i = 2; /* no SRC, no Mic available */ + if (chip->mgr->board_has_aes1) { + i = 3; /* SRC available */ + if (chip->mgr->board_has_mic) + i = 5; /* Mic and MicroMix available */ + } + if (ucontrol->value.enumerated.item[0] >= i) return -EINVAL; mutex_lock(&chip->mgr->mixer_mutex); if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { chip->audio_capture_source = ucontrol->value.enumerated.item[0]; - pcxhr_set_audio_source(chip); + if (chip->mgr->is_hr_stereo) + hr222_set_audio_source(chip); + else + pcxhr_set_audio_source(chip); ret = 1; } mutex_unlock(&chip->mgr->mixer_mutex); @@ -626,25 +714,46 @@ static struct snd_kcontrol_new pcxhr_control_audio_src = { /* * clock type selection * enum pcxhr_clock_type { - * PCXHR_CLOCK_TYPE_INTERNAL = 0, - * PCXHR_CLOCK_TYPE_WORD_CLOCK, - * PCXHR_CLOCK_TYPE_AES_SYNC, - * PCXHR_CLOCK_TYPE_AES_1, - * PCXHR_CLOCK_TYPE_AES_2, - * PCXHR_CLOCK_TYPE_AES_3, - * PCXHR_CLOCK_TYPE_AES_4, - * }; + * PCXHR_CLOCK_TYPE_INTERNAL = 0, + * PCXHR_CLOCK_TYPE_WORD_CLOCK, + * PCXHR_CLOCK_TYPE_AES_SYNC, + * PCXHR_CLOCK_TYPE_AES_1, + * PCXHR_CLOCK_TYPE_AES_2, + * PCXHR_CLOCK_TYPE_AES_3, + * PCXHR_CLOCK_TYPE_AES_4, + * PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, + * HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, + * HR22_CLOCK_TYPE_AES_SYNC, + * HR22_CLOCK_TYPE_AES_1, + * HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, + * }; */ static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[7] = { - "Internal", "WordClock", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" + static const char *textsPCXHR[7] = { + "Internal", "WordClock", "AES Sync", + "AES 1", "AES 2", "AES 3", "AES 4" }; + static const char *textsHR22[3] = { + "Internal", "AES Sync", "AES 1" + }; + const char **texts; struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); - int clock_items = 3 + mgr->capture_chips; - + int clock_items = 2; /* at least Internal and AES Sync clock */ + if (mgr->board_has_aes1) { + clock_items += mgr->capture_chips; /* add AES x */ + if (!mgr->is_hr_stereo) + clock_items += 1; /* add word clock */ + } + if (mgr->is_hr_stereo) { + texts = textsHR22; + snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1)); + } else { + texts = textsPCXHR; + snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1)); + } uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = clock_items; @@ -667,9 +776,13 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); - unsigned int clock_items = 3 + mgr->capture_chips; int rate, ret = 0; - + unsigned int clock_items = 2; /* at least Internal and AES Sync clock */ + if (mgr->board_has_aes1) { + clock_items += mgr->capture_chips; /* add AES x */ + if (!mgr->is_hr_stereo) + clock_items += 1; /* add word clock */ + } if (ucontrol->value.enumerated.item[0] >= clock_items) return -EINVAL; mutex_lock(&mgr->mixer_mutex); @@ -677,7 +790,8 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, mutex_lock(&mgr->setup_mutex); mgr->use_clock_type = ucontrol->value.enumerated.item[0]; if (mgr->use_clock_type) - pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate); + pcxhr_get_external_clock(mgr, mgr->use_clock_type, + &rate); else rate = mgr->sample_rate; if (rate) { @@ -686,7 +800,7 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, mgr->sample_rate = rate; } mutex_unlock(&mgr->setup_mutex); - ret = 1; /* return 1 even if the set was not done. ok ? */ + ret = 1; /* return 1 even if the set was not done. ok ? */ } mutex_unlock(&mgr->mixer_mutex); return ret; @@ -747,14 +861,16 @@ static struct snd_kcontrol_new pcxhr_control_clock_rate = { /* * IEC958 status bits */ -static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0; } -static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits) +static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, + int aes_idx, unsigned char *aes_bits) { int i, err; unsigned char temp; @@ -763,39 +879,61 @@ static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsign pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; switch (chip->chip_idx) { - case 0: rmh.cmd[1] = CS8420_01_CS; break; /* use CS8416_01_CS for AES SYNC plug */ + /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */ + case 0: rmh.cmd[1] = CS8420_01_CS; break; case 1: rmh.cmd[1] = CS8420_23_CS; break; case 2: rmh.cmd[1] = CS8420_45_CS; break; case 3: rmh.cmd[1] = CS8420_67_CS; break; default: return -EINVAL; } - switch (aes_idx) { - case 0: rmh.cmd[2] = CS8420_CSB0; break; /* use CS8416_CSBx for AES SYNC plug */ - case 1: rmh.cmd[2] = CS8420_CSB1; break; - case 2: rmh.cmd[2] = CS8420_CSB2; break; - case 3: rmh.cmd[2] = CS8420_CSB3; break; - case 4: rmh.cmd[2] = CS8420_CSB4; break; - default: return -EINVAL; + if (chip->mgr->board_aes_in_192k) { + switch (aes_idx) { + case 0: rmh.cmd[2] = CS8416_CSB0; break; + case 1: rmh.cmd[2] = CS8416_CSB1; break; + case 2: rmh.cmd[2] = CS8416_CSB2; break; + case 3: rmh.cmd[2] = CS8416_CSB3; break; + case 4: rmh.cmd[2] = CS8416_CSB4; break; + default: return -EINVAL; + } + } else { + switch (aes_idx) { + /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */ + case 0: rmh.cmd[2] = CS8420_CSB0; break; + case 1: rmh.cmd[2] = CS8420_CSB1; break; + case 2: rmh.cmd[2] = CS8420_CSB2; break; + case 3: rmh.cmd[2] = CS8420_CSB3; break; + case 4: rmh.cmd[2] = CS8420_CSB4; break; + default: return -EINVAL; + } } - rmh.cmd[1] &= 0x0fffff; /* size and code the chip id for the fpga */ - rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; /* chip signature + map for spi read */ + /* size and code the chip id for the fpga */ + rmh.cmd[1] &= 0x0fffff; + /* chip signature + map for spi read */ + rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) return err; - temp = 0; - for (i = 0; i < 8; i++) { - /* attention : reversed bit order (not with CS8416_01_CS) */ - temp <<= 1; - if (rmh.stat[1] & (1 << i)) - temp |= 1; + + if (chip->mgr->board_aes_in_192k) { + temp = (unsigned char)rmh.stat[1]; + } else { + temp = 0; + /* reversed bit order (not with CS8416_01_CS) */ + for (i = 0; i < 8; i++) { + temp <<= 1; + if (rmh.stat[1] & (1 << i)) + temp |= 1; + } } - snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); + snd_printdd("read iec958 AES %d byte %d = 0x%x\n", + chip->chip_idx, aes_idx, temp); *aes_bits = temp; return 0; } -static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); unsigned char aes_bits; @@ -806,7 +944,12 @@ static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v if (kcontrol->private_value == 0) /* playback */ aes_bits = chip->aes_bits[i]; else { /* capture */ - err = pcxhr_iec958_capture_byte(chip, i, &aes_bits); + if (chip->mgr->is_hr_stereo) + err = hr222_iec958_capture_byte(chip, i, + &aes_bits); + else + err = pcxhr_iec958_capture_byte(chip, i, + &aes_bits); if (err) break; } @@ -825,7 +968,8 @@ static int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits) +static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, + int aes_idx, unsigned char aes_bits) { int i, err, cmd; unsigned char new_bits = aes_bits; @@ -834,12 +978,12 @@ static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigne for (i = 0; i < 8; i++) { if ((old_bits & 0x01) != (new_bits & 0x01)) { - cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ - if(chip->chip_idx > 3) + cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ + if (chip->chip_idx > 3) /* new bit used if chip_idx>3 (PCX1222HR) */ cmd |= 1 << 22; - cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ - cmd |= (new_bits & 0x01) << 23; /* add bit value */ + cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ + cmd |= (new_bits & 0x01) << 23; /* add bit value */ pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); rmh.cmd[0] |= IO_NUM_REG_CUER; rmh.cmd[1] = cmd; @@ -867,7 +1011,12 @@ static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, mutex_lock(&chip->mgr->mixer_mutex); for (i = 0; i < 5; i++) { if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { - pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]); + if (chip->mgr->is_hr_stereo) + hr222_iec958_update_byte(chip, i, + ucontrol->value.iec958.status[i]); + else + pcxhr_iec958_update_byte(chip, i, + ucontrol->value.iec958.status[i]); changed = 1; } } @@ -917,29 +1066,53 @@ static void pcxhr_init_audio_levels(struct snd_pcxhr *chip) /* at boot time the digital volumes are unmuted 0dB */ for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { chip->digital_playback_active[j][i] = 1; - chip->digital_playback_volume[j][i] = PCXHR_DIGITAL_ZERO_LEVEL; + chip->digital_playback_volume[j][i] = + PCXHR_DIGITAL_ZERO_LEVEL; } - /* after boot, only two bits are set on the uer interface */ - chip->aes_bits[0] = IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_FS_48000; -/* only for test purpose, remove later */ + /* after boot, only two bits are set on the uer + * interface + */ + chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL | + IEC958_AES0_PRO_FS_48000); #ifdef CONFIG_SND_DEBUG - /* analog volumes for playback (is LEVEL_MIN after boot) */ + /* analog volumes for playback + * (is LEVEL_MIN after boot) + */ chip->analog_playback_active[i] = 1; - chip->analog_playback_volume[i] = PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL; - pcxhr_update_analog_audio_level(chip, 0, i); + if (chip->mgr->is_hr_stereo) + chip->analog_playback_volume[i] = + HR222_LINE_PLAYBACK_ZERO_LEVEL; + else { + chip->analog_playback_volume[i] = + PCXHR_LINE_PLAYBACK_ZERO_LEVEL; + pcxhr_update_analog_audio_level(chip, 0, i); + } #endif -/* test end */ + /* stereo cards need to be initialised after boot */ + if (chip->mgr->is_hr_stereo) + hr222_update_analog_audio_level(chip, 0, i); } if (chip->nb_streams_capt) { /* at boot time the digital volumes are unmuted 0dB */ - chip->digital_capture_volume[i] = PCXHR_DIGITAL_ZERO_LEVEL; -/* only for test purpose, remove later */ + chip->digital_capture_volume[i] = + PCXHR_DIGITAL_ZERO_LEVEL; + chip->analog_capture_active = 1; #ifdef CONFIG_SND_DEBUG - /* analog volumes for playback (is LEVEL_MIN after boot) */ - chip->analog_capture_volume[i] = PCXHR_ANALOG_CAPTURE_ZERO_LEVEL; - pcxhr_update_analog_audio_level(chip, 1, i); + /* analog volumes for playback + * (is LEVEL_MIN after boot) + */ + if (chip->mgr->is_hr_stereo) + chip->analog_capture_volume[i] = + HR222_LINE_CAPTURE_ZERO_LEVEL; + else { + chip->analog_capture_volume[i] = + PCXHR_LINE_CAPTURE_ZERO_LEVEL; + pcxhr_update_analog_audio_level(chip, 1, i); + } #endif -/* test end */ + /* stereo cards need to be initialised after boot */ + if (chip->mgr->is_hr_stereo) + hr222_update_analog_audio_level(chip, 1, i); } } @@ -963,90 +1136,125 @@ int pcxhr_create_mixer(struct pcxhr_mgr *mgr) temp = pcxhr_control_analog_level; temp.name = "Master Playback Volume"; temp.private_value = 0; /* playback */ - temp.tlv.p = db_scale_analog_playback; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + if (mgr->is_hr_stereo) + temp.tlv.p = db_scale_a_hr222_playback; + else + temp.tlv.p = db_scale_analog_playback; + err = snd_ctl_add(chip->card, + snd_ctl_new1(&temp, chip)); + if (err < 0) return err; + /* output mute controls */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_output_switch, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_output_switch, + chip)); + if (err < 0) return err; - + temp = snd_pcxhr_pcm_vol; temp.name = "PCM Playback Volume"; temp.count = PCXHR_PLAYBACK_STREAMS; temp.private_value = 0; /* playback */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&temp, chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_pcm_switch, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_pcm_switch, chip)); + if (err < 0) return err; /* IEC958 controls */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_playback_iec958_mask, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_playback_iec958_mask, + chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_playback_iec958, - chip))) < 0) + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_playback_iec958, + chip)); + if (err < 0) return err; } if (chip->nb_streams_capt) { - /* analog input level control only on first two chips !*/ + /* analog input level control */ temp = pcxhr_control_analog_level; - temp.name = "Master Capture Volume"; + temp.name = "Line Capture Volume"; temp.private_value = 1; /* capture */ - temp.tlv.p = db_scale_analog_capture; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + if (mgr->is_hr_stereo) + temp.tlv.p = db_scale_a_hr222_capture; + else + temp.tlv.p = db_scale_analog_capture; + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&temp, chip)); + if (err < 0) return err; temp = snd_pcxhr_pcm_vol; temp.name = "PCM Capture Volume"; temp.count = 1; temp.private_value = 1; /* capture */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&temp, chip)); + if (err < 0) return err; + /* Audio source */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_audio_src, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_audio_src, chip)); + if (err < 0) return err; + /* IEC958 controls */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_capture_iec958_mask, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_capture_iec958_mask, + chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_capture_iec958, - chip))) < 0) + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_capture_iec958, + chip)); + if (err < 0) return err; + + if (mgr->is_hr_stereo) { + err = hr222_add_mic_controls(chip); + if (err < 0) + return err; + } } /* monitoring only if playback and capture device available */ if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { /* monitoring */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_monitor_vol, - chip))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_monitor_vol, chip)); + if (err < 0) return err; - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_monitor_sw, - chip))) < 0) + + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_monitor_sw, chip)); + if (err < 0) return err; } if (i == 0) { /* clock mode only one control per pcxhr */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_clock_type, - mgr))) < 0) + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_clock_type, mgr)); + if (err < 0) return err; - /* non standard control used to scan the external clock presence/frequencies */ - if ((err = snd_ctl_add(chip->card, - snd_ctl_new1(&pcxhr_control_clock_rate, - mgr))) < 0) + /* non standard control used to scan + * the external clock presence/frequencies + */ + err = snd_ctl_add(chip->card, + snd_ctl_new1(&pcxhr_control_clock_rate, mgr)); + if (err < 0) return err; } From ee09543c866559e1ffb4f5c38533f2bedd725acd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2008 15:03:38 +0100 Subject: [PATCH 193/367] ALSA: hda - Add quirk for MSI 7260 mobo Added preset model=targa-dig for MSI 7260 mobo. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f52e271edd57..4afa0c9b9b6e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8473,6 +8473,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), From b0e6481a9ae9e8c80b5d956980767ecad35c95c1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Nov 2008 16:07:01 +0100 Subject: [PATCH 194/367] ALSA: hda - Really fix bits value in proc output The fix in 82894b6f6f109722070d4d78730fe50cdaba9443 resulted in zero due to wrong mask and bit shifts. Now fixed really. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index a2eba4f17e9c..9a8498456e6c 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -103,7 +103,7 @@ static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; - snd_iprintf(buffer, " bits [0x%x]:", (pcm & AC_SUPPCM_RATES) >> 16); + snd_iprintf(buffer, " bits [0x%x]:", (pcm >> 16) & 0xff); snd_print_pcm_bits(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); } From 0be43050d4da08295b985cb23347ecc1003cb8d6 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 25 Nov 2008 12:45:08 +0200 Subject: [PATCH 195/367] ASoC: OMAP: Apply channel constrains to N810 machine driver Prepare for upcoming McBSP DAI update adding support for mono links by restricting number of channels to 2 in N810. This is due tlv320aic3x which claims channels_min = 1 and playing pure mono audio over I2S would cause it to be played only from left channel if both cpu and codec DAI's claim to support mono. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/n810.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index d216b4f9e14e..18e2062e3a11 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -70,9 +70,13 @@ static void n810_ext_control(struct snd_soc_codec *codec) static int n810_startup(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_codec *codec = rtd->socdev->codec; + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); + n810_ext_control(codec); return clk_enable(sys_clkout2); } From 375e8a7c943d5aa8716be229e398473b23709ce9 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 25 Nov 2008 12:45:09 +0200 Subject: [PATCH 196/367] ASoC: OMAP: Add support for mono audio links in McBSP DAI Patch adds support for mono audio links so that McBSP DAI can operate with real mono codecs. In I2S, the signalling remains the same but only first frame (left channel) is transmitting audio data and second frame having null data. In DSP_A, only first frame is transmitted. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/omap/omap-mcbsp.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 252bc7ebb194..e8f1314762d7 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -203,7 +203,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; - int wlen; + int wlen, channels; unsigned long port; if (cpu_class_is_omap1()) { @@ -232,12 +232,17 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, return 0; } - switch (params_channels(params)) { + channels = params_channels(params); + switch (channels) { case 2: - /* Set 1 word per (McBPSP) frame and use dual-phase frames */ - regs->rcr2 |= RFRLEN2(1 - 1) | RPHASE; + /* Use dual-phase frames */ + regs->rcr2 |= RPHASE; + regs->xcr2 |= XPHASE; + case 1: + /* Set 1 word per (McBSP) frame */ + regs->rcr2 |= RFRLEN2(1 - 1); regs->rcr1 |= RFRLEN1(1 - 1); - regs->xcr2 |= XFRLEN2(1 - 1) | XPHASE; + regs->xcr2 |= XFRLEN2(1 - 1); regs->xcr1 |= XFRLEN1(1 - 1); break; default: @@ -266,8 +271,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, regs->srgr1 |= FWID(wlen - 1); break; case SND_SOC_DAIFMT_DSP_A: - regs->srgr2 |= FPER(wlen * 2 - 1); - regs->srgr1 |= FWID(wlen * 2 - 2); + regs->srgr2 |= FPER(wlen * channels - 1); + regs->srgr1 |= FWID(wlen * channels - 2); break; } @@ -457,13 +462,13 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, .name = "omap-mcbsp-dai-"#link_id, \ .id = (link_id), \ .playback = { \ - .channels_min = 2, \ + .channels_min = 1, \ .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ }, \ .capture = { \ - .channels_min = 2, \ + .channels_min = 1, \ .channels_max = 2, \ .rates = OMAP_MCBSP_RATES, \ .formats = SNDRV_PCM_FMTBIT_S16_LE, \ From 9c8f1a0e6ed48f2ecf08ac0fb7fb043f8c34dc63 Mon Sep 17 00:00:00 2001 From: Arun KS Date: Tue, 25 Nov 2008 09:56:12 +0530 Subject: [PATCH 197/367] ASoC: Fix TWL4030 Kconfig dependency Fixes Kconfig dependency of TWL4030 audio codec driver with TWL4030 core driver on both overo and omap2evm boards Signed-off-by: Arun KS Acked-by: David Brownell Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 6c56277e160b..090043702e80 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -24,7 +24,7 @@ config SND_OMAP_SOC_OSK5912 config SND_OMAP_SOC_OVERO tristate "SoC Audio support for Gumstix Overo" - depends on SND_OMAP_SOC && MACH_OVERO + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OVERO select SND_OMAP_SOC_MCBSP select SND_SOC_TWL4030 help @@ -32,7 +32,7 @@ config SND_OMAP_SOC_OVERO config SND_OMAP_SOC_OMAP2EVM tristate "SoC Audio support for OMAP2EVM board" - depends on SND_OMAP_SOC && MACH_OMAP2EVM + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP2EVM select SND_OMAP_SOC_MCBSP select SND_SOC_TWL4030 help From 4451582f7e9fc2860b289aca60a6065286439bb8 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Mon, 24 Nov 2008 22:21:23 -0600 Subject: [PATCH 198/367] ASoC: Add support for TI SDP3430 This patch add ASoC support for TI SDP3430. It's based on Gumstix Overo SoC code by Steve Sakoman. Signed-off-by: Misael Lopez Cruz Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 7 ++ sound/soc/omap/Makefile | 3 +- sound/soc/omap/sdp3430.c | 152 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 sound/soc/omap/sdp3430.c diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 090043702e80..1cd0176811c5 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -38,5 +38,12 @@ config SND_OMAP_SOC_OMAP2EVM help Say Y if you want to add support for SoC audio on the omap2evm board. +config SND_OMAP_SOC_SDP3430 + tristate "SoC Audio support for Texas Instruments SDP3430" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_3430SDP + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on Texas Instruments SDP3430. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index f5da3cc764ae..29cf3a856c89 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -10,9 +10,10 @@ snd-soc-n810-objs := n810.o snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o snd-soc-omap2evm-objs := omap2evm.o +snd-soc-sdp3430-objs := sdp3430.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o - +obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c new file mode 100644 index 000000000000..85fd160bca17 --- /dev/null +++ b/sound/soc/omap/sdp3430.c @@ -0,0 +1,152 @@ +/* + * sdp3430.c -- SoC audio for TI OMAP3430 SDP + * + * Author: Misael Lopez Cruz + * + * Based on: + * Author: Steve Sakoman + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +static int sdp3430_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM); + if (ret < 0) { + printk(KERN_ERR "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "can't set codec system clock\n"); + return ret; + } + + return 0; +} + +static struct snd_soc_ops sdp3430_ops = { + .hw_params = sdp3430_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link sdp3430_dai = { + .name = "TWL4030", + .stream_name = "TWL4030", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &sdp3430_ops, +}; + +/* Audio machine driver */ +static struct snd_soc_machine snd_soc_machine_sdp3430 = { + .name = "SDP3430", + .dai_link = &sdp3430_dai, + .num_links = 1, +}; + +/* Audio subsystem */ +static struct snd_soc_device sdp3430_snd_devdata = { + .machine = &snd_soc_machine_sdp3430, + .platform = &omap_soc_platform, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *sdp3430_snd_device; + +static int __init sdp3430_soc_init(void) +{ + int ret; + + if (!machine_is_omap_3430sdp()) { + pr_debug("Not SDP3430!\n"); + return -ENODEV; + } + printk(KERN_INFO "SDP3430 SoC init\n"); + + sdp3430_snd_device = platform_device_alloc("soc-audio", -1); + if (!sdp3430_snd_device) { + printk(KERN_ERR "Platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(sdp3430_snd_device, &sdp3430_snd_devdata); + sdp3430_snd_devdata.dev = &sdp3430_snd_device->dev; + *(unsigned int *)sdp3430_dai.cpu_dai->private_data = 1; /* McBSP2 */ + + ret = platform_device_add(sdp3430_snd_device); + if (ret) + goto err1; + + return 0; + +err1: + printk(KERN_ERR "Unable to add platform device\n"); + platform_device_put(sdp3430_snd_device); + + return ret; +} +module_init(sdp3430_soc_init); + +static void __exit sdp3430_soc_exit(void) +{ + platform_device_unregister(sdp3430_snd_device); +} +module_exit(sdp3430_soc_exit); + +MODULE_AUTHOR("Misael Lopez Cruz "); +MODULE_DESCRIPTION("ALSA SoC SDP3430"); +MODULE_LICENSE("GPL"); + From 5c0d7bb797a975691ca8bbc38e53da03c6e151bb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 25 Nov 2008 09:35:21 +0300 Subject: [PATCH 199/367] ASoC: tosa: move gpio probing to machine callbacks Signed-off-by: Dmitry Baryshkov Signed-off-by: Mark Brown --- sound/soc/pxa/tosa.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 9d9be5a14d14..48242b32a28b 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -230,10 +230,32 @@ static struct snd_soc_dai_link tosa_dai[] = { }, }; +static int tosa_probe(struct platform_device *dev) +{ + int ret; + + ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); + if (ret) + return ret; + ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0); + if (ret) + gpio_free(TOSA_GPIO_L_MUTE); + + return ret; +} + +static int tosa_remove(struct platform_device *dev) +{ + gpio_free(TOSA_GPIO_L_MUTE); + return 0; +} + static struct snd_soc_card tosa = { .name = "Tosa", .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), + .probe = tosa_probe, + .remove = tosa_remove, }; static struct snd_soc_device tosa_snd_devdata = { @@ -251,11 +273,6 @@ static int __init tosa_init(void) if (!machine_is_tosa()) return -ENODEV; - ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); - if (ret) - return ret; - gpio_direction_output(TOSA_GPIO_L_MUTE, 0); - tosa_snd_device = platform_device_alloc("soc-audio", -1); if (!tosa_snd_device) { ret = -ENOMEM; @@ -272,15 +289,12 @@ static int __init tosa_init(void) platform_device_put(tosa_snd_device); err_alloc: - gpio_free(TOSA_GPIO_L_MUTE); - return ret; } static void __exit tosa_exit(void) { platform_device_unregister(tosa_snd_device); - gpio_free(TOSA_GPIO_L_MUTE); } module_init(tosa_init); From 9e0f1b7f6bc5265847e995540981642c857f15b6 Mon Sep 17 00:00:00 2001 From: Qinghuang Feng Date: Tue, 25 Nov 2008 23:24:54 +0800 Subject: [PATCH 200/367] ASoC: Clean up kernel-doc for snd_soc_dai_set_fmt There is no argument named @clk_id in snd_soc_dai_set_fmt, remove its' comment. Signed-off-by: Qinghuang Feng Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dbd92e12e860..00fccdd41bb0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1883,7 +1883,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); /** * snd_soc_dai_set_fmt - configure DAI hardware audio format. * @dai: DAI - * @clk_id: DAI specific clock ID * @fmt: SND_SOC_DAIFMT_ format value. * * Configures the DAI hardware format and clocking. From 4f199629b0fba95fd5caecbf35ed68417d9a9b7a Mon Sep 17 00:00:00 2001 From: Qinghuang Feng Date: Tue, 25 Nov 2008 23:24:49 +0800 Subject: [PATCH 201/367] ALSA: sound/pci/hda/hda_codec.c: cleanup kernel-doc There is no argument named @state in snd_hda_resume, remove its' comment. Signed-off-by: Qinghuang Feng Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 53f64eb75ec6..1131c86ad495 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3358,7 +3358,6 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) /** * snd_hda_resume - resume the codecs * @bus: the HDA bus - * @state: resume state * * Returns 0 if successful. * From 414ff491b2ab68359c7a2037b30ccfea20d829d4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Nov 2008 10:32:26 +0000 Subject: [PATCH 202/367] ASoC: Fix word wrapping in OMAP Kconfig Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 1cd0176811c5..9a869390abb9 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -44,6 +44,5 @@ config SND_OMAP_SOC_SDP3430 select SND_OMAP_SOC_MCBSP select SND_SOC_TWL4030 help - Say Y if you want to add support for SoC audio on Texas Instruments SDP3430. - - + Say Y if you want to add support for SoC audio on Texas Instruments + SDP3430. From eea0579fc85e64e9f05361d5aacf496fe7a151aa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 26 Nov 2008 14:13:03 +0100 Subject: [PATCH 203/367] ALSA: pcsp - Fix starting the stream with HRTIMER_CB_IRQSAFE_UNLOCK With the callback mode HRTIMER_CB_IRQSAFE_UNLOCK, the start of the stream with zero delay doesn't work. Since IRQSAFE mode is removed, we have to change the pcsp start-up code. This patch splits the callback function to two parts, the triggering of the port and the calculation of the expire time, and the update of the ALSA PCM core. The first part is called both from the trigger-start and the hrtimer callback while the latter is handled only in the hrtimer callback. Signed-off-by: Takashi Iwai --- sound/drivers/pcsp/pcsp.h | 2 + sound/drivers/pcsp/pcsp_lib.c | 87 ++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h index 70533a333b5b..cdef2664218f 100644 --- a/sound/drivers/pcsp/pcsp.h +++ b/sound/drivers/pcsp/pcsp.h @@ -62,6 +62,8 @@ struct snd_pcsp { unsigned short port, irq, dma; spinlock_t substream_lock; struct snd_pcm_substream *playback_substream; + unsigned int fmt_size; + unsigned int is_signed; size_t playback_ptr; size_t period_ptr; atomic_t timer_active; diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index f8d8470861da..84cc2658c05b 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -36,12 +36,13 @@ static void pcsp_call_pcm_elapsed(unsigned long priv) static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); -enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) +/* write the port and returns the next expire time in ns; + * called at the trigger-start and in hrtimer callback + */ +static unsigned long pcsp_timer_update(struct hrtimer *handle) { unsigned char timer_cnt, val; - int fmt_size, periods_elapsed; u64 ns; - size_t period_bytes, buffer_bytes; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); @@ -51,28 +52,25 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) outb(chip->val61, 0x61); chip->thalf = 0; if (!atomic_read(&chip->timer_active)) - goto stop; - hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer), - ktime_set(0, chip->ns_rem)); - return HRTIMER_RESTART; + return 0; + return chip->ns_rem; } if (!atomic_read(&chip->timer_active)) - goto stop; + return 0; substream = chip->playback_substream; if (!substream) - goto stop; + return 0; runtime = substream->runtime; - fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3; /* assume it is mono! */ - val = runtime->dma_area[chip->playback_ptr + fmt_size - 1]; - if (snd_pcm_format_signed(runtime->format)) + val = runtime->dma_area[chip->playback_ptr + chip->fmt_size - 1]; + if (chip->is_signed) val ^= 0x80; timer_cnt = val * CUR_DIV() / 256; if (timer_cnt && chip->enable) { - spin_lock(&i8253_lock); + spin_lock_irqsave(&i8253_lock, flags); if (!nforce_wa) { outb_p(chip->val61, 0x61); outb_p(timer_cnt, 0x42); @@ -81,14 +79,39 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) outb(chip->val61 ^ 2, 0x61); chip->thalf = 1; } - spin_unlock(&i8253_lock); + spin_unlock_irqrestore(&i8253_lock, flags); } + chip->ns_rem = PCSP_PERIOD_NS(); + ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); + chip->ns_rem -= ns; + return ns; +} + +enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) +{ + struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); + struct snd_pcm_substream *substream; + int periods_elapsed, pointer_update; + size_t period_bytes, buffer_bytes; + unsigned long ns; + unsigned long flags; + + pointer_update = !chip->thalf; + ns = pcsp_timer_update(handle); + if (!ns) + return HRTIMER_NORESTART; + + /* update the playback position */ + substream = chip->playback_substream; + if (!substream) + return HRTIMER_NORESTART; + period_bytes = snd_pcm_lib_period_bytes(substream); buffer_bytes = snd_pcm_lib_buffer_bytes(substream); spin_lock_irqsave(&chip->substream_lock, flags); - chip->playback_ptr += PCSP_INDEX_INC() * fmt_size; + chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size; periods_elapsed = chip->playback_ptr - chip->period_ptr; if (periods_elapsed < 0) { #if PCSP_DEBUG @@ -106,32 +129,27 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) if (periods_elapsed) { chip->period_ptr += periods_elapsed * period_bytes; chip->period_ptr %= buffer_bytes; - tasklet_schedule(&pcsp_pcm_tasklet); } spin_unlock_irqrestore(&chip->substream_lock, flags); - if (!atomic_read(&chip->timer_active)) - goto stop; + if (periods_elapsed) + tasklet_schedule(&pcsp_pcm_tasklet); + + hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns)); - chip->ns_rem = PCSP_PERIOD_NS(); - ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem); - chip->ns_rem -= ns; - hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer), - ktime_set(0, ns)); return HRTIMER_RESTART; - - stop: - return HRTIMER_NORESTART; } -static void pcsp_start_playing(struct snd_pcsp *chip) +static int pcsp_start_playing(struct snd_pcsp *chip) { + unsigned long ns; + #if PCSP_DEBUG printk(KERN_INFO "PCSP: start_playing called\n"); #endif if (atomic_read(&chip->timer_active)) { printk(KERN_ERR "PCSP: Timer already active\n"); - return; + return -EIO; } spin_lock(&i8253_lock); @@ -141,7 +159,12 @@ static void pcsp_start_playing(struct snd_pcsp *chip) atomic_set(&chip->timer_active, 1); chip->thalf = 0; - hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL); + ns = pcsp_timer_update(&pcsp_chip.timer); + if (!ns) + return -EIO; + + hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL); + return 0; } static void pcsp_stop_playing(struct snd_pcsp *chip) @@ -221,6 +244,9 @@ static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream) pcsp_sync_stop(chip); chip->playback_ptr = 0; chip->period_ptr = 0; + chip->fmt_size = + snd_pcm_format_physical_width(substream->runtime->format) >> 3; + chip->is_signed = snd_pcm_format_signed(substream->runtime->format); return 0; } @@ -233,8 +259,7 @@ static int snd_pcsp_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - pcsp_start_playing(chip); - break; + return pcsp_start_playing(chip); case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: pcsp_stop_playing(chip); From 54f01916297bafc18bd7df4e2300a0544a84fce3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 26 Nov 2008 17:47:36 +0100 Subject: [PATCH 204/367] ASoC: Allow more routing features for tlv320aic3x This patch enables more routing functions for tlv320aic3x codecs. It is now possible to - control the volume of the PGA bypass path for the HPL, HPR, HPLCOM and HPRCOM outputs individually - route right line1 input to the left ADC channel - route left line1 input to the right ADC channel - route right mic3 input to left DAC channel - route left mic3 input to right DAC channel - route left line1 input to right line1 output - route right line1 input to left line1 output Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 96 +++++++++++++++++++++++----------- sound/soc/codecs/tlv320aic3x.h | 12 +++++ 2 files changed, 78 insertions(+), 30 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index b76bcc3c4110..255e784c805b 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -272,8 +272,10 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPROUT_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R("HP PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, - PGAR_2_HPROUT_VOL, 0, 0x7f, 1), + SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, + 0, 0x7f, 1), + SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL, + 0, 0x7f, 1), SOC_DOUBLE_R("HP Line2 Bypass Playback Volume", LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL, 0, 0x7f, 1), @@ -281,8 +283,10 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPRCOM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HPCOM DAC Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3, 0x01, 0), - SOC_DOUBLE_R("HPCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, - PGAR_2_HPRCOM_VOL, 0, 0x7f, 1), + SOC_SINGLE("HPLCOM PGA Bypass Playback Volume", PGAL_2_HPLCOM_VOL, + 0, 0x7f, 1), + SOC_SINGLE("HPRCOM PGA Bypass Playback Volume", PGAL_2_HPRCOM_VOL, + 0, 0x7f, 1), SOC_DOUBLE_R("HPCOM Line2 Bypass Playback Volume", LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL, 0, 0x7f, 1), @@ -333,7 +337,8 @@ SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); /* Left DAC_L1 Mixer */ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", DACL1_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", DACL1_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", DACL1_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HPCOM Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0), @@ -341,7 +346,8 @@ static const struct snd_kcontrol_new aic3x_left_dac_mixer_controls[] = { /* Right DAC_R1 Mixer */ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", DACR1_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", DACR1_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", DACR1_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", DACR1_2_HPROUT_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HPCOM Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0), @@ -350,14 +356,18 @@ static const struct snd_kcontrol_new aic3x_right_dac_mixer_controls[] = { /* Left PGA Mixer */ static const struct snd_kcontrol_new aic3x_left_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Line2L Switch", LINE2L_2_LADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1), }; /* Right PGA Mixer */ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1), SOC_DAPM_SINGLE_AIC3X("Line2R Switch", LINE2R_2_RADC_CTRL, 3, 1, 1), + SOC_DAPM_SINGLE_AIC3X("Mic3L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1), SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1), }; @@ -379,34 +389,42 @@ SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); /* Left PGA Bypass Mixer */ static const struct snd_kcontrol_new aic3x_left_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", PGAL_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", PGAL_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", PGAL_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HP Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPL Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPR Switch", PGAL_2_HPROUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPLCOM Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPRCOM Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0), }; /* Right PGA Bypass Mixer */ static const struct snd_kcontrol_new aic3x_right_pga_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", PGAR_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", PGAR_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", PGAR_2_MONOLOPM_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HP Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPL Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPR Switch", PGAR_2_HPROUT_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPLCOM Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPRCOM Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0), }; /* Left Line2 Bypass Mixer */ static const struct snd_kcontrol_new aic3x_left_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", LINE2L_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPLCOM Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0), }; /* Right Line2 Bypass Mixer */ static const struct snd_kcontrol_new aic3x_right_line2_bp_mixer_controls[] = { - SOC_DAPM_SINGLE("Line Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineL Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("LineR Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("Mono Switch", LINE2R_2_MONOLOPM_VOL, 7, 1, 0), SOC_DAPM_SINGLE("HP Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0), - SOC_DAPM_SINGLE("HPCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), + SOC_DAPM_SINGLE("HPRCOM Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0), }; static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { @@ -439,22 +457,26 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { /* Mono Output */ SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0), - /* Left Inputs to Left ADC */ + /* Inputs to Left ADC */ SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0), SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0, &aic3x_left_pga_mixer_controls[0], ARRAY_SIZE(aic3x_left_pga_mixer_controls)), SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line1_mux_controls), + SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, + &aic3x_left_line1_mux_controls), SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, &aic3x_left_line2_mux_controls), - /* Right Inputs to Right ADC */ + /* Inputs to Right ADC */ SND_SOC_DAPM_ADC("Right ADC", "Right Capture", LINE1R_2_RADC_CTRL, 2, 0), SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0, &aic3x_right_pga_mixer_controls[0], ARRAY_SIZE(aic3x_right_pga_mixer_controls)), + SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, + &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, &aic3x_right_line1_mux_controls), SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, @@ -531,7 +553,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left DAC Mux", "DAC_L2", "Left DAC"}, {"Left DAC Mux", "DAC_L3", "Left DAC"}, - {"Left DAC_L1 Mixer", "Line Switch", "Left DAC Mux"}, + {"Left DAC_L1 Mixer", "LineL Switch", "Left DAC Mux"}, + {"Left DAC_L1 Mixer", "LineR Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "Mono Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "HP Switch", "Left DAC Mux"}, {"Left DAC_L1 Mixer", "HPCOM Switch", "Left DAC Mux"}, @@ -557,7 +580,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right DAC Mux", "DAC_R2", "Right DAC"}, {"Right DAC Mux", "DAC_R3", "Right DAC"}, - {"Right DAC_R1 Mixer", "Line Switch", "Right DAC Mux"}, + {"Right DAC_R1 Mixer", "LineL Switch", "Right DAC Mux"}, + {"Right DAC_R1 Mixer", "LineR Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "Mono Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "HP Switch", "Right DAC Mux"}, {"Right DAC_R1 Mixer", "HPCOM Switch", "Right DAC Mux"}, @@ -592,8 +616,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left Line2L Mux", "differential", "LINE2L"}, {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, + {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"}, {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, + {"Left PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Left ADC", NULL, "Left PGA Mixer"}, {"Left ADC", NULL, "GPIO1 dmic modclk"}, @@ -605,18 +631,23 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right Line2R Mux", "single-ended", "LINE2R"}, {"Right Line2R Mux", "differential", "LINE2R"}, + {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"}, {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"}, {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"}, + {"Right PGA Mixer", "Mic3L Switch", "MIC3L"}, {"Right PGA Mixer", "Mic3R Switch", "MIC3R"}, {"Right ADC", NULL, "Right PGA Mixer"}, {"Right ADC", NULL, "GPIO1 dmic modclk"}, /* Left PGA Bypass */ - {"Left PGA Bypass Mixer", "Line Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "LineL Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "LineR Switch", "Left PGA Mixer"}, {"Left PGA Bypass Mixer", "Mono Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HP Switch", "Left PGA Mixer"}, - {"Left PGA Bypass Mixer", "HPCOM Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPL Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPR Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPLCOM Switch", "Left PGA Mixer"}, + {"Left PGA Bypass Mixer", "HPRCOM Switch", "Left PGA Mixer"}, {"Left HPCOM Mux", "differential of HPLOUT", "Left PGA Bypass Mixer"}, {"Left HPCOM Mux", "constant VCM", "Left PGA Bypass Mixer"}, @@ -627,10 +658,13 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left HP Out", NULL, "Left PGA Bypass Mixer"}, /* Right PGA Bypass */ - {"Right PGA Bypass Mixer", "Line Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "LineL Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "LineR Switch", "Right PGA Mixer"}, {"Right PGA Bypass Mixer", "Mono Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HP Switch", "Right PGA Mixer"}, - {"Right PGA Bypass Mixer", "HPCOM Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPL Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPR Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPLCOM Switch", "Right PGA Mixer"}, + {"Right PGA Bypass Mixer", "HPRCOM Switch", "Right PGA Mixer"}, {"Right HPCOM Mux", "differential of HPROUT", "Right PGA Bypass Mixer"}, {"Right HPCOM Mux", "constant VCM", "Right PGA Bypass Mixer"}, @@ -643,10 +677,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right HP Out", NULL, "Right PGA Bypass Mixer"}, /* Left Line2 Bypass */ - {"Left Line2 Bypass Mixer", "Line Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "LineL Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "LineR Switch", "Left Line2L Mux"}, {"Left Line2 Bypass Mixer", "Mono Switch", "Left Line2L Mux"}, {"Left Line2 Bypass Mixer", "HP Switch", "Left Line2L Mux"}, - {"Left Line2 Bypass Mixer", "HPCOM Switch", "Left Line2L Mux"}, + {"Left Line2 Bypass Mixer", "HPLCOM Switch", "Left Line2L Mux"}, {"Left HPCOM Mux", "differential of HPLOUT", "Left Line2 Bypass Mixer"}, {"Left HPCOM Mux", "constant VCM", "Left Line2 Bypass Mixer"}, @@ -657,10 +692,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left HP Out", NULL, "Left Line2 Bypass Mixer"}, /* Right Line2 Bypass */ - {"Right Line2 Bypass Mixer", "Line Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "LineL Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "LineR Switch", "Right Line2R Mux"}, {"Right Line2 Bypass Mixer", "Mono Switch", "Right Line2R Mux"}, {"Right Line2 Bypass Mixer", "HP Switch", "Right Line2R Mux"}, - {"Right Line2 Bypass Mixer", "HPCOM Switch", "Right Line2R Mux"}, + {"Right Line2 Bypass Mixer", "HPRCOM Switch", "Right Line2R Mux"}, {"Right HPCOM Mux", "differential of HPROUT", "Right Line2 Bypass Mixer"}, {"Right HPCOM Mux", "constant VCM", "Right Line2 Bypass Mixer"}, diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 00a195aa02e4..7e982acf3996 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -48,7 +48,9 @@ #define MIC3LR_2_RADC_CTRL 18 /* Line1 Input control registers */ #define LINE1L_2_LADC_CTRL 19 +#define LINE1R_2_LADC_CTRL 21 #define LINE1R_2_RADC_CTRL 22 +#define LINE1L_2_RADC_CTRL 24 /* Line2 Input control registers */ #define LINE2L_2_LADC_CTRL 20 #define LINE2R_2_RADC_CTRL 23 @@ -79,6 +81,8 @@ #define LINE2L_2_HPLOUT_VOL 45 #define LINE2R_2_HPROUT_VOL 62 #define PGAL_2_HPLOUT_VOL 46 +#define PGAL_2_HPROUT_VOL 60 +#define PGAR_2_HPLOUT_VOL 49 #define PGAR_2_HPROUT_VOL 63 #define DACL1_2_HPLOUT_VOL 47 #define DACR1_2_HPROUT_VOL 64 @@ -88,6 +92,8 @@ #define LINE2L_2_HPLCOM_VOL 52 #define LINE2R_2_HPRCOM_VOL 69 #define PGAL_2_HPLCOM_VOL 53 +#define PGAR_2_HPLCOM_VOL 56 +#define PGAL_2_HPRCOM_VOL 67 #define PGAR_2_HPRCOM_VOL 70 #define DACL1_2_HPLCOM_VOL 54 #define DACR1_2_HPRCOM_VOL 71 @@ -103,11 +109,17 @@ #define MONOLOPM_CTRL 79 /* Line Output Plus/Minus control registers */ #define LINE2L_2_LLOPM_VOL 80 +#define LINE2L_2_RLOPM_VOL 87 +#define LINE2R_2_LLOPM_VOL 83 #define LINE2R_2_RLOPM_VOL 90 #define PGAL_2_LLOPM_VOL 81 +#define PGAL_2_RLOPM_VOL 88 +#define PGAR_2_LLOPM_VOL 84 #define PGAR_2_RLOPM_VOL 91 #define DACL1_2_LLOPM_VOL 82 +#define DACL1_2_RLOPM_VOL 89 #define DACR1_2_RLOPM_VOL 92 +#define DACR1_2_LLOPM_VOL 85 #define LLOPM_CTRL 86 #define RLOPM_CTRL 93 /* GPIO/IRQ registers */ From 12666f050b3b4b122f61ef12707f33fadb4a78b5 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Thu, 27 Nov 2008 08:21:05 +0100 Subject: [PATCH 205/367] ALSA: snd-usb-caiaq: clean up the control adding code snd-usb-caiaq: clean up the control adding code by moving dulpicate code to a function. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- sound/usb/caiaq/caiaq-control.c | 103 ++++++++++++++------------------ sound/usb/caiaq/caiaq-device.c | 2 +- 2 files changed, 46 insertions(+), 59 deletions(-) diff --git a/sound/usb/caiaq/caiaq-control.c b/sound/usb/caiaq/caiaq-control.c index 798ca124da58..ccd763dd7167 100644 --- a/sound/usb/caiaq/caiaq-control.c +++ b/sound/usb/caiaq/caiaq-control.c @@ -247,69 +247,56 @@ static struct caiaq_controller a8dj_controller[] = { { "Software lock", 40 } }; -int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) +static int __devinit add_controls(struct caiaq_controller *c, int num, + struct snd_usb_caiaqdev *dev) { - int i; + int i, ret; struct snd_kcontrol *kc; - switch (dev->chip.usb_id) { - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): - for (i = 0; i < ARRAY_SIZE(ak1_controller); i++) { - struct caiaq_controller *c = ak1_controller + i; - kcontrol_template.name = c->name; - kcontrol_template.private_value = c->index; - kc = snd_ctl_new1(&kcontrol_template, dev); - snd_ctl_add(dev->chip.card, kc); - } - - break; - - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): - for (i = 0; i < ARRAY_SIZE(rk2_controller); i++) { - struct caiaq_controller *c = rk2_controller + i; - kcontrol_template.name = c->name; - kcontrol_template.private_value = c->index; - kc = snd_ctl_new1(&kcontrol_template, dev); - snd_ctl_add(dev->chip.card, kc); - } - - break; - - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): - for (i = 0; i < ARRAY_SIZE(rk3_controller); i++) { - struct caiaq_controller *c = rk3_controller + i; - kcontrol_template.name = c->name; - kcontrol_template.private_value = c->index; - kc = snd_ctl_new1(&kcontrol_template, dev); - snd_ctl_add(dev->chip.card, kc); - } - - break; - - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): - for (i = 0; i < ARRAY_SIZE(kore_controller); i++) { - struct caiaq_controller *c = kore_controller + i; - kcontrol_template.name = c->name; - kcontrol_template.private_value = c->index; - kc = snd_ctl_new1(&kcontrol_template, dev); - snd_ctl_add(dev->chip.card, kc); - } - - break; - - case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): - for (i = 0; i < ARRAY_SIZE(a8dj_controller); i++) { - struct caiaq_controller *c = a8dj_controller + i; - kcontrol_template.name = c->name; - kcontrol_template.private_value = c->index; - kc = snd_ctl_new1(&kcontrol_template, dev); - snd_ctl_add(dev->chip.card, kc); - } - - break; + for (i = 0; i < num; i++, c++) { + kcontrol_template.name = c->name; + kcontrol_template.private_value = c->index; + kc = snd_ctl_new1(&kcontrol_template, dev); + ret = snd_ctl_add(dev->chip.card, kc); + if (ret < 0) + return ret; } return 0; } +int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) +{ + int ret = 0; + + switch (dev->chip.usb_id) { + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): + ret = add_controls(ak1_controller, + ARRAY_SIZE(ak1_controller), dev); + break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): + ret = add_controls(rk2_controller, + ARRAY_SIZE(rk2_controller), dev); + break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): + ret = add_controls(rk3_controller, + ARRAY_SIZE(rk3_controller), dev); + break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): + ret = add_controls(kore_controller, + ARRAY_SIZE(kore_controller), dev); + break; + + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): + ret = add_controls(a8dj_controller, + ARRAY_SIZE(a8dj_controller), dev); + break; + } + + return ret; +} + diff --git a/sound/usb/caiaq/caiaq-device.c b/sound/usb/caiaq/caiaq-device.c index 83175083e50f..b143ef7152f7 100644 --- a/sound/usb/caiaq/caiaq-device.c +++ b/sound/usb/caiaq/caiaq-device.c @@ -42,7 +42,7 @@ #endif MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("caiaq USB audio, version 1.3.8"); +MODULE_DESCRIPTION("caiaq USB audio, version 1.3.9"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," "{Native Instruments, RigKontrol3}," From 986862bdf17655d012f9b0654925dccdcc4183c9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 12:40:13 +0100 Subject: [PATCH 206/367] ALSA: hda - make some functions static Minor clean ups: move snd_hda_codecs_inuse() into hda_intel.c and make static. Also, make snd_hda_query_supported_pcm() static as it's used only in hda_codec.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 14 +------------- sound/pci/hda/hda_codec.h | 4 ---- sound/pci/hda/hda_intel.c | 13 +++++++++++++ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1131c86ad495..f84874445b50 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2218,7 +2218,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, * * Returns 0 if successful, otherwise a negative error code. */ -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, +static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp) { int i; @@ -3374,18 +3374,6 @@ int snd_hda_resume(struct hda_bus *bus) } return 0; } -#ifdef CONFIG_SND_HDA_POWER_SAVE -int snd_hda_codecs_inuse(struct hda_bus *bus) -{ - struct hda_codec *codec; - - list_for_each_entry(codec, &bus->codec_list, list) { - if (snd_hda_codec_needs_resume(codec)) - return 1; - } - return 0; -} -#endif #endif /* diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index a70b181bbace..e1077df5e882 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -852,8 +852,6 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, unsigned int channels, unsigned int format, unsigned int maxbps); -int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, - u32 *ratesp, u64 *formatsp, unsigned int *bpsp); int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, unsigned int format); @@ -884,12 +882,10 @@ const char *snd_hda_get_jack_location(u32 cfg); void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); #define snd_hda_codec_needs_resume(codec) codec->power_count -int snd_hda_codecs_inuse(struct hda_bus *bus); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} #define snd_hda_codec_needs_resume(codec) 1 -#define snd_hda_codecs_inuse(bus) 1 #endif #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6462d758e641..f13ec4c71f8a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1896,6 +1896,19 @@ static void azx_power_notify(struct hda_bus *bus) else if (chip->running && power_save_controller) azx_stop_chip(chip); } + +static int snd_hda_codecs_inuse(struct hda_bus *bus) +{ + struct hda_codec *codec; + + list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; + } + return 0; +} +#else /* !CONFIG_SND_HDA_POWER_SAVE */ +#define snd_hda_codecs_inuse(bus) 1 #endif /* CONFIG_SND_HDA_POWER_SAVE */ #ifdef CONFIG_PM From fee2fba3586f78762ecc5f432dfd3602765a31b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 12:43:28 +0100 Subject: [PATCH 207/367] ALSA: hda - Move power_save option to hda_intel.c Move power_save option into hda_intel.c, and make a field in hda_bus, instead of keeping module parameters in separate files. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 16 ++++++---------- sound/pci/hda/hda_codec.h | 2 ++ sound/pci/hda/hda_intel.c | 6 +++++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f84874445b50..052a898a63ba 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -33,14 +33,6 @@ #include #include "hda_patch.h" /* codec presets */ -#ifdef CONFIG_SND_HDA_POWER_SAVE -/* define this option here to hide as static */ -static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; -module_param(power_save, int, 0644); -MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " - "(in second, 0 = disable)."); -#endif - /* * vendor / preset table */ @@ -519,6 +511,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, bus->private_data = temp->private_data; bus->pci = temp->pci; bus->modelname = temp->modelname; + bus->power_save = temp->power_save; bus->ops = temp->ops; mutex_init(&bus->cmd_mutex); @@ -2694,15 +2687,18 @@ void snd_hda_power_up(struct hda_codec *codec) codec->power_transition = 0; } +#define power_save(codec) \ + ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) + void snd_hda_power_down(struct hda_codec *codec) { --codec->power_count; if (!codec->power_on || codec->power_count || codec->power_transition) return; - if (power_save) { + if (power_save(codec)) { codec->power_transition = 1; /* avoid reentrance */ schedule_delayed_work(&codec->power_work, - msecs_to_jiffies(power_save * 1000)); + msecs_to_jiffies(power_save(codec) * 1000)); } } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index e1077df5e882..4034625b5997 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -585,6 +585,7 @@ struct hda_bus_template { void *private_data; struct pci_dev *pci; const char *modelname; + int *power_save; struct hda_bus_ops ops; }; @@ -601,6 +602,7 @@ struct hda_bus { void *private_data; struct pci_dev *pci; const char *modelname; + int *power_save; struct hda_bus_ops ops; /* codec linked list */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f13ec4c71f8a..f17ccd513350 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -83,7 +83,10 @@ module_param(enable_msi, int, 0444); MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); #ifdef CONFIG_SND_HDA_POWER_SAVE -/* power_save option is defined in hda_codec.c */ +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +module_param(power_save, int, 0644); +MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " + "(in second, 0 = disable)."); /* reset the HD-audio controller in power save mode. * this may give more power-saving, but will take longer time to @@ -1230,6 +1233,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, memset(&bus_temp, 0, sizeof(bus_temp)); bus_temp.private_data = chip; bus_temp.modelname = model; + bus_temp.power_save = &power_save; bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; From 529bd6c4a63f8468fd66f63fdc22d7070439b3cd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 14:17:01 +0100 Subject: [PATCH 208/367] ALSA: hda - Fix PCM reconfigure The reconfiguration of PCM affected all PCM streams on the bus, but this this should be done rather only for the target codec. This patch does the following: - introduce bitmap indicating the PCM device usages on a hda_bus - refactor the PCM build functions - fix __devinit prefix in some fucntions - add a proper ifdef around HDA-reconfig-specific functions Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 162 ++++++++++++++++++++++---------------- sound/pci/hda/hda_codec.h | 4 + sound/pci/hda/hda_hwdep.c | 2 +- 3 files changed, 98 insertions(+), 70 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 052a898a63ba..1cb85b73e19b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1206,6 +1206,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) return 0; } +#ifdef CONFIG_SND_HDA_RECONFIG /* Clear all controls assigned to the given codec */ void snd_hda_ctls_clear(struct hda_codec *codec) { @@ -1227,9 +1228,12 @@ void snd_hda_codec_reset(struct hda_codec *codec) snd_hda_ctls_clear(codec); /* relase PCMs */ for (i = 0; i < codec->num_pcms; i++) { - if (codec->pcm_info[i].pcm) + if (codec->pcm_info[i].pcm) { snd_device_free(codec->bus->card, codec->pcm_info[i].pcm); + clear_bit(codec->pcm_info[i].device, + codec->bus->pcm_dev_bits); + } } if (codec->patch_ops.free) codec->patch_ops.free(codec); @@ -1240,6 +1244,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) codec->pcm_info = NULL; codec->preset = NULL; } +#endif /* CONFIG_SND_HDA_RECONFIG */ /* create a virtual master control and add slaves */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, @@ -2432,11 +2437,59 @@ static int set_pcm_default_values(struct hda_codec *codec, return 0; } +/* + * get the empty PCM device number to assign + */ +static int get_empty_pcm_device(struct hda_bus *bus, int type) +{ + static const char *dev_name[HDA_PCM_NTYPES] = { + "Audio", "SPDIF", "HDMI", "Modem" + }; + /* starting device index for each PCM type */ + static int dev_idx[HDA_PCM_NTYPES] = { + [HDA_PCM_TYPE_AUDIO] = 0, + [HDA_PCM_TYPE_SPDIF] = 1, + [HDA_PCM_TYPE_HDMI] = 3, + [HDA_PCM_TYPE_MODEM] = 6 + }; + /* normal audio device indices; not linear to keep compatibility */ + static int audio_idx[4] = { 0, 2, 4, 5 }; + int i, dev; + + switch (type) { + case HDA_PCM_TYPE_AUDIO: + for (i = 0; i < ARRAY_SIZE(audio_idx); i++) { + dev = audio_idx[i]; + if (!test_bit(dev, bus->pcm_dev_bits)) + break; + } + if (i >= ARRAY_SIZE(audio_idx)) { + snd_printk(KERN_WARNING "Too many audio devices\n"); + return -EAGAIN; + } + break; + case HDA_PCM_TYPE_SPDIF: + case HDA_PCM_TYPE_HDMI: + case HDA_PCM_TYPE_MODEM: + dev = dev_idx[type]; + if (test_bit(dev, bus->pcm_dev_bits)) { + snd_printk(KERN_WARNING "%s already defined\n", + dev_name[type]); + return -EAGAIN; + } + break; + default: + snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); + return -EINVAL; + } + set_bit(dev, bus->pcm_dev_bits); + return dev; +} + /* * attach a new PCM stream */ -static int __devinit -snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) +static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) { struct hda_bus *bus = codec->bus; struct hda_pcm_stream *info; @@ -2455,6 +2508,39 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) return bus->ops.attach_pcm(bus, codec, pcm); } +/* assign all PCMs of the given codec */ +int snd_hda_codec_build_pcms(struct hda_codec *codec) +{ + unsigned int pcm; + int err; + + if (!codec->num_pcms) { + if (!codec->patch_ops.build_pcms) + return 0; + err = codec->patch_ops.build_pcms(codec); + if (err < 0) + return err; + } + for (pcm = 0; pcm < codec->num_pcms; pcm++) { + struct hda_pcm *cpcm = &codec->pcm_info[pcm]; + int dev; + + if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams) + return 0; /* no substreams assigned */ + + if (!cpcm->pcm) { + dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type); + if (dev < 0) + return 0; + cpcm->device = dev; + err = snd_hda_attach_pcm(codec, cpcm); + if (err < 0) + return err; + } + } + return 0; +} + /** * snd_hda_build_pcms - build PCM information * @bus: the BUS @@ -2481,76 +2567,14 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm) * * This function returns 0 if successfull, or a negative error code. */ -int snd_hda_build_pcms(struct hda_bus *bus) +int __devinit snd_hda_build_pcms(struct hda_bus *bus) { - static const char *dev_name[HDA_PCM_NTYPES] = { - "Audio", "SPDIF", "HDMI", "Modem" - }; - /* starting device index for each PCM type */ - static int dev_idx[HDA_PCM_NTYPES] = { - [HDA_PCM_TYPE_AUDIO] = 0, - [HDA_PCM_TYPE_SPDIF] = 1, - [HDA_PCM_TYPE_HDMI] = 3, - [HDA_PCM_TYPE_MODEM] = 6 - }; - /* normal audio device indices; not linear to keep compatibility */ - static int audio_idx[4] = { 0, 2, 4, 5 }; struct hda_codec *codec; - int num_devs[HDA_PCM_NTYPES]; - memset(num_devs, 0, sizeof(num_devs)); list_for_each_entry(codec, &bus->codec_list, list) { - unsigned int pcm; - int err; - if (!codec->num_pcms) { - if (!codec->patch_ops.build_pcms) - continue; - err = codec->patch_ops.build_pcms(codec); - if (err < 0) - return err; - } - for (pcm = 0; pcm < codec->num_pcms; pcm++) { - struct hda_pcm *cpcm = &codec->pcm_info[pcm]; - int type = cpcm->pcm_type; - int dev; - - if (!cpcm->stream[0].substreams && - !cpcm->stream[1].substreams) - continue; /* no substreams assigned */ - - switch (type) { - case HDA_PCM_TYPE_AUDIO: - if (num_devs[type] >= ARRAY_SIZE(audio_idx)) { - snd_printk(KERN_WARNING - "Too many audio devices\n"); - continue; - } - dev = audio_idx[num_devs[type]]; - break; - case HDA_PCM_TYPE_SPDIF: - case HDA_PCM_TYPE_HDMI: - case HDA_PCM_TYPE_MODEM: - if (num_devs[type]) { - snd_printk(KERN_WARNING - "%s already defined\n", - dev_name[type]); - continue; - } - dev = dev_idx[type]; - break; - default: - snd_printk(KERN_WARNING - "Invalid PCM type %d\n", type); - continue; - } - num_devs[type]++; - if (!cpcm->pcm) { - cpcm->device = dev; - err = snd_hda_attach_pcm(codec, cpcm); - if (err < 0) - return err; - } - } + int err = snd_hda_codec_build_pcms(codec); + if (err < 0) + return err; } return 0; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 4034625b5997..9fe0b67bb1e4 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -617,6 +617,9 @@ struct hda_bus { struct snd_info_entry *proc; + /* assigned PCMs */ + DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); + /* misc op flags */ unsigned int needs_damn_long_delay :1; unsigned int shutdown :1; /* being unloaded */ @@ -846,6 +849,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec); * PCM */ int snd_hda_build_pcms(struct hda_bus *bus); +int snd_hda_codec_build_pcms(struct hda_codec *codec); void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stream_tag, int channel_id, int format); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 5868bbc131cd..173af489322f 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -168,7 +168,7 @@ static int reconfig_codec(struct hda_codec *codec) if (err < 0) return err; /* rebuild PCMs */ - err = snd_hda_build_pcms(codec->bus); + err = snd_hda_codec_build_pcms(codec); if (err < 0) return err; /* rebuild mixers */ From 30d72e9f614e7bd76e28d4d92bd54d90a96905bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 15:25:34 +0100 Subject: [PATCH 209/367] ALSA: hda - Fix creation of automatic capture mixers Fixed a wrong boundary check of num_adc_nids in set_capture_mixer() in patch_realtek.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4afa0c9b9b6e..9cd2545d988e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4269,7 +4269,7 @@ static void set_capture_mixer(struct alc_spec *spec) alc_capture_mixer2, alc_capture_mixer3, }; - if (spec->num_adc_nids > 0 && spec->num_adc_nids < 3) + if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) spec->cap_mixer = caps[spec->num_adc_nids - 1]; } From 73f6a12ed187b7e7ac9334d1419ba7bf7ac1be26 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 27 Nov 2008 15:40:40 +0100 Subject: [PATCH 210/367] ALSA: sound/pci/mixart/mixart.c: Add missing snd_card_free The function snd_mixart_create creates a link between mgr and card that allows snd_mixart_free to free card as well. But if snd_mixart_create fails, then the link has not been created and card has to be freed explicitly. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S,S1; position p1,p2,p3; expression E,E1; type T,T1; expression *ptr != NULL; @@ ( if ((x@p1 = snd_card_new(...)) == NULL) S | x@p1 = snd_card_new(...); ) ... when != snd_card_free(...,(T)x,...) when != if (...) { <+... snd_card_free(...,(T)x,...) ...+> } when != true x == NULL || ... when != x = E when != E = (T)x when any ( if (x == NULL || ...) S1 | if@p2 (...) { ... when != snd_card_free(...,(T1)x,...) when != if (...) { <+... snd_card_free(...,(T1)x,...) ...+> } when != x = E1 when != E1 = (T1)x ( return \(0\|<+...x...+>\|ptr\); | return@p3 ...; ) } ) @ script:python @ p1 << r.p1; p3 << r.p3; @@ print "* file: %s snd_card_new: %s return: %s" % (p1[0].file,p1[0].line,p3[0].line) // Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/pci/mixart/mixart.c | 4 +++- sound/pci/pcxhr/pcxhr.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 2d0dce649a64..fd9a117f37a4 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1010,7 +1010,7 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card * .dev_free = snd_mixart_chip_dev_free, }; - mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; @@ -1025,6 +1025,7 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card * return err; } + mgr->chip[idx] = chip; snd_card_set_dev(card, &mgr->pci->dev); return 0; @@ -1378,6 +1379,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i); if ((err = snd_mixart_create(mgr, card, i)) < 0) { + snd_card_free(card); snd_mixart_free(mgr); return err; } diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 0e06c6c9fcc0..58621206a2b3 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -1024,7 +1024,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, .dev_free = pcxhr_chip_dev_free, }; - mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; @@ -1050,6 +1050,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, struct snd_card *card, return err; } + mgr->chip[idx] = chip; snd_card_set_dev(card, &mgr->pci->dev); return 0; @@ -1307,6 +1308,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, const struct pci_device_id sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i); if ((err = pcxhr_create(mgr, card, i)) < 0) { + snd_card_free(card); pcxhr_free(mgr); return err; } From 1289e9e8b42f973f2ab39e5f4f2239ff826c27e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Nov 2008 15:47:11 +0100 Subject: [PATCH 211/367] ALSA: hda - Modularize HD-audio driver Split the monolithc HD-audio driver into several pieces: - snd-hda-intel HD-audio PCI controller driver; loaded via udev - snd-hda-codec HD-audio codec bus driver - snd-hda-codec-* Specific HD-audio codec drivers When built as modules, snd-hda-codec (that is invoked by snd-hda-intel) looks up the codec vendor ID and loads the corresponding codec module automatically via request_module(). When built in a kernel, each codec drivers are statically hooked up before probing the PCI. This patch adds appropriate EXPORT_SYMBOL_GPL()'s and the module information for each driver, and driver-linking codes between codec-bus and codec drivers. TODO: - Avoid EXPORT_SYMBOL*() when built-in kernel - Restore __devinit appropriately depending on the condition Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 50 +++++++++ sound/pci/hda/Makefile | 77 +++++++++---- sound/pci/hda/hda_beep.c | 2 + sound/pci/hda/hda_codec.c | 187 ++++++++++++++++++++++++-------- sound/pci/hda/hda_codec.h | 11 ++ sound/pci/hda/hda_generic.c | 1 + sound/pci/hda/hda_hwdep.c | 2 +- sound/pci/hda/hda_patch.h | 24 ---- sound/pci/hda/patch_analog.c | 26 ++++- sound/pci/hda/patch_atihdmi.c | 31 +++++- sound/pci/hda/patch_cmedia.c | 27 ++++- sound/pci/hda/patch_conexant.c | 28 ++++- sound/pci/hda/patch_intelhdmi.c | 30 ++++- sound/pci/hda/patch_nvhdmi.c | 27 ++++- sound/pci/hda/patch_realtek.c | 26 ++++- sound/pci/hda/patch_si3054.c | 35 +++++- sound/pci/hda/patch_sigmatel.c | 27 ++++- sound/pci/hda/patch_via.c | 26 ++++- 18 files changed, 528 insertions(+), 109 deletions(-) delete mode 100644 sound/pci/hda/hda_patch.h diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7c60f1a45a8d..717040a491b9 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -46,6 +46,11 @@ config SND_HDA_CODEC_REALTEK Say Y here to include Realtek HD-audio codec support in snd-hda-intel driver, such as ALC880. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-realtek. + This module is automatically loaded at probing. + config SND_HDA_CODEC_ANALOG bool "Build Analog Device HD-audio codec support" default y @@ -53,6 +58,11 @@ config SND_HDA_CODEC_ANALOG Say Y here to include Analog Device HD-audio codec support in snd-hda-intel driver, such as AD1986A. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-analog. + This module is automatically loaded at probing. + config SND_HDA_CODEC_SIGMATEL bool "Build IDT/Sigmatel HD-audio codec support" default y @@ -60,6 +70,11 @@ config SND_HDA_CODEC_SIGMATEL Say Y here to include IDT (Sigmatel) HD-audio codec support in snd-hda-intel driver, such as STAC9200. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-idt. + This module is automatically loaded at probing. + config SND_HDA_CODEC_VIA bool "Build VIA HD-audio codec support" default y @@ -67,6 +82,11 @@ config SND_HDA_CODEC_VIA Say Y here to include VIA HD-audio codec support in snd-hda-intel driver, such as VT1708. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-via. + This module is automatically loaded at probing. + config SND_HDA_CODEC_ATIHDMI bool "Build ATI HDMI HD-audio codec support" default y @@ -74,6 +94,11 @@ config SND_HDA_CODEC_ATIHDMI Say Y here to include ATI HDMI HD-audio codec support in snd-hda-intel driver, such as ATI RS600 HDMI. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-atihdmi. + This module is automatically loaded at probing. + config SND_HDA_CODEC_NVHDMI bool "Build NVIDIA HDMI HD-audio codec support" default y @@ -81,6 +106,11 @@ config SND_HDA_CODEC_NVHDMI Say Y here to include NVIDIA HDMI HD-audio codec support in snd-hda-intel driver, such as NVIDIA MCP78 HDMI. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-nvhdmi. + This module is automatically loaded at probing. + config SND_HDA_CODEC_INTELHDMI bool "Build INTEL HDMI HD-audio codec support" default y @@ -88,6 +118,11 @@ config SND_HDA_CODEC_INTELHDMI Say Y here to include INTEL HDMI HD-audio codec support in snd-hda-intel driver, such as Eaglelake integrated HDMI. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-intelhdmi. + This module is automatically loaded at probing. + config SND_HDA_ELD def_bool y depends on SND_HDA_CODEC_INTELHDMI @@ -99,6 +134,11 @@ config SND_HDA_CODEC_CONEXANT Say Y here to include Conexant HD-audio codec support in snd-hda-intel driver, such as CX20549. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-conexant. + This module is automatically loaded at probing. + config SND_HDA_CODEC_CMEDIA bool "Build C-Media HD-audio codec support" default y @@ -106,6 +146,11 @@ config SND_HDA_CODEC_CMEDIA Say Y here to include C-Media HD-audio codec support in snd-hda-intel driver, such as CMI9880. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-cmedia. + This module is automatically loaded at probing. + config SND_HDA_CODEC_SI3054 bool "Build Silicon Labs 3054 HD-modem codec support" default y @@ -113,6 +158,11 @@ config SND_HDA_CODEC_SI3054 Say Y here to include Silicon Labs 3054 HD-modem codec (and compatibles) support in snd-hda-intel driver. + When the HD-audio driver is built as a module, the codec + support code is also built as another module, + snd-hda-codec-si3054. + This module is automatically loaded at probing. + config SND_HDA_GENERIC bool "Enable generic HD-audio codec parser" default y diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 6daf5fd9a279..50f9d0967251 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,22 +1,59 @@ -snd-hda-intel-y := hda_intel.o -# since snd-hda-intel is the only driver using hda-codec, -# merge it into a single module although it was originally -# designed to be individual modules -snd-hda-intel-y += hda_codec.o -snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o -snd-hda-intel-$(CONFIG_SND_HDA_ELD) += hda_eld.o -snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o -snd-hda-intel-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o -snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_REALTEK) += patch_realtek.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CMEDIA) += patch_cmedia.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ANALOG) += patch_analog.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += patch_sigmatel.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_SI3054) += patch_si3054.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_ATIHDMI) += patch_atihdmi.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_CONEXANT) += patch_conexant.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_VIA) += patch_via.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_NVHDMI) += patch_nvhdmi.o -snd-hda-intel-$(CONFIG_SND_HDA_CODEC_INTELHDMI) += patch_intelhdmi.o +snd-hda-intel-objs := hda_intel.o +snd-hda-codec-y := hda_codec.o +snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o +snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o +# snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o +snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o +snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o + +snd-hda-codec-realtek-objs := patch_realtek.o +snd-hda-codec-cmedia-objs := patch_cmedia.o +snd-hda-codec-analog-objs := patch_analog.o +snd-hda-codec-idt-objs := patch_sigmatel.o +snd-hda-codec-si3054-objs := patch_si3054.o +snd-hda-codec-atihdmi-objs := patch_atihdmi.o +snd-hda-codec-conexant-objs := patch_conexant.o +snd-hda-codec-via-objs := patch_via.o +snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o +snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o hda_eld.o + +# common driver +obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o + +# codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans) +ifdef CONFIG_SND_HDA_CODEC_REALTEK +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o +endif +ifdef CONFIG_SND_HDA_CODEC_CMEDIA +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cmedia.o +endif +ifdef CONFIG_SND_HDA_CODEC_ANALOG +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-analog.o +endif +ifdef CONFIG_SND_HDA_CODEC_SIGMATEL +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-idt.o +endif +ifdef CONFIG_SND_HDA_CODEC_SI3054 +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o +endif +ifdef CONFIG_SND_HDA_CODEC_ATIHDMI +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o +endif +ifdef CONFIG_SND_HDA_CODEC_CONEXANT +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o +endif +ifdef CONFIG_SND_HDA_CODEC_VIA +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o +endif +ifdef CONFIG_SND_HDA_CODEC_NVHDMI +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-nvhdmi.o +endif +ifdef CONFIG_SND_HDA_CODEC_INTELHDMI +obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-intelhdmi.o +endif + +# this must be the last entry after codec drivers; +# otherwise the codec patches won't be hooked before the PCI probe +# when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 3ecd7e797dee..e6cc9463667a 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -128,6 +128,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); void snd_hda_detach_beep_device(struct hda_codec *codec) { @@ -140,3 +141,4 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) kfree(beep); } } +EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1cb85b73e19b..4aa7b1b72877 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -31,7 +31,6 @@ #include #include "hda_local.h" #include -#include "hda_patch.h" /* codec presets */ /* * vendor / preset table @@ -62,39 +61,26 @@ static struct hda_vendor_id hda_vendor_ids[] = { {} /* terminator */ }; -static const struct hda_codec_preset *hda_preset_tables[] = { -#ifdef CONFIG_SND_HDA_CODEC_REALTEK - snd_hda_preset_realtek, -#endif -#ifdef CONFIG_SND_HDA_CODEC_CMEDIA - snd_hda_preset_cmedia, -#endif -#ifdef CONFIG_SND_HDA_CODEC_ANALOG - snd_hda_preset_analog, -#endif -#ifdef CONFIG_SND_HDA_CODEC_SIGMATEL - snd_hda_preset_sigmatel, -#endif -#ifdef CONFIG_SND_HDA_CODEC_SI3054 - snd_hda_preset_si3054, -#endif -#ifdef CONFIG_SND_HDA_CODEC_ATIHDMI - snd_hda_preset_atihdmi, -#endif -#ifdef CONFIG_SND_HDA_CODEC_CONEXANT - snd_hda_preset_conexant, -#endif -#ifdef CONFIG_SND_HDA_CODEC_VIA - snd_hda_preset_via, -#endif -#ifdef CONFIG_SND_HDA_CODEC_NVHDMI - snd_hda_preset_nvhdmi, -#endif -#ifdef CONFIG_SND_HDA_CODEC_INTELHDMI - snd_hda_preset_intelhdmi, -#endif - NULL -}; +static DEFINE_MUTEX(preset_mutex); +static LIST_HEAD(hda_preset_tables); + +int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) +{ + mutex_lock(&preset_mutex); + list_add_tail(&preset->list, &hda_preset_tables); + mutex_unlock(&preset_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset); + +int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) +{ + mutex_lock(&preset_mutex); + list_del(&preset->list); + mutex_unlock(&preset_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_power_work(struct work_struct *work); @@ -128,6 +114,7 @@ const char *snd_hda_get_jack_location(u32 cfg) } return "UNKNOWN"; } +EXPORT_SYMBOL_GPL(snd_hda_get_jack_location); const char *snd_hda_get_jack_connectivity(u32 cfg) { @@ -135,6 +122,7 @@ const char *snd_hda_get_jack_connectivity(u32 cfg) return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; } +EXPORT_SYMBOL_GPL(snd_hda_get_jack_connectivity); const char *snd_hda_get_jack_type(u32 cfg) { @@ -148,6 +136,7 @@ const char *snd_hda_get_jack_type(u32 cfg) return jack_types[(cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT]; } +EXPORT_SYMBOL_GPL(snd_hda_get_jack_type); /* * Compose a 32bit command word to be sent to the HD-audio controller @@ -196,6 +185,7 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, snd_hda_power_down(codec); return res; } +EXPORT_SYMBOL_GPL(snd_hda_codec_read); /** * snd_hda_codec_write - send a single command without waiting for response @@ -224,6 +214,7 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, snd_hda_power_down(codec); return err; } +EXPORT_SYMBOL_GPL(snd_hda_codec_write); /** * snd_hda_sequence_write - sequence writes @@ -238,6 +229,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) for (; seq->nid; seq++) snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); } +EXPORT_SYMBOL_GPL(snd_hda_sequence_write); /** * snd_hda_get_sub_nodes - get the range of sub nodes @@ -259,6 +251,7 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } +EXPORT_SYMBOL_GPL(snd_hda_get_sub_nodes); /** * snd_hda_get_connections - get connection list @@ -347,6 +340,7 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } return conns; } +EXPORT_SYMBOL_GPL(snd_hda_get_connections); /** @@ -381,6 +375,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) return 0; } +EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event); /* * process queued unsolicited events @@ -482,7 +477,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 /*__devinit*/ snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, struct hda_bus **busp) { @@ -526,6 +521,7 @@ int __devinit snd_hda_bus_new(struct snd_card *card, *busp = bus; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_bus_new); #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ @@ -534,19 +530,33 @@ int __devinit snd_hda_bus_new(struct snd_card *card, #define is_generic_config(codec) 0 #endif +#ifdef CONFIG_SND_HDA_INTEL_MODULE +#define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */ +#else +#define HDA_MODREQ_MAX_COUNT 0 +#endif + /* * find a matching codec preset */ static const struct hda_codec_preset * find_codec_preset(struct hda_codec *codec) { - const struct hda_codec_preset **tbl, *preset; + struct hda_codec_preset_list *tbl; + const struct hda_codec_preset *preset; + int mod_requested = 0; if (is_generic_config(codec)) return NULL; /* use the generic parser */ - for (tbl = hda_preset_tables; *tbl; tbl++) { - for (preset = *tbl; preset->id; preset++) { + again: + mutex_lock(&preset_mutex); + list_for_each_entry(tbl, &hda_preset_tables, list) { + if (!try_module_get(tbl->owner)) { + snd_printk(KERN_ERR "hda_codec: cannot module_get\n"); + continue; + } + for (preset = tbl->preset; preset->id; preset++) { u32 mask = preset->mask; if (preset->afg && preset->afg != codec->afg) continue; @@ -556,9 +566,27 @@ find_codec_preset(struct hda_codec *codec) mask = ~0; if (preset->id == (codec->vendor_id & mask) && (!preset->rev || - preset->rev == codec->revision_id)) + preset->rev == codec->revision_id)) { + mutex_unlock(&preset_mutex); + codec->owner = tbl->owner; return preset; + } } + module_put(tbl->owner); + } + mutex_unlock(&preset_mutex); + + if (mod_requested < HDA_MODREQ_MAX_COUNT) { + char name[32]; + if (!mod_requested) + snprintf(name, sizeof(name), "snd-hda-codec-id:%08x", + codec->vendor_id); + else + snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*", + (codec->vendor_id >> 16) & 0xffff); + request_module(name); + mod_requested++; + goto again; } return NULL; } @@ -598,7 +626,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 /*__devinit*/ setup_fg_nodes(struct hda_codec *codec) { int i, total_nodes; hda_nid_t nid; @@ -661,6 +689,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); + module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); kfree(codec->name); @@ -677,7 +706,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) * * Returns 0 if successful, or a negative error code. */ -int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, +int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp) { struct hda_codec *codec; @@ -779,6 +808,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, *codecp = codec; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_codec_new); int snd_hda_codec_configure(struct hda_codec *codec) { @@ -838,6 +868,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, msleep(1); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); } +EXPORT_SYMBOL_GPL(snd_hda_codec_setup_stream); void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) { @@ -851,6 +882,7 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); #endif } +EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup_stream); /* * amp access functions @@ -862,7 +894,7 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) #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 /*__devinit*/ init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size) { memset(cache, 0, sizeof(*cache)); @@ -932,6 +964,7 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) } return info->amp_caps; } +EXPORT_SYMBOL_GPL(query_amp_caps); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps) @@ -945,6 +978,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, info->head.val |= INFO_AMP_CAPS; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps); /* * read the current volume to info @@ -998,6 +1032,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; return get_vol_mute(codec, info, nid, ch, direction, index); } +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read); /* * update the AMP value, mask = bit mask to set, val = the value @@ -1017,6 +1052,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update); /* * update the AMP stereo with the same mask and value @@ -1030,6 +1066,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, idx, mask, val); return ret; } +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo); #ifdef SND_HDA_NEEDS_RESUME /* resume the all amp commands from the cache */ @@ -1055,6 +1092,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) } } } +EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ /* volume */ @@ -1082,6 +1120,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = caps; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_info); int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1101,6 +1140,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, & HDA_AMP_VOLMASK; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get); int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1125,6 +1165,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) @@ -1151,6 +1192,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -EFAULT; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_tlv); /* * set (static) TLV for virtual master volume; recalculated as max 0dB @@ -1170,6 +1212,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, tlv[2] = -nums * step; tlv[3] = step; } +EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv); /* find a mixer control element with the given name */ static struct snd_kcontrol * @@ -1189,6 +1232,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, { return _snd_hda_find_mixer_ctl(codec, name, 0); } +EXPORT_SYMBOL_GPL(snd_hda_find_mixer_ctl); /* Add a control element and assign to the codec */ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) @@ -1205,6 +1249,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) *knewp = kctl; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_ctl_add); #ifdef CONFIG_SND_HDA_RECONFIG /* Clear all controls assigned to the given codec */ @@ -1243,6 +1288,8 @@ void snd_hda_codec_reset(struct hda_codec *codec) codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; + module_put(codec->owner); + codec->owner = NULL; } #endif /* CONFIG_SND_HDA_RECONFIG */ @@ -1281,6 +1328,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_add_vmaster); /* switch */ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, @@ -1294,6 +1342,7 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 1; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info); int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1313,6 +1362,7 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, HDA_AMP_MUTE) ? 0 : 1; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get); int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1343,6 +1393,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); /* * bound volume controls @@ -1368,6 +1419,7 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get); int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1391,6 +1443,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put); /* * generic bound volume/swtich controls @@ -1410,6 +1463,7 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info); int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1426,6 +1480,7 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get); int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1448,6 +1503,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put); int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) @@ -1464,6 +1520,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, mutex_unlock(&codec->spdif_mutex); return err; } +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_tlv); struct hda_ctl_ops snd_hda_bind_vol = { .info = snd_hda_mixer_amp_volume_info, @@ -1471,6 +1528,7 @@ struct hda_ctl_ops snd_hda_bind_vol = { .put = snd_hda_mixer_amp_volume_put, .tlv = snd_hda_mixer_amp_tlv }; +EXPORT_SYMBOL_GPL(snd_hda_bind_vol); struct hda_ctl_ops snd_hda_bind_sw = { .info = snd_hda_mixer_amp_switch_info, @@ -1478,6 +1536,7 @@ struct hda_ctl_ops snd_hda_bind_sw = { .put = snd_hda_mixer_amp_switch_put, .tlv = snd_hda_mixer_amp_tlv }; +EXPORT_SYMBOL_GPL(snd_hda_bind_sw); /* * SPDIF out controls @@ -1739,6 +1798,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_create_spdif_out_ctls); /* * SPDIF sharing with analog output @@ -1776,6 +1836,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); } +EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw); /* * SPDIF input @@ -1885,6 +1946,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) AC_DIG1_ENABLE; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls); #ifdef SND_HDA_NEEDS_RESUME /* @@ -1930,6 +1992,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, snd_hda_power_down(codec); return err; } +EXPORT_SYMBOL_GPL(snd_hda_codec_write_cache); /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) @@ -1945,6 +2008,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec) get_cmd_cache_cmd(key), buffer->val); } } +EXPORT_SYMBOL_GPL(snd_hda_codec_resume_cache); /** * snd_hda_sequence_write_cache - sequence writes with caching @@ -1962,6 +2026,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, seq->param); } +EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache); #endif /* SND_HDA_NEEDS_RESUME */ /* @@ -2080,7 +2145,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 /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) { struct hda_codec *codec; @@ -2091,6 +2156,7 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_build_controls); int snd_hda_codec_build_controls(struct hda_codec *codec) { @@ -2202,6 +2268,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, return val; } +EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format); /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats @@ -2381,6 +2448,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, return 1; } +EXPORT_SYMBOL_GPL(snd_hda_is_supported_format); /* * PCM stuff @@ -2578,6 +2646,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_build_pcms); /** * snd_hda_check_board_config - compare the current codec with the config table @@ -2633,6 +2702,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, } return -1; } +EXPORT_SYMBOL_GPL(snd_hda_check_board_config); /** * snd_hda_add_new_ctls - create controls from the array @@ -2668,6 +2738,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, @@ -2710,6 +2781,10 @@ void snd_hda_power_up(struct hda_codec *codec) cancel_delayed_work(&codec->power_work); codec->power_transition = 0; } +EXPORT_SYMBOL_GPL(snd_hda_power_up); + +#define power_save(codec) \ + ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) #define power_save(codec) \ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) @@ -2725,6 +2800,7 @@ void snd_hda_power_down(struct hda_codec *codec) msecs_to_jiffies(power_save(codec) * 1000)); } } +EXPORT_SYMBOL_GPL(snd_hda_power_down); int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, @@ -2761,6 +2837,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); #endif /* @@ -2780,6 +2857,7 @@ int snd_hda_ch_mode_info(struct hda_codec *codec, chmode[uinfo->value.enumerated.item].channels); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info); int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2797,6 +2875,7 @@ int snd_hda_ch_mode_get(struct hda_codec *codec, } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get); int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2817,6 +2896,7 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put); /* * input MUX helper @@ -2837,6 +2917,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, strcpy(uinfo->value.enumerated.name, imux->items[index].label); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_input_mux_info); int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, @@ -2858,6 +2939,7 @@ int snd_hda_input_mux_put(struct hda_codec *codec, *cur_val = idx; return 1; } +EXPORT_SYMBOL_GPL(snd_hda_input_mux_put); /* @@ -2910,6 +2992,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open); int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, @@ -2922,6 +3005,7 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare); /* * release the digital out @@ -2934,6 +3018,7 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close); /* * set up more restrictions for analog out @@ -2973,6 +3058,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, return snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open); /* * set up the i/o for analog out @@ -3031,6 +3117,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare); /* * clean up the setting for analog out @@ -3057,6 +3144,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup); /* * Helper for automatic pin configuration @@ -3342,11 +3430,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, return 0; } +EXPORT_SYMBOL_GPL(snd_hda_parse_pin_def_config); /* labels for input pins */ const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" }; +EXPORT_SYMBOL_GPL(auto_pin_cfg_labels); #ifdef CONFIG_PM @@ -3374,6 +3464,7 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) } return 0; } +EXPORT_SYMBOL_GPL(snd_hda_suspend); /** * snd_hda_resume - resume the codecs @@ -3394,7 +3485,8 @@ int snd_hda_resume(struct hda_bus *bus) } return 0; } -#endif +EXPORT_SYMBOL_GPL(snd_hda_resume); +#endif /* CONFIG_PM */ /* * generic arrays @@ -3423,6 +3515,7 @@ void *snd_array_new(struct snd_array *array) } return snd_array_elem(array, array->used++); } +EXPORT_SYMBOL_GPL(snd_array_new); /* free the given array elements */ void snd_array_free(struct snd_array *array) @@ -3432,6 +3525,7 @@ void snd_array_free(struct snd_array *array) array->alloced = 0; array->list = NULL; } +EXPORT_SYMBOL_GPL(snd_array_free); /* * used by hda_proc.c and hda_eld.c @@ -3450,6 +3544,7 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } +EXPORT_SYMBOL_GPL(snd_print_pcm_rates); void snd_print_pcm_bits(int pcm, char *buf, int buflen) { @@ -3462,3 +3557,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } +EXPORT_SYMBOL_GPL(snd_print_pcm_bits); + +MODULE_DESCRIPTION("HDA codec core"); +MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9fe0b67bb1e4..586ea08b340b 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -642,6 +642,16 @@ struct hda_codec_preset { int (*patch)(struct hda_codec *codec); }; +struct hda_codec_preset_list { + const struct hda_codec_preset *preset; + struct module *owner; + struct list_head list; +}; + +/* initial hook */ +int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset); +int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset); + /* ops set by the preset patch */ struct hda_codec_ops { int (*build_controls)(struct hda_codec *codec); @@ -735,6 +745,7 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; + struct module *owner; const char *name; /* codec name */ const char *modelname; /* model name for preset */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 98ff010d5b95..65745e96dc70 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -1101,3 +1101,4 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec) snd_hda_generic_free(codec); return err; } +EXPORT_SYMBOL(snd_hda_parse_generic_codec); diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 173af489322f..300ab407cf42 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -116,7 +116,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 /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) { char hwname[16]; struct snd_hwdep *hwdep; diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h deleted file mode 100644 index 38212c1020a6..000000000000 --- a/sound/pci/hda/hda_patch.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * HDA Patches - included by hda_codec.c - */ - -/* Realtek codecs */ -extern struct hda_codec_preset snd_hda_preset_realtek[]; -/* C-Media codecs */ -extern struct hda_codec_preset snd_hda_preset_cmedia[]; -/* Analog Devices codecs */ -extern struct hda_codec_preset snd_hda_preset_analog[]; -/* SigmaTel codecs */ -extern struct hda_codec_preset snd_hda_preset_sigmatel[]; -/* SiLabs 3054/3055 modem codecs */ -extern struct hda_codec_preset snd_hda_preset_si3054[]; -/* ATI HDMI codecs */ -extern struct hda_codec_preset snd_hda_preset_atihdmi[]; -/* Conexant audio codec */ -extern struct hda_codec_preset snd_hda_preset_conexant[]; -/* VIA codecs */ -extern struct hda_codec_preset snd_hda_preset_via[]; -/* NVIDIA HDMI codecs */ -extern struct hda_codec_preset snd_hda_preset_nvhdmi[]; -/* INTEL HDMI codecs */ -extern struct hda_codec_preset snd_hda_preset_intelhdmi[]; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 0cc6be12b8b7..c1918a1a6df9 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -27,7 +27,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" struct ad198x_spec { struct snd_kcontrol_new *mixers[5]; @@ -4308,7 +4307,7 @@ static int patch_ad1882(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_analog[] = { +static struct hda_codec_preset snd_hda_preset_analog[] = { { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, @@ -4326,3 +4325,26 @@ struct hda_codec_preset snd_hda_preset_analog[] = { { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:11d4*"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Analog Devices HD-audio codec"); + +static struct hda_codec_preset_list analog_list = { + .preset = snd_hda_preset_analog, + .owner = THIS_MODULE, +}; + +static int __init patch_analog_init(void) +{ + return snd_hda_add_codec_preset(&analog_list); +} + +static void __exit patch_analog_exit(void) +{ + snd_hda_delete_codec_preset(&analog_list); +} + +module_init(patch_analog_init) +module_exit(patch_analog_exit) diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 5603a1acddb1..5887b827bb32 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -27,7 +27,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" struct atihdmi_spec { struct hda_multi_out multiout; @@ -187,7 +186,7 @@ static int patch_atihdmi(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_atihdmi[] = { +static struct hda_codec_preset snd_hda_preset_atihdmi[] = { { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, @@ -196,3 +195,31 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = { { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:1002793c"); +MODULE_ALIAS("snd-hda-codec-id:10027919"); +MODULE_ALIAS("snd-hda-codec-id:1002791a"); +MODULE_ALIAS("snd-hda-codec-id:1002aa01"); +MODULE_ALIAS("snd-hda-codec-id:10951390"); +MODULE_ALIAS("snd-hda-codec-id:17e80047"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ATI HDMI HD-audio codec"); + +static struct hda_codec_preset_list atihdmi_list = { + .preset = snd_hda_preset_atihdmi, + .owner = THIS_MODULE, +}; + +static int __init patch_atihdmi_init(void) +{ + return snd_hda_add_codec_preset(&atihdmi_list); +} + +static void __exit patch_atihdmi_exit(void) +{ + snd_hda_delete_codec_preset(&atihdmi_list); +} + +module_init(patch_atihdmi_init) +module_exit(patch_atihdmi_exit) diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 6ef57fbfb6eb..f3ebe837f2d5 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -28,7 +28,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #define NUM_PINS 11 @@ -736,8 +735,32 @@ static int patch_cmi9880(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_cmedia[] = { +static struct hda_codec_preset snd_hda_preset_cmedia[] = { { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:13f69880"); +MODULE_ALIAS("snd-hda-codec-id:434d4980"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("C-Media HD-audio codec"); + +static struct hda_codec_preset_list cmedia_list = { + .preset = snd_hda_preset_cmedia, + .owner = THIS_MODULE, +}; + +static int __init patch_cmedia_init(void) +{ + return snd_hda_add_codec_preset(&cmedia_list); +} + +static void __exit patch_cmedia_exit(void) +{ + snd_hda_delete_codec_preset(&cmedia_list); +} + +module_init(patch_cmedia_init) +module_exit(patch_cmedia_exit) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 076010708152..b20e1cede00b 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -27,7 +27,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_OUT 0x01 @@ -1771,7 +1770,7 @@ static int patch_cxt5051(struct hda_codec *codec) /* */ -struct hda_codec_preset snd_hda_preset_conexant[] = { +static struct hda_codec_preset snd_hda_preset_conexant[] = { { .id = 0x14f15045, .name = "CX20549 (Venice)", .patch = patch_cxt5045 }, { .id = 0x14f15047, .name = "CX20551 (Waikiki)", @@ -1780,3 +1779,28 @@ struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5051 }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:14f15045"); +MODULE_ALIAS("snd-hda-codec-id:14f15047"); +MODULE_ALIAS("snd-hda-codec-id:14f15051"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Conexant HD-audio codec"); + +static struct hda_codec_preset_list conexant_list = { + .preset = snd_hda_preset_conexant, + .owner = THIS_MODULE, +}; + +static int __init patch_conexant_init(void) +{ + return snd_hda_add_codec_preset(&conexant_list); +} + +static void __exit patch_conexant_exit(void) +{ + snd_hda_delete_codec_preset(&conexant_list); +} + +module_init(patch_conexant_init) +module_exit(patch_conexant_exit) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index fe08bef897cd..290da562f29b 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -32,7 +32,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #define CVT_NID 0x02 /* audio converter */ #define PIN_NID 0x03 /* HDMI output pin */ @@ -675,7 +674,7 @@ static int patch_intel_hdmi(struct hda_codec *codec) return 0; } -struct hda_codec_preset snd_hda_preset_intelhdmi[] = { +static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi }, { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, @@ -683,3 +682,30 @@ struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:808629fb"); +MODULE_ALIAS("snd-hda-codec-id:80862801"); +MODULE_ALIAS("snd-hda-codec-id:80862802"); +MODULE_ALIAS("snd-hda-codec-id:80862803"); +MODULE_ALIAS("snd-hda-codec-id:10951392"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel HDMI HD-audio codec"); + +static struct hda_codec_preset_list intel_list = { + .preset = snd_hda_preset_intelhdmi, + .owner = THIS_MODULE, +}; + +static int __init patch_intelhdmi_init(void) +{ + return snd_hda_add_codec_preset(&intel_list); +} + +static void __exit patch_intelhdmi_exit(void) +{ + snd_hda_delete_codec_preset(&intel_list); +} + +module_init(patch_intelhdmi_init) +module_exit(patch_intelhdmi_exit) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 1360d54a7d01..e23de5594b6e 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -28,7 +28,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" struct nvhdmi_spec { struct hda_multi_out multiout; @@ -159,8 +158,32 @@ static int patch_nvhdmi(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_nvhdmi[] = { +static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:10de0002"); +MODULE_ALIAS("snd-hda-codec-id:10de0007"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); + +static struct hda_codec_preset_list nvhdmi_list = { + .preset = snd_hda_preset_nvhdmi, + .owner = THIS_MODULE, +}; + +static int __init patch_nvhdmi_init(void) +{ + return snd_hda_add_codec_preset(&nvhdmi_list); +} + +static void __exit patch_nvhdmi_exit(void) +{ + snd_hda_delete_codec_preset(&nvhdmi_list); +} + +module_init(patch_nvhdmi_init) +module_exit(patch_nvhdmi_exit) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9cd2545d988e..ba640d36d648 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -30,7 +30,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #define ALC880_FRONT_EVENT 0x01 #define ALC880_DCVOL_EVENT 0x02 @@ -16579,7 +16578,7 @@ static int patch_alc662(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_realtek[] = { +static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, @@ -16611,3 +16610,26 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:10ec*"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Realtek HD-audio codec"); + +static struct hda_codec_preset_list realtek_list = { + .preset = snd_hda_preset_realtek, + .owner = THIS_MODULE, +}; + +static int __init patch_realtek_init(void) +{ + return snd_hda_add_codec_preset(&realtek_list); +} + +static void __exit patch_realtek_exit(void) +{ + snd_hda_delete_codec_preset(&realtek_list); +} + +module_init(patch_realtek_init) +module_exit(patch_realtek_exit) diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 9332b63e406c..43b436c5d01b 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -28,7 +28,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" /* si3054 verbs */ #define SI3054_VERB_READ_NODE 0x900 @@ -283,7 +282,7 @@ static int patch_si3054(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_si3054[] = { +static struct hda_codec_preset snd_hda_preset_si3054[] = { { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, @@ -301,3 +300,35 @@ struct hda_codec_preset snd_hda_preset_si3054[] = { {} }; +MODULE_ALIAS("snd-hda-codec-id:163c3055"); +MODULE_ALIAS("snd-hda-codec-id:163c3155"); +MODULE_ALIAS("snd-hda-codec-id:11c13026"); +MODULE_ALIAS("snd-hda-codec-id:11c13055"); +MODULE_ALIAS("snd-hda-codec-id:11c13155"); +MODULE_ALIAS("snd-hda-codec-id:10573055"); +MODULE_ALIAS("snd-hda-codec-id:10573057"); +MODULE_ALIAS("snd-hda-codec-id:10573155"); +MODULE_ALIAS("snd-hda-codec-id:11063288"); +MODULE_ALIAS("snd-hda-codec-id:15433155"); +MODULE_ALIAS("snd-hda-codec-id:18540018"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Si3054 HD-audio modem codec"); + +static struct hda_codec_preset_list si3054_list = { + .preset = snd_hda_preset_si3054, + .owner = THIS_MODULE, +}; + +static int __init patch_si3054_init(void) +{ + return snd_hda_add_codec_preset(&si3054_list); +} + +static void __exit patch_si3054_exit(void) +{ + snd_hda_delete_codec_preset(&si3054_list); +} + +module_init(patch_si3054_init) +module_exit(patch_si3054_exit) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 70181d500536..9e07f44ab28a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -33,7 +33,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" #include "hda_beep.h" enum { @@ -5455,7 +5454,7 @@ static int patch_stac9872(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_sigmatel[] = { +static struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x83847690, .name = "STAC9200", .patch = patch_stac9200 }, { .id = 0x83847882, .name = "STAC9220 A1", .patch = patch_stac922x }, { .id = 0x83847680, .name = "STAC9221 A1", .patch = patch_stac922x }, @@ -5519,3 +5518,27 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:8384*"); +MODULE_ALIAS("snd-hda-codec-id:111d*"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec"); + +static struct hda_codec_preset_list sigmatel_list = { + .preset = snd_hda_preset_sigmatel, + .owner = THIS_MODULE, +}; + +static int __init patch_sigmatel_init(void) +{ + return snd_hda_add_codec_preset(&sigmatel_list); +} + +static void __exit patch_sigmatel_exit(void) +{ + snd_hda_delete_codec_preset(&sigmatel_list); +} + +module_init(patch_sigmatel_init) +module_exit(patch_sigmatel_exit) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 05182be1c9f0..6e4d01d1d502 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -47,7 +47,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_patch.h" /* amp values */ #define AMP_VAL_IDX_SHIFT 19 @@ -3249,7 +3248,7 @@ static int patch_vt1702(struct hda_codec *codec) /* * patch entries */ -struct hda_codec_preset snd_hda_preset_via[] = { +static struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, @@ -3320,3 +3319,26 @@ struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1702}, {} /* terminator */ }; + +MODULE_ALIAS("snd-hda-codec-id:1106*"); + +static struct hda_codec_preset_list via_list = { + .preset = snd_hda_preset_via, + .owner = THIS_MODULE, +}; + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("VIA HD-audio codec"); + +static int __init patch_via_init(void) +{ + return snd_hda_add_codec_preset(&via_list); +} + +static void __exit patch_via_exit(void) +{ + snd_hda_delete_codec_preset(&via_list); +} + +module_init(patch_via_init) +module_exit(patch_via_exit) From 11cd41b893895c76a8f9bee9467f4b0869b5eeb3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 07:22:18 +0100 Subject: [PATCH 212/367] ALSA: hda - Fix build error with CONFIG_SND_HDA_POWER_SAVE Moved power_save field initialization inside a proper ifdef to fix a build error without CONFIG_SND_HDA_POWER_SAVE. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f17ccd513350..8aee322313ed 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1233,12 +1233,12 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, memset(&bus_temp, 0, sizeof(bus_temp)); bus_temp.private_data = chip; bus_temp.modelname = model; - bus_temp.power_save = &power_save; bus_temp.pci = chip->pci; bus_temp.ops.command = azx_send_cmd; bus_temp.ops.get_response = azx_get_response; bus_temp.ops.attach_pcm = azx_attach_pcm_stream; #ifdef CONFIG_SND_HDA_POWER_SAVE + bus_temp.power_save = &power_save; bus_temp.ops.pm_notify = azx_power_notify; #endif From daead538e9d8efe61d7d2bd12993c8d961b0abd6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 12:55:36 +0100 Subject: [PATCH 213/367] ALSA: hda - Add codec-specific proc hook Added a hook for proc outputs of codec-specific stuff. Moved realtek-specific coeff output into patch_realtek.c as well. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 4 ++++ sound/pci/hda/hda_proc.c | 16 ++-------------- sound/pci/hda/patch_realtek.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9fe0b67bb1e4..43af18c4a214 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -784,6 +784,10 @@ struct hda_codec { int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ #endif + + /* codec-specific additional proc output */ + void (*proc_widget_hook)(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid); }; /* direction */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 9a8498456e6c..7b3817985c34 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -414,17 +414,6 @@ static void print_conn_list(struct snd_info_buffer *buffer, } } -static void print_realtek_coef(struct snd_info_buffer *buffer, - struct hda_codec *codec, hda_nid_t nid) -{ - int coeff = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PROC_COEF, 0); - snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); - coeff = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_COEF_INDEX, 0); - snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); -} - static void print_gpio(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { @@ -606,9 +595,8 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_caps & AC_WCAP_PROC_WID) print_proc_caps(buffer, codec, nid); - /* NID 0x20 == Realtek Define Registers */ - if (codec->vendor_id == 0x10ec && nid == 0x20) - print_realtek_coef(buffer, codec, nid); + if (codec->proc_widget_hook) + codec->proc_widget_hook(buffer, codec, nid); } snd_hda_power_down(codec); } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9cd2545d988e..698c85625a42 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -766,6 +766,27 @@ static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) spec->init_verbs[spec->num_init_verbs++] = verb; } +#ifdef CONFIG_PROC_FS +/* + * hook for proc + */ +static void print_realtek_coef(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + int coeff; + + if (nid != 0x20) + return; + coeff = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); + snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); + coeff = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_COEF_INDEX, 0); + snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); +} +#else +#define print_realtek_coef NULL +#endif + /* * set up from the preset table */ @@ -4344,6 +4365,7 @@ static int patch_alc880(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc880_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -5869,6 +5891,7 @@ static int patch_alc260(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc260_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -7074,6 +7097,7 @@ static int patch_alc882(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc882_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -9042,6 +9066,7 @@ static int patch_alc883(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc883_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -10848,6 +10873,7 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc262_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -11913,6 +11939,8 @@ static int patch_alc268(struct hda_codec *codec) if (board_config == ALC268_AUTO) spec->init_hook = alc268_auto_init; + codec->proc_widget_hook = print_realtek_coef; + return 0; } @@ -12714,6 +12742,7 @@ static int patch_alc269(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc269_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -13802,6 +13831,7 @@ static int patch_alc861(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc861_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -14763,6 +14793,7 @@ static int patch_alc861vd(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc861vd_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } @@ -16572,6 +16603,7 @@ static int patch_alc662(struct hda_codec *codec) if (!spec->loopback.amplist) spec->loopback.amplist = alc662_loopbacks; #endif + codec->proc_widget_hook = print_realtek_coef; return 0; } From bb40abe223ace0b6f29e8433d3936dac664178b5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 12:57:38 +0100 Subject: [PATCH 214/367] ALSA: hda - Remove unused proc entry in hda_bus struct Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 43af18c4a214..bbbc83b387d1 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -615,8 +615,6 @@ struct hda_bus { /* unsolicited event queue */ struct hda_bus_unsolicited *unsol; - struct snd_info_entry *proc; - /* assigned PCMs */ DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES); From 2d34e1b3bb991a99322fb55681d1e73ada3de35c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 14:35:16 +0100 Subject: [PATCH 215/367] ALSA: hda - Add IDT/STAC-specific proc output Added power-map and analog-loopback information to proc output for IDT/STAC codecs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 2 ++ sound/pci/hda/patch_sigmatel.c | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 7b3817985c34..7ca66d654148 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -493,6 +493,8 @@ static void print_codec_info(struct snd_info_entry *entry, } print_gpio(buffer, codec, codec->afg); + if (codec->proc_widget_hook) + codec->proc_widget_hook(buffer, codec, codec->afg); for (i = 0; i < nodes; i++, nid++) { unsigned int wid_caps = diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 70181d500536..33170a242009 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4262,6 +4262,52 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) } } +#ifdef CONFIG_PROC_FS +static void stac92hd_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + if (nid == codec->afg) + snd_iprintf(buffer, "Power-Map: 0x%02x\n", + snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0)); +} + +static void analog_loop_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, + unsigned int verb) +{ + snd_iprintf(buffer, "Analog Loopback: 0x%02x\n", + snd_hda_codec_read(codec, codec->afg, 0, verb, 0)); +} + +/* stac92hd71bxx, stac92hd73xx */ +static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + stac92hd_proc_hook(buffer, codec, nid); + if (nid == codec->afg) + analog_loop_proc_hook(buffer, codec, 0xfa0); +} + +static void stac9205_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + if (nid == codec->afg) + analog_loop_proc_hook(buffer, codec, 0xfe0); +} + +static void stac927x_proc_hook(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + if (nid == codec->afg) + analog_loop_proc_hook(buffer, codec, 0xfeb); +} +#else +#define stac92hd_proc_hook NULL +#define stac92hd7x_proc_hook NULL +#define stac9205_proc_hook NULL +#define stac927x_proc_hook NULL +#endif + #ifdef SND_HDA_NEEDS_RESUME static int stac92xx_resume(struct hda_codec *codec) { @@ -4585,6 +4631,8 @@ again: codec->patch_ops = stac92xx_patch_ops; + codec->proc_widget_hook = stac92hd7x_proc_hook; + return 0; } @@ -4671,6 +4719,8 @@ again: codec->patch_ops = stac92xx_patch_ops; + codec->proc_widget_hook = stac92hd_proc_hook; + return 0; } @@ -4889,6 +4939,8 @@ again: return err; } + codec->proc_widget_hook = stac92hd7x_proc_hook; + return 0; }; @@ -5109,6 +5161,8 @@ static int patch_stac927x(struct hda_codec *codec) codec->patch_ops = stac92xx_patch_ops; + codec->proc_widget_hook = stac927x_proc_hook; + /* * !!FIXME!! * The STAC927x seem to require fairly long delays for certain @@ -5224,6 +5278,8 @@ static int patch_stac9205(struct hda_codec *codec) codec->patch_ops = stac92xx_patch_ops; + codec->proc_widget_hook = stac9205_proc_hook; + return 0; } From 56d17712d54d3aa3d6ef930123d692351d33217c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 14:36:23 +0100 Subject: [PATCH 216/367] ALSA: hda - Clear codec->proc_widget_hook at reset Clear the remaining pointer at snd_hda_codec_reset() to avoid Oops. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1cb85b73e19b..a867e1e8658a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1237,6 +1237,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) } if (codec->patch_ops.free) codec->patch_ops.free(codec); + codec->proc_widget_hook = NULL; codec->spec = NULL; free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); From 57a5ef483b6290a9f22d4c52baca051c1e755f3a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 14:46:28 +0100 Subject: [PATCH 217/367] ALSA: hda - Add quirk for Sony VAIO VGN-SR19XN Added model=sony-assamd for Sony VAIO VGN-SR19XN with ALC262 codec. Reference: Novell bnc#450080 https://bugzilla.novell.com/show_bug.cgi?id=450080 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 698c85625a42..40b3fcd142a3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10559,6 +10559,8 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), + SND_PCI_QUIRK(0x104d, 0x9033, "Sony VAIO VGN-SR19XN", + ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", ALC262_TOSHIBA_RX1), SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), From de04b102bfc9a13e96f0892305b394077ffb6514 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 26 Nov 2008 10:37:23 +0100 Subject: [PATCH 218/367] ALSA: oxygen: add Claro halo support Add support for the HT-Omega Claro halo (XT). Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 3 ++- sound/pci/Kconfig | 3 ++- sound/pci/oxygen/oxygen.c | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index e0e54a27fc10..0cca842a6631 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1647,7 +1647,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. * AuzenTech X-Meridian * Bgears b-Enspirer * Club3D Theatron DTS - * HT-Omega Claro + * HT-Omega Claro (plus) + * HT-Omega Claro halo (XT) * Razer Barracuda AC-1 * Sondigo Inferno diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 7003711f4fcc..611df4b72831 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -208,7 +208,8 @@ config SND_OXYGEN * AuzenTech X-Meridian * Bgears b-Enspirer * Club3D Theatron DTS - * HT-Omega Claro + * HT-Omega Claro (plus) + * HT-Omega Claro halo (XT) * Razer Barracuda AC-1 * Sondigo Inferno diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index b60f6212745a..de999c6d6dd3 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -61,6 +61,7 @@ MODULE_PARM_DESC(enable, "enable card"); enum { MODEL_CMEDIA_REF, /* C-Media's reference design */ MODEL_MERIDIAN, /* AuzenTech X-Meridian */ + MODEL_HALO, /* HT-Omega Claro halo */ }; static struct pci_device_id oxygen_ids[] __devinitdata = { @@ -74,6 +75,7 @@ static struct pci_device_id oxygen_ids[] __devinitdata = { { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = MODEL_MERIDIAN }, { OXYGEN_PCI_SUBID(0x7284, 0x9761), .driver_data = MODEL_CMEDIA_REF }, + { OXYGEN_PCI_SUBID(0x7284, 0x9781), .driver_data = MODEL_HALO }, { } }; MODULE_DEVICE_TABLE(pci, oxygen_ids); @@ -301,6 +303,8 @@ static int generic_probe(struct oxygen *chip, unsigned long driver_data) PLAYBACK_1_TO_SPDIF | CAPTURE_0_FROM_I2S_2 | CAPTURE_1_FROM_SPDIF; + } + if (driver_data == MODEL_MERIDIAN || driver_data == MODEL_HALO) { chip->model.misc_flags = OXYGEN_MISC_MIDI; chip->model.device_config |= MIDI_OUTPUT | MIDI_INPUT; } From 645f10c1ac7f733b224eaf97634edf9b20e2370e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 15:07:37 +0100 Subject: [PATCH 219/367] ALSA: hda - Check MODULE instead of CONFIG_SND_HDA_INTEL_MODULE Checking MODULE is more generic. Also a cosmetic comment change. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 4aa7b1b72877..2fff0fb77ba2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -530,10 +530,10 @@ EXPORT_SYMBOL_GPL(snd_hda_bus_new); #define is_generic_config(codec) 0 #endif -#ifdef CONFIG_SND_HDA_INTEL_MODULE +#ifdef MODULE #define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */ #else -#define HDA_MODREQ_MAX_COUNT 0 +#define HDA_MODREQ_MAX_COUNT 0 /* all presets are statically linked */ #endif /* From ff7a3267368634e368ebaac68d5e3abf129edd1d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 15:17:06 +0100 Subject: [PATCH 220/367] ALSA: hda - Don't export symbols when built-in kernel The global functions in hda_codec.c and other core parts are only for HD-audio codec and controller drivers. When the HD-audio driver is built in kernel, all stuff have to be statically linked, thus we don't need any exports. This patch introduces a conditional macro to do export only when needed. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 4 +- sound/pci/hda/hda_codec.c | 148 +++++++++++++++++++------------------- sound/pci/hda/hda_codec.h | 15 ++++ 3 files changed, 91 insertions(+), 76 deletions(-) diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e6cc9463667a..e00421c0d8ba 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -128,7 +128,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); +EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); void snd_hda_detach_beep_device(struct hda_codec *codec) { @@ -141,4 +141,4 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) kfree(beep); } } -EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); +EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2fff0fb77ba2..004344825e9e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -71,7 +71,7 @@ int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) mutex_unlock(&preset_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset); +EXPORT_SYMBOL_HDA(snd_hda_add_codec_preset); int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) { @@ -80,7 +80,7 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) mutex_unlock(&preset_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset); +EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_power_work(struct work_struct *work); @@ -114,7 +114,7 @@ const char *snd_hda_get_jack_location(u32 cfg) } return "UNKNOWN"; } -EXPORT_SYMBOL_GPL(snd_hda_get_jack_location); +EXPORT_SYMBOL_HDA(snd_hda_get_jack_location); const char *snd_hda_get_jack_connectivity(u32 cfg) { @@ -122,7 +122,7 @@ const char *snd_hda_get_jack_connectivity(u32 cfg) return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; } -EXPORT_SYMBOL_GPL(snd_hda_get_jack_connectivity); +EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity); const char *snd_hda_get_jack_type(u32 cfg) { @@ -136,7 +136,7 @@ const char *snd_hda_get_jack_type(u32 cfg) return jack_types[(cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT]; } -EXPORT_SYMBOL_GPL(snd_hda_get_jack_type); +EXPORT_SYMBOL_HDA(snd_hda_get_jack_type); /* * Compose a 32bit command word to be sent to the HD-audio controller @@ -185,7 +185,7 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, snd_hda_power_down(codec); return res; } -EXPORT_SYMBOL_GPL(snd_hda_codec_read); +EXPORT_SYMBOL_HDA(snd_hda_codec_read); /** * snd_hda_codec_write - send a single command without waiting for response @@ -214,7 +214,7 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, snd_hda_power_down(codec); return err; } -EXPORT_SYMBOL_GPL(snd_hda_codec_write); +EXPORT_SYMBOL_HDA(snd_hda_codec_write); /** * snd_hda_sequence_write - sequence writes @@ -229,7 +229,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) for (; seq->nid; seq++) snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); } -EXPORT_SYMBOL_GPL(snd_hda_sequence_write); +EXPORT_SYMBOL_HDA(snd_hda_sequence_write); /** * snd_hda_get_sub_nodes - get the range of sub nodes @@ -251,7 +251,7 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } -EXPORT_SYMBOL_GPL(snd_hda_get_sub_nodes); +EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); /** * snd_hda_get_connections - get connection list @@ -340,7 +340,7 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, } return conns; } -EXPORT_SYMBOL_GPL(snd_hda_get_connections); +EXPORT_SYMBOL_HDA(snd_hda_get_connections); /** @@ -375,7 +375,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) return 0; } -EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event); +EXPORT_SYMBOL_HDA(snd_hda_queue_unsol_event); /* * process queued unsolicited events @@ -521,7 +521,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, *busp = bus; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_bus_new); +EXPORT_SYMBOL_HDA(snd_hda_bus_new); #ifdef CONFIG_SND_HDA_GENERIC #define is_generic_config(codec) \ @@ -808,7 +808,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr *codecp = codec; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_codec_new); +EXPORT_SYMBOL_HDA(snd_hda_codec_new); int snd_hda_codec_configure(struct hda_codec *codec) { @@ -868,7 +868,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, msleep(1); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); } -EXPORT_SYMBOL_GPL(snd_hda_codec_setup_stream); +EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) { @@ -882,7 +882,7 @@ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); #endif } -EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup_stream); +EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); /* * amp access functions @@ -964,7 +964,7 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) } return info->amp_caps; } -EXPORT_SYMBOL_GPL(query_amp_caps); +EXPORT_SYMBOL_HDA(query_amp_caps); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps) @@ -978,7 +978,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, info->head.val |= INFO_AMP_CAPS; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps); +EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); /* * read the current volume to info @@ -1032,7 +1032,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; return get_vol_mute(codec, info, nid, ch, direction, index); } -EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read); +EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); /* * update the AMP value, mask = bit mask to set, val = the value @@ -1052,7 +1052,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } -EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update); +EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update); /* * update the AMP stereo with the same mask and value @@ -1066,7 +1066,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, idx, mask, val); return ret; } -EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo); +EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); #ifdef SND_HDA_NEEDS_RESUME /* resume the all amp commands from the cache */ @@ -1092,7 +1092,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) } } } -EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp); +EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ /* volume */ @@ -1120,7 +1120,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = caps; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_info); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1140,7 +1140,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, & HDA_AMP_VOLMASK; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1165,7 +1165,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put); int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) @@ -1192,7 +1192,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -EFAULT; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_tlv); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv); /* * set (static) TLV for virtual master volume; recalculated as max 0dB @@ -1212,7 +1212,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, tlv[2] = -nums * step; tlv[3] = step; } -EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv); +EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv); /* find a mixer control element with the given name */ static struct snd_kcontrol * @@ -1232,7 +1232,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, { return _snd_hda_find_mixer_ctl(codec, name, 0); } -EXPORT_SYMBOL_GPL(snd_hda_find_mixer_ctl); +EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); /* Add a control element and assign to the codec */ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) @@ -1249,7 +1249,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) *knewp = kctl; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_ctl_add); +EXPORT_SYMBOL_HDA(snd_hda_ctl_add); #ifdef CONFIG_SND_HDA_RECONFIG /* Clear all controls assigned to the given codec */ @@ -1328,7 +1328,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_add_vmaster); +EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); /* switch */ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, @@ -1342,7 +1342,7 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 1; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info); int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1362,7 +1362,7 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, HDA_AMP_MUTE) ? 0 : 1; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get); int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1393,7 +1393,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); /* * bound volume controls @@ -1419,7 +1419,7 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1443,7 +1443,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); /* * generic bound volume/swtich controls @@ -1463,7 +1463,7 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1480,7 +1480,7 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -1503,7 +1503,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->spdif_mutex); return err < 0 ? err : change; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) @@ -1520,7 +1520,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, mutex_unlock(&codec->spdif_mutex); return err; } -EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_tlv); +EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); struct hda_ctl_ops snd_hda_bind_vol = { .info = snd_hda_mixer_amp_volume_info, @@ -1528,7 +1528,7 @@ struct hda_ctl_ops snd_hda_bind_vol = { .put = snd_hda_mixer_amp_volume_put, .tlv = snd_hda_mixer_amp_tlv }; -EXPORT_SYMBOL_GPL(snd_hda_bind_vol); +EXPORT_SYMBOL_HDA(snd_hda_bind_vol); struct hda_ctl_ops snd_hda_bind_sw = { .info = snd_hda_mixer_amp_switch_info, @@ -1536,7 +1536,7 @@ struct hda_ctl_ops snd_hda_bind_sw = { .put = snd_hda_mixer_amp_switch_put, .tlv = snd_hda_mixer_amp_tlv }; -EXPORT_SYMBOL_GPL(snd_hda_bind_sw); +EXPORT_SYMBOL_HDA(snd_hda_bind_sw); /* * SPDIF out controls @@ -1798,7 +1798,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_create_spdif_out_ctls); +EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); /* * SPDIF sharing with analog output @@ -1836,7 +1836,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, return snd_hda_ctl_add(codec, snd_ctl_new1(&spdif_share_sw, mout)); } -EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw); +EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw); /* * SPDIF input @@ -1946,7 +1946,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) AC_DIG1_ENABLE; return 0; } -EXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls); +EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); #ifdef SND_HDA_NEEDS_RESUME /* @@ -1992,7 +1992,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, snd_hda_power_down(codec); return err; } -EXPORT_SYMBOL_GPL(snd_hda_codec_write_cache); +EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); /* resume the all commands from the cache */ void snd_hda_codec_resume_cache(struct hda_codec *codec) @@ -2008,7 +2008,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec) get_cmd_cache_cmd(key), buffer->val); } } -EXPORT_SYMBOL_GPL(snd_hda_codec_resume_cache); +EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache); /** * snd_hda_sequence_write_cache - sequence writes with caching @@ -2026,7 +2026,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, seq->param); } -EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache); +EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); #endif /* SND_HDA_NEEDS_RESUME */ /* @@ -2156,7 +2156,7 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_build_controls); +EXPORT_SYMBOL_HDA(snd_hda_build_controls); int snd_hda_codec_build_controls(struct hda_codec *codec) { @@ -2268,7 +2268,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, return val; } -EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format); +EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); /** * snd_hda_query_supported_pcm - query the supported PCM rates and formats @@ -2448,7 +2448,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, return 1; } -EXPORT_SYMBOL_GPL(snd_hda_is_supported_format); +EXPORT_SYMBOL_HDA(snd_hda_is_supported_format); /* * PCM stuff @@ -2646,7 +2646,7 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_build_pcms); +EXPORT_SYMBOL_HDA(snd_hda_build_pcms); /** * snd_hda_check_board_config - compare the current codec with the config table @@ -2702,7 +2702,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, } return -1; } -EXPORT_SYMBOL_GPL(snd_hda_check_board_config); +EXPORT_SYMBOL_HDA(snd_hda_check_board_config); /** * snd_hda_add_new_ctls - create controls from the array @@ -2738,7 +2738,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); +EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, @@ -2781,7 +2781,7 @@ void snd_hda_power_up(struct hda_codec *codec) cancel_delayed_work(&codec->power_work); codec->power_transition = 0; } -EXPORT_SYMBOL_GPL(snd_hda_power_up); +EXPORT_SYMBOL_HDA(snd_hda_power_up); #define power_save(codec) \ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) @@ -2800,7 +2800,7 @@ void snd_hda_power_down(struct hda_codec *codec) msecs_to_jiffies(power_save(codec) * 1000)); } } -EXPORT_SYMBOL_GPL(snd_hda_power_down); +EXPORT_SYMBOL_HDA(snd_hda_power_down); int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, @@ -2837,7 +2837,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); +EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); #endif /* @@ -2857,7 +2857,7 @@ int snd_hda_ch_mode_info(struct hda_codec *codec, chmode[uinfo->value.enumerated.item].channels); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info); +EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info); int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2875,7 +2875,7 @@ int snd_hda_ch_mode_get(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get); +EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get); int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, @@ -2896,7 +2896,7 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } -EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put); +EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put); /* * input MUX helper @@ -2917,7 +2917,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, strcpy(uinfo->value.enumerated.name, imux->items[index].label); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_input_mux_info); +EXPORT_SYMBOL_HDA(snd_hda_input_mux_info); int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, @@ -2939,7 +2939,7 @@ int snd_hda_input_mux_put(struct hda_codec *codec, *cur_val = idx; return 1; } -EXPORT_SYMBOL_GPL(snd_hda_input_mux_put); +EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); /* @@ -2992,7 +2992,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open); int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, @@ -3005,7 +3005,7 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); /* * release the digital out @@ -3018,7 +3018,7 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close); /* * set up more restrictions for analog out @@ -3058,7 +3058,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, return snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open); /* * set up the i/o for analog out @@ -3117,7 +3117,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); /* * clean up the setting for analog out @@ -3144,7 +3144,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup); +EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup); /* * Helper for automatic pin configuration @@ -3430,13 +3430,13 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, return 0; } -EXPORT_SYMBOL_GPL(snd_hda_parse_pin_def_config); +EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config); /* labels for input pins */ const char *auto_pin_cfg_labels[AUTO_PIN_LAST] = { "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux" }; -EXPORT_SYMBOL_GPL(auto_pin_cfg_labels); +EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); #ifdef CONFIG_PM @@ -3464,7 +3464,7 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_suspend); +EXPORT_SYMBOL_HDA(snd_hda_suspend); /** * snd_hda_resume - resume the codecs @@ -3485,7 +3485,7 @@ int snd_hda_resume(struct hda_bus *bus) } return 0; } -EXPORT_SYMBOL_GPL(snd_hda_resume); +EXPORT_SYMBOL_HDA(snd_hda_resume); #endif /* CONFIG_PM */ /* @@ -3515,7 +3515,7 @@ void *snd_array_new(struct snd_array *array) } return snd_array_elem(array, array->used++); } -EXPORT_SYMBOL_GPL(snd_array_new); +EXPORT_SYMBOL_HDA(snd_array_new); /* free the given array elements */ void snd_array_free(struct snd_array *array) @@ -3525,7 +3525,7 @@ void snd_array_free(struct snd_array *array) array->alloced = 0; array->list = NULL; } -EXPORT_SYMBOL_GPL(snd_array_free); +EXPORT_SYMBOL_HDA(snd_array_free); /* * used by hda_proc.c and hda_eld.c @@ -3544,7 +3544,7 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -EXPORT_SYMBOL_GPL(snd_print_pcm_rates); +EXPORT_SYMBOL_HDA(snd_print_pcm_rates); void snd_print_pcm_bits(int pcm, char *buf, int buflen) { @@ -3557,7 +3557,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -EXPORT_SYMBOL_GPL(snd_print_pcm_bits); +EXPORT_SYMBOL_HDA(snd_print_pcm_bits); MODULE_DESCRIPTION("HDA codec core"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 586ea08b340b..6612d0f20bc6 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -905,4 +905,19 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {} #define snd_hda_codec_needs_resume(codec) 1 #endif +/* + * Codec modularization + */ + +/* Export symbols only for communication with codec drivers; + * When built in kernel, all HD-audio drivers are supposed to be statically + * linked to the kernel. Thus, the symbols don't have to (or shouldn't) be + * exported unless it's built as a module. + */ +#ifdef MODULE +#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym) +#else +#define EXPORT_SYMBOL_HDA(sym) +#endif + #endif /* __SOUND_HDA_CODEC_H */ From 36adba1fc79851949c4792f2e9b4d0dddbc6d5e4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 15:27:11 +0100 Subject: [PATCH 221/367] ALSA: hda - Remove EXPERIMENTAL from CONFIG_SND_HDA_POWER_SAVE It's mature enough now. Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7c60f1a45a8d..ccf7326a667a 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -122,7 +122,6 @@ config SND_HDA_GENERIC config SND_HDA_POWER_SAVE bool "Aggressive power-saving on HD-audio" - depends on EXPERIMENTAL help Say Y here to enable more aggressive power-saving mode on HD-audio driver. The power-saving timeout can be configured From 02834f112d159eb87b584c7df56bddc5beeff5b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Nov 2008 15:29:01 +0100 Subject: [PATCH 222/367] ALSA: ac97 - Remove EXPERIMENTAL from CONFIG_SND_AC97_POWER_SAVE It's mature enough now. Signed-off-by: Takashi Iwai --- sound/drivers/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 255fd18b9aec..0bcf14640fde 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -163,7 +163,7 @@ config SND_ML403_AC97CR config SND_AC97_POWER_SAVE bool "AC97 Power-Saving Mode" - depends on SND_AC97_CODEC && EXPERIMENTAL + depends on SND_AC97_CODEC default n help Say Y here to enable the aggressive power-saving support of From c9b46f9144b8dce6c12aec08f34a908aedd28b37 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 11:42:09 +0100 Subject: [PATCH 223/367] ALSA: hda - Use amp cache for SPDIF mute controls in patch_sigmatel.c The amp switch of SPDIF outputs have to be cached in the amp cache instead of codec cache. Otherwise it conflicts with the IEC958 playback switch control in hda_codec.c. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 33170a242009..068a77ae459e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -590,12 +590,12 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, else nid = codec->slave_dig_outs[smux_idx - 1]; if (spec->cur_smux[smux_idx] == smux->num_items - 1) - val = AMP_OUT_MUTE; + val = HDA_AMP_MUTE; else - val = AMP_OUT_UNMUTE; + val = 0; /* un/mute SPDIF out */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); + snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, + HDA_AMP_MUTE, val); } return 0; } From 8c2f767bf3c4a7932898e657c6b12a2234cd2eca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 11:54:35 +0100 Subject: [PATCH 224/367] ALSA: hda - Remove unnecessary caches for power states in patch_sigmatel.c The power-state changes in patch_sigmatel.c are accessed via *_cached() but they shouldn't be really cached. Fixed to the normal write. Also, stac92hd71xx_suspend and resume are no longer necessary as the power-state changes are handled properly in the common routine. Removed these hacks now. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 62 ++++------------------------------ 1 file changed, 6 insertions(+), 56 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 068a77ae459e..14db35a61cfe 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2413,7 +2413,7 @@ static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, if (spec->powerdown_adcs) { msleep(40); - snd_hda_codec_write_cache(codec, nid, 0, + 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); @@ -2429,7 +2429,7 @@ static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, snd_hda_codec_cleanup_stream(codec, nid); if (spec->powerdown_adcs) - snd_hda_codec_write_cache(codec, nid, 0, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); return 0; } @@ -3866,7 +3866,7 @@ static void stac92xx_power_down(struct hda_codec *codec) for (dac = spec->dac_list; *dac; dac++) if (!is_in_dac_nids(spec, *dac) && spec->multiout.hp_nid != *dac) - snd_hda_codec_write_cache(codec, *dac, 0, + snd_hda_codec_write(codec, *dac, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } @@ -3885,7 +3885,7 @@ static int stac92xx_init(struct hda_codec *codec) /* power down adcs initially */ if (spec->powerdown_adcs) for (i = 0; i < spec->num_adcs; i++) - snd_hda_codec_write_cache(codec, + snd_hda_codec_write(codec, spec->adc_nids[i], 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); @@ -4724,48 +4724,6 @@ again: return 0; } -#ifdef SND_HDA_NEEDS_RESUME -static void stac92hd71xx_set_power_state(struct hda_codec *codec, int pwr) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_POWER_STATE, pwr); - - msleep(1); - for (i = 0; i < spec->num_adcs; i++) { - snd_hda_codec_write_cache(codec, - spec->adc_nids[i], 0, - AC_VERB_SET_POWER_STATE, pwr); - } -}; - -static int stac92hd71xx_resume(struct hda_codec *codec) -{ - stac92hd71xx_set_power_state(codec, AC_PWRST_D0); - return stac92xx_resume(codec); -} - -static int stac92hd71xx_suspend(struct hda_codec *codec, pm_message_t state) -{ - stac92hd71xx_set_power_state(codec, AC_PWRST_D3); - return stac92xx_suspend(codec, state); -}; - -#endif - -static struct hda_codec_ops stac92hd71bxx_patch_ops = { - .build_controls = stac92xx_build_controls, - .build_pcms = stac92xx_build_pcms, - .init = stac92xx_init, - .free = stac92xx_free, - .unsol_event = stac92xx_unsol_event, -#ifdef SND_HDA_NEEDS_RESUME - .suspend = stac92hd71xx_suspend, - .resume = stac92hd71xx_resume, -#endif -}; - static struct hda_input_mux stac92hd71bxx_dmux = { .num_items = 4, .items = { @@ -4842,12 +4800,8 @@ again: break; } if ((codec->revision_id & 0xf) == 0 || - (codec->revision_id & 0xf) == 1) { -#ifdef SND_HDA_NEEDS_RESUME - codec->patch_ops = stac92hd71bxx_patch_ops; -#endif + (codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ - } /* no output amps */ spec->num_pwrs = 0; @@ -4859,12 +4813,8 @@ again: stac_change_pin_config(codec, 0xf, 0x40f000f0); break; case 0x111d7603: /* 6 Port with Analog Mixer */ - if ((codec->revision_id & 0xf) == 1) { -#ifdef SND_HDA_NEEDS_RESUME - codec->patch_ops = stac92hd71bxx_patch_ops; -#endif + if ((codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ - } /* no output amps */ spec->num_pwrs = 0; From 480cf663e6988b3e79b570b42d2dbdb6c2ba9b94 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 15:28:07 +0100 Subject: [PATCH 225/367] ALSA: Fix a compile warning in cs46xx_lib.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a build warning sound/pci/cs46xx/cs46xx_lib.c:3643: warning: unused variable ‘i’ when CONFIG_SND_CS46XX_NEW_DSP=n. Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/cs46xx_lib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index fb6dc3980257..8ab07aa63652 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3640,7 +3640,10 @@ int snd_cs46xx_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct snd_cs46xx *chip = card->private_data; - int i, amp_saved; + int amp_saved; +#ifdef CONFIG_SND_CS46XX_NEW_DSP + int i; +#endif pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); From ade9b2fb9bf8114f77eefc70b9042417e62acf72 Mon Sep 17 00:00:00 2001 From: Markus Bollinger Date: Mon, 1 Dec 2008 15:31:06 +0100 Subject: [PATCH 226/367] ALSA: pcxhr - change firmware filenames - compatibility issue : change firmware filenames the pcxhr driver version <= 1.0.18a does not work with new firmware > 1.0.17. Keep the old firmware files and add new firmware files with different names Signed-off-by: Markus Bollinger Signed-off-by: Takashi Iwai --- sound/pci/pcxhr/pcxhr_hwdep.c | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index ea50018d785b..592743a298b0 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -366,18 +366,18 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) { static char *fw_files[][5] = { - [0] = { "xi_1_882.dat", "xc_1_882.dat", - "e321_512.e56", "b321_512.b56", "d321_512.d56" }, - [1] = { "xi_1_882.dat", "xc_882e.dat", - "e321_512.e56", "b882e.b56", "d321_512.d56" }, - [2] = { "xi_1_882.dat", "xc_1222.dat", - "e321_512.e56", "b1222.b56", "d1222.d56" }, - [3] = { "xi_1_882.dat", "xc_1222e.dat", - "e321_512.e56", "b1222e.b56", "d1222.d56" }, - [4] = { NULL, "x1_222hr.dat", - "e924.e56", "b924.b56", "l_1_222.d56" }, - [5] = { NULL, "x1_924hr.dat", - "e924.e56", "b924.b56", "l_1_222.d56" }, + [0] = { "xlxint.dat", "xlxc882hr.dat", + "dspe882.e56", "dspb882hr.b56", "dspd882.d56" }, + [1] = { "xlxint.dat", "xlxc882e.dat", + "dspe882.e56", "dspb882e.b56", "dspd882.d56" }, + [2] = { "xlxint.dat", "xlxc1222hr.dat", + "dspe882.e56", "dspb1222hr.b56", "dspd1222.d56" }, + [3] = { "xlxint.dat", "xlxc1222e.dat", + "dspe882.e56", "dspb1222e.b56", "dspd1222.d56" }, + [4] = { NULL, "xlxc222.dat", + "dspe924.e56", "dspb924.b56", "dspd222.d56" }, + [5] = { NULL, "xlxc924.dat", + "dspe924.e56", "dspb924.b56", "dspd222.d56" }, }; char path[32]; @@ -404,25 +404,25 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) return 0; } -MODULE_FIRMWARE("pcxhr/xi_1_882.dat"); -MODULE_FIRMWARE("pcxhr/xc_1_882.dat"); -MODULE_FIRMWARE("pcxhr/xc_882e.dat"); -MODULE_FIRMWARE("pcxhr/e321_512.e56"); -MODULE_FIRMWARE("pcxhr/b321_512.b56"); -MODULE_FIRMWARE("pcxhr/b882e.b56"); -MODULE_FIRMWARE("pcxhr/d321_512.d56"); +MODULE_FIRMWARE("pcxhr/xlxint.dat"); +MODULE_FIRMWARE("pcxhr/xlxc882hr.dat"); +MODULE_FIRMWARE("pcxhr/xlxc882e.dat"); +MODULE_FIRMWARE("pcxhr/dspe882.e56"); +MODULE_FIRMWARE("pcxhr/dspb882hr.b56"); +MODULE_FIRMWARE("pcxhr/dspb882e.b56"); +MODULE_FIRMWARE("pcxhr/dspd882.d56"); -MODULE_FIRMWARE("pcxhr/xc_1222.dat"); -MODULE_FIRMWARE("pcxhr/xc_1222e.dat"); -MODULE_FIRMWARE("pcxhr/b1222.b56"); -MODULE_FIRMWARE("pcxhr/b1222e.b56"); -MODULE_FIRMWARE("pcxhr/d1222.d56"); +MODULE_FIRMWARE("pcxhr/xlxc1222hr.dat"); +MODULE_FIRMWARE("pcxhr/xlxc1222e.dat"); +MODULE_FIRMWARE("pcxhr/dspb1222hr.b56"); +MODULE_FIRMWARE("pcxhr/dspb1222e.b56"); +MODULE_FIRMWARE("pcxhr/dspd1222.d56"); -MODULE_FIRMWARE("pcxhr/x1_222hr.dat"); -MODULE_FIRMWARE("pcxhr/x1_924hr.dat"); -MODULE_FIRMWARE("pcxhr/e924.e56"); -MODULE_FIRMWARE("pcxhr/b924.b56"); -MODULE_FIRMWARE("pcxhr/l_1_222.d56"); +MODULE_FIRMWARE("pcxhr/xlxc222.dat"); +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 */ From 9171e5e6a20a9cd4992ff9c7cbee13c6fdf7b0b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 15:39:13 +0100 Subject: [PATCH 227/367] ALSA: soc - Fix compile warnings in wm8903.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hide annoying uninitialized warnings: sound/soc/codecs/wm8903.c:382: warning: ‘reg’ may be used uninitialized in this function sound/soc/codecs/wm8903.c:383: warning: ‘shift’ may be used uninitialized in this function Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8903.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index efbe8927b7d2..78070b2cd480 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -379,8 +379,8 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, struct wm8903_priv *wm8903 = codec->private_data; struct i2c_client *i2c = codec->control_data; u16 val; - u16 reg; - int shift; + u16 uninitialized_var(reg); + int uninitialized_var(shift); u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0); switch (w->reg) { From 1966bbd62ce31cef0cb020a6b4bd852dbc63b40c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Dec 2008 14:54:45 +0000 Subject: [PATCH 228/367] ALSA: ac97 - Add WM9715 to AC97 IDs The WM9715 is software compatible with the WM9711 and WM9712. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index bd510eceff1f..e2b843b4f9d0 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -175,7 +175,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x574d4C04, 0xffffffff, "WM9704M,WM9704Q", patch_wolfson04, NULL}, { 0x574d4C05, 0xffffffff, "WM9705,WM9710", patch_wolfson05, NULL}, { 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL}, -{ 0x574d4C12, 0xffffffff, "WM9711,WM9712", patch_wolfson11, NULL}, +{ 0x574d4C12, 0xffffffff, "WM9711,WM9712,WM9715", patch_wolfson11, NULL}, { 0x574d4c13, 0xffffffff, "WM9713,WM9714", patch_wolfson13, NULL, AC97_DEFAULT_POWER_OFF}, { 0x594d4800, 0xffffffff, "YMF743", patch_yamaha_ymf743, NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, From f5d4c67e41a262f0cdfaec1bb0fa8e5952187ef9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 16:29:47 +0100 Subject: [PATCH 229/367] ALSA: soc - Remove obsoleted sound/driver.h inclusion Signed-off-by: Takashi Iwai --- sound/soc/pxa/em-x270.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index 4a61925c3104..d6884b755d55 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include From 2caf6a1f9c8bcdc81ba580cfbf512d073c9444be Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 17:56:06 +0100 Subject: [PATCH 230/367] ALSA: ASoC: Remove superfluous dependency on SND_SOC The dependency on SND_SOC is already fulfilled in sound/soc/Kconfig, thus no more need in Kconfig of each sub directory. Signed-off-by: Takashi Iwai --- sound/soc/blackfin/Kconfig | 4 ++-- sound/soc/fsl/Kconfig | 2 +- sound/soc/omap/Kconfig | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index e162cbbd3f3b..0a2f8f9eff53 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -1,6 +1,6 @@ config SND_BF5XX_I2S tristate "SoC I2S Audio for the ADI BF5xx chip" - depends on BLACKFIN && SND_SOC + depends on BLACKFIN help Say Y or M if you want to add support for codecs attached to the Blackfin SPORT (synchronous serial ports) interface in I2S @@ -34,7 +34,7 @@ config SND_BFIN_AD73311_SE config SND_BF5XX_AC97 tristate "SoC AC97 Audio for the ADI BF5xx chip" - depends on BLACKFIN && SND_SOC + depends on BLACKFIN help Say Y or M if you want to add support for codecs attached to the Blackfin SPORT (synchronous serial ports) interface in slot 16 diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 8d73edc56102..95c12b26fe37 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -20,7 +20,7 @@ config SND_SOC_MPC8610_HPCD config SND_SOC_MPC5200_I2S tristate "Freescale MPC5200 PSC in I2S mode driver" - depends on SND_SOC && PPC_MPC52xx && PPC_BESTCOMM + depends on PPC_MPC52xx && PPC_BESTCOMM select SND_SOC_OF_SIMPLE select PPC_BESTCOMM_GEN_BD help diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 9a869390abb9..da39f27c6613 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -1,6 +1,6 @@ config SND_OMAP_SOC tristate "SoC Audio for the Texas Instruments OMAP chips" - depends on ARCH_OMAP && SND_SOC + depends on ARCH_OMAP config SND_OMAP_SOC_MCBSP tristate From 0bc286e2ac72e483d2b5a6dac0dafb05e9f047c8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 19:59:35 +0100 Subject: [PATCH 231/367] Revert "ALSA: soc - Fix compile warnings in wm8903.c" This reverts commit 9171e5e6a20a9cd4992ff9c7cbee13c6fdf7b0b1. I can't reproduce the compile warnings any more. The warnings might be some weird cross-compiling set up. Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8903.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 78070b2cd480..efbe8927b7d2 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -379,8 +379,8 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, struct wm8903_priv *wm8903 = codec->private_data; struct i2c_client *i2c = codec->control_data; u16 val; - u16 uninitialized_var(reg); - int uninitialized_var(shift); + u16 reg; + int shift; u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0); switch (w->reg) { From 5220ed6b321639d68a66bad2082456c1b273f3ea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 20:00:47 +0100 Subject: [PATCH 232/367] ALSA: ASoC: Fix compile warnings on corgi.c Fix the wrong shutdown callback type. Also removed the unused variables there: sound/soc/pxa/corgi.c: In function 'corgi_shutdown': sound/soc/pxa/corgi.c:114: warning: unused variable 'codec' sound/soc/pxa/corgi.c: At top level: sound/soc/pxa/corgi.c:175: warning: initialization from incompatible pointer type Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/pxa/corgi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 647f056a3cb3..e56bf4b6c2af 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -108,15 +108,11 @@ static int corgi_startup(struct snd_pcm_substream *substream) } /* we need to unmute the HP at shutdown as the mute burns power on corgi */ -static int corgi_shutdown(struct snd_pcm_substream *substream) +static void corgi_shutdown(struct snd_pcm_substream *substream) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->socdev->codec; - /* set = unmute headphone */ gpio_set_value(CORGI_GPIO_MUTE_L, 1); gpio_set_value(CORGI_GPIO_MUTE_R, 1); - return 0; } static int corgi_hw_params(struct snd_pcm_substream *substream, From 682d5874f3d654b5d13d9b8dd56b9e05cfadd01b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 1 Dec 2008 20:03:54 +0100 Subject: [PATCH 233/367] ALSA: ASoC: Fix old-style trigger callback in s3c2443-ac97.c Fix the old-style trigger callback in s3c2443-ac97.c: sound/soc/s3c24xx/s3c2443-ac97.c:378: warning: initialization from incompatible pointer type Signed-off-by: Takashi Iwai --- sound/soc/s3c24xx/s3c2443-ac97.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 41bde6a3883b..f0bc9b7e0840 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -285,7 +285,8 @@ static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream, return 0; } -static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd) +static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { u32 ac_glbctrl; From 968a6025aa9f909d487988efb542217a126023a0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 28 Nov 2008 11:49:07 +0000 Subject: [PATCH 234/367] ASoC: Rename snd_soc_register_card() to snd_soc_init_card() Currently ASoC card initialisation is completed by a function called snd_soc_register_card(). As part of the work to allow independant registration of cards, codecs and machines in ASoC v2 a new function of the same name has been added so rename the existing function to facilitate the merge of v2. Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- sound/soc/codecs/ac97.c | 2 +- sound/soc/codecs/ad1980.c | 2 +- sound/soc/codecs/ad73311.c | 2 +- sound/soc/codecs/ak4535.c | 2 +- sound/soc/codecs/cs4270.c | 2 +- sound/soc/codecs/pcm3008.c | 2 +- sound/soc/codecs/ssm2602.c | 2 +- sound/soc/codecs/tlv320aic23.c | 2 +- sound/soc/codecs/tlv320aic26.c | 2 +- sound/soc/codecs/tlv320aic3x.c | 2 +- sound/soc/codecs/twl4030.c | 2 +- sound/soc/codecs/uda134x.c | 2 +- sound/soc/codecs/uda1380.c | 2 +- sound/soc/codecs/wm8510.c | 2 +- sound/soc/codecs/wm8580.c | 2 +- sound/soc/codecs/wm8728.c | 2 +- sound/soc/codecs/wm8731.c | 2 +- sound/soc/codecs/wm8750.c | 2 +- sound/soc/codecs/wm8753.c | 2 +- sound/soc/codecs/wm8900.c | 2 +- sound/soc/codecs/wm8903.c | 2 +- sound/soc/codecs/wm8971.c | 2 +- sound/soc/codecs/wm8990.c | 2 +- sound/soc/codecs/wm9712.c | 2 +- sound/soc/codecs/wm9713.c | 2 +- sound/soc/soc-core.c | 6 +++--- 27 files changed, 29 insertions(+), 29 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 444f9c211379..9356c1ce98c1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -162,7 +162,7 @@ extern struct snd_ac97_bus_ops soc_ac97_ops; /* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); -int snd_soc_register_card(struct snd_soc_device *socdev); +int snd_soc_init_card(struct snd_soc_device *socdev); /* set runtime hw params */ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream, diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index c4208c8210c8..fb53e6511af2 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -114,7 +114,7 @@ static int ac97_soc_probe(struct platform_device *pdev) if (ret < 0) goto bus_err; - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) goto bus_err; return 0; diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index a9a268112d3f..73fdbb4d4a3d 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -270,7 +270,7 @@ static int ad1980_soc_probe(struct platform_device *pdev) ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); ad1980_add_controls(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register card\n"); goto reset_err; diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 59c4c8f18cbb..0f4110f4bceb 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -67,7 +67,7 @@ static int ad73311_soc_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "ad73311: failed to register card\n"); goto register_err; diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index c742290e5533..23062c952e85 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -512,7 +512,7 @@ static int ak4535_init(struct snd_soc_device *socdev) ak4535_add_controls(codec); ak4535_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "ak4535: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 7507d468b200..4667a07b566c 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -723,7 +723,7 @@ static int cs4270_probe(struct platform_device *pdev) printk(KERN_INFO "cs4270: I2C disabled, using stand-alone mode\n"); #endif - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "cs4270: failed to register card\n"); goto error_del_driver; diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 651a15eb8c2c..a5862555b444 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -91,7 +91,7 @@ static int pcm3008_soc_probe(struct platform_device *pdev) } /* Register Card. */ - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "pcm3008: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 0c5884ea1b00..973844973fe1 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -624,7 +624,7 @@ static int ssm2602_init(struct snd_soc_device *socdev) ssm2602_add_controls(codec); ssm2602_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { pr_err("ssm2602: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index a4e13d0688c9..d209bec02a69 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -720,7 +720,7 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) tlv320aic23_add_controls(codec); tlv320aic23_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "tlv320aic23: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 6b7ddfc92573..e33fb7e00d1e 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -359,7 +359,7 @@ static int aic26_probe(struct platform_device *pdev) /* CODEC is setup, we can register the card now */ dev_dbg(&pdev->dev, "Registering card\n"); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { dev_err(&pdev->dev, "aic26: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 255e784c805b..0f4067bdd4a3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1187,7 +1187,7 @@ static int aic3x_init(struct snd_soc_device *socdev) aic3x_add_controls(codec); aic3x_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "aic3x: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 413623147891..f3e9e591b52f 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -764,7 +764,7 @@ static int twl4030_init(struct snd_soc_device *socdev) twl4030_add_controls(codec); twl4030_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "twl4030: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 91f333cdc7cf..58de749185e6 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -578,7 +578,7 @@ static int uda134x_soc_probe(struct platform_device *pdev) goto pcm_err; } - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "UDA134X: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 330877c70699..42491650593f 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -677,7 +677,7 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk) /* uda1380 init */ uda1380_add_controls(codec); uda1380_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { pr_err("uda1380: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 173b66c0c766..126c70f749d1 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -658,7 +658,7 @@ static int wm8510_init(struct snd_soc_device *socdev) wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8510_add_controls(codec); wm8510_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8510: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 220d4b68904a..572a31de3219 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -869,7 +869,7 @@ static int wm8580_init(struct snd_soc_device *socdev) wm8580_add_controls(codec); wm8580_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8580: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 71949bd320d3..28f12c6a6ac8 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -332,7 +332,7 @@ static int wm8728_init(struct snd_soc_device *socdev) wm8728_add_controls(codec); wm8728_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8728: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index c0f277053bb2..403dea13b5d9 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -545,7 +545,7 @@ static int wm8731_init(struct snd_soc_device *socdev) wm8731_add_controls(codec); wm8731_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8731: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 860a1d56830a..979446f5c983 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -818,7 +818,7 @@ static int wm8750_init(struct snd_soc_device *socdev) wm8750_add_controls(codec); wm8750_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8750: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 5e4cd3bb824a..96c0453fffb3 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1605,7 +1605,7 @@ static int wm8753_init(struct snd_soc_device *socdev) wm8753_add_controls(codec); wm8753_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8753: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index d1326be91c8b..29cd83991c5b 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1365,7 +1365,7 @@ static int wm8900_init(struct snd_soc_device *socdev) wm8900_add_controls(codec); wm8900_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { dev_err(&i2c_client->dev, "Failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index efbe8927b7d2..393a4c198823 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1648,7 +1648,7 @@ static int wm8903_init(struct snd_soc_device *socdev) wm8903_add_controls(codec); wm8903_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { dev_err(&i2c->dev, "wm8903: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 26edcc9d6e87..53e6937e9ba1 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -747,7 +747,7 @@ static int wm8971_init(struct snd_soc_device *socdev) wm8971_add_controls(codec); wm8971_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8971: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 13926516d16e..5c5128b6b453 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1462,7 +1462,7 @@ static int wm8990_init(struct snd_soc_device *socdev) wm8990_add_controls(codec); wm8990_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm8990: failed to register card\n"); goto card_err; diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 40f14061fb72..af83d629078a 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -700,7 +700,7 @@ static int wm9712_soc_probe(struct platform_device *pdev) wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm9712_add_controls(codec); wm9712_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) { printk(KERN_ERR "wm9712: failed to register card\n"); goto reset_err; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 9dad0bffcb05..49962a88770d 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1247,7 +1247,7 @@ static int wm9713_soc_probe(struct platform_device *pdev) wm9713_add_controls(codec); wm9713_add_widgets(codec); - ret = snd_soc_register_card(socdev); + ret = snd_soc_init_card(socdev); if (ret < 0) goto reset_err; return 0; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 13b4aaff0e9c..0448708245e7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1233,7 +1233,7 @@ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) EXPORT_SYMBOL_GPL(snd_soc_new_pcms); /** - * snd_soc_register_card - register sound card + * snd_soc_init_card - register sound card * @socdev: the SoC audio device * * Register a SoC sound card. Also registers an AC97 device if the @@ -1241,7 +1241,7 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms); * * Returns 0 for success, else error. */ -int snd_soc_register_card(struct snd_soc_device *socdev) +int snd_soc_init_card(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->codec; struct snd_soc_card *card = socdev->card; @@ -1298,7 +1298,7 @@ int snd_soc_register_card(struct snd_soc_device *socdev) out: return ret; } -EXPORT_SYMBOL_GPL(snd_soc_register_card); +EXPORT_SYMBOL_GPL(snd_soc_init_card); /** * snd_soc_free_pcms - free sound card and pcms From 7d8c16a6f728f0ee5c42d1d731923cfd0cc19971 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Nov 2008 22:11:24 +0000 Subject: [PATCH 235/367] ASoC: Annotate core removal function Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0448708245e7..7eb2ea1fd42e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1952,7 +1952,7 @@ static int __devinit snd_soc_init(void) return platform_driver_register(&soc_driver); } -static void snd_soc_exit(void) +static void __exit snd_soc_exit(void) { platform_driver_unregister(&soc_driver); } From fa5c76978cee331b25e6d271482cf8e76f51e68b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Nov 2008 22:55:46 +0000 Subject: [PATCH 236/367] ASoC: Remove in-code changelog from AD73311 driver Signed-off-by: Mark Brown --- sound/soc/codecs/ad73311.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 0f4110f4bceb..500f9f3363d1 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -8,9 +8,6 @@ * 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. - * - * Revision history - * 25th Sep 2008 Initial version. */ #include From 381a22b564ff5a7ada09ad9a0831246da1dc5513 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Dec 2008 10:03:45 +0200 Subject: [PATCH 237/367] ASoC: TWL4030: Change the capture volume control to TLV The digital Capture gain control has a range: 0 to 31 dB in 1 dB steps. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index f3e9e591b52f..4b7a2d173a4a 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -360,6 +360,12 @@ static DECLARE_TLV_DB_SCALE(master_tlv, -6300, 100, 1); */ static DECLARE_TLV_DB_SCALE(master_coarse_tlv, 0, 600, 0); +/* + * Capture gain after the ADCs + * from 0 dB to 31 dB in 1 dB steps + */ +static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("Master Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, @@ -367,9 +373,11 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("Master PCM Playback Volume", TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, 6, 0x2, 0, master_coarse_tlv), - SOC_DOUBLE_R("Capture Volume", - TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, - 0, 0x1f, 0), + + /* Common capture gain controls */ + SOC_DOUBLE_R_TLV("Capture Volume", + TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, + 0, 0x1f, 0, digital_capture_tlv), }; /* add non dapm controls */ From d889a72c5c71161d6f934f9d7fca0e5b7e52bc08 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Dec 2008 10:03:46 +0200 Subject: [PATCH 238/367] ASoC: TWL4030: Change the common playback volume controls Add Playback volume controls for all four DACs. All four paths has three levels of volume controls: Digital Fine gain, Digital Coarse gain, Analog gain. The controls are named to reflect their connection to the DACs. Per DAC volume can be performed, if needed: amixer sset 'DAC1 Analog' 5,10 DACL1 analog gain to 5 DACR1 analog gain to 10 Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4b7a2d173a4a..1dae73af5273 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -351,14 +351,20 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) */ -static DECLARE_TLV_DB_SCALE(master_tlv, -6300, 100, 1); +static DECLARE_TLV_DB_SCALE(digital_fine_tlv, -6300, 100, 1); /* * CGAIN volume control: * 0 dB to 12 dB in 6 dB steps * value 2 and 3 means 12 dB */ -static DECLARE_TLV_DB_SCALE(master_coarse_tlv, 0, 600, 0); +static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0); + +/* + * Analog playback gain + * -24 dB to 12 dB in 2 dB steps + */ +static DECLARE_TLV_DB_SCALE(analog_tlv, -2400, 200, 0); /* * Capture gain after the ADCs @@ -367,12 +373,27 @@ static DECLARE_TLV_DB_SCALE(master_coarse_tlv, 0, 600, 0); static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); static const struct snd_kcontrol_new twl4030_snd_controls[] = { - SOC_DOUBLE_R_TLV("Master Playback Volume", - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 0, 0x3f, 0, master_tlv), - SOC_DOUBLE_R_TLV("Master PCM Playback Volume", - TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, - 6, 0x2, 0, master_coarse_tlv), + /* Common playback gain controls */ + SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", + TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, + 0, 0x3f, 0, digital_fine_tlv), + SOC_DOUBLE_R_TLV("DAC2 Digital Fine Playback Volume", + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, + 0, 0x3f, 0, digital_fine_tlv), + + SOC_DOUBLE_R_TLV("DAC1 Digital Coarse Playback Volume", + TWL4030_REG_ARXL1PGA, TWL4030_REG_ARXR1PGA, + 6, 0x2, 0, digital_coarse_tlv), + SOC_DOUBLE_R_TLV("DAC2 Digital Coarse Playback Volume", + TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA, + 6, 0x2, 0, digital_coarse_tlv), + + SOC_DOUBLE_R_TLV("DAC1 Analog Playback Volume", + TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL, + 3, 0x12, 1, analog_tlv), + SOC_DOUBLE_R_TLV("DAC2 Analog Playback Volume", + TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, + 3, 0x12, 1, analog_tlv), /* Common capture gain controls */ SOC_DOUBLE_R_TLV("Capture Volume", From 4290239cd05b6323da87b5e7e7db4c673bff5359 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 1 Dec 2008 10:03:47 +0200 Subject: [PATCH 239/367] ASoC: TWL4030: Add volume controls for outputs All outputs have dedicated gain controls except the HandsFree output. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1dae73af5273..ffd5120697a2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -366,6 +366,12 @@ static DECLARE_TLV_DB_SCALE(digital_coarse_tlv, 0, 600, 0); */ static DECLARE_TLV_DB_SCALE(analog_tlv, -2400, 200, 0); +/* + * Gain controls tied to outputs + * -6 dB to 6 dB in 6 dB steps (mute instead of -12) + */ +static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1); + /* * Capture gain after the ADCs * from 0 dB to 31 dB in 1 dB steps @@ -395,6 +401,21 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, 3, 0x12, 1, analog_tlv), + /* Separate output gain controls */ + SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", + TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL, + 4, 3, 0, output_tvl), + + SOC_DOUBLE_TLV_TWL4030("Headset Playback Volume", + TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, output_tvl), + + SOC_DOUBLE_R_TLV_TWL4030("Carkit Playback Volume", + TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL, + 4, 3, 0, output_tvl), + + SOC_SINGLE_TLV_TWL4030("Earpiece Playback Volume", + TWL4030_REG_EAR_CTL, 4, 3, 0, output_tvl), + /* Common capture gain controls */ SOC_DOUBLE_R_TLV("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, From 0ecfe7987855d21c2a89ffe003ddf0ee11b42d47 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Dec 2008 17:59:25 +0000 Subject: [PATCH 240/367] ASoC: Don't free static data in WM9713 Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 49962a88770d..f3ca8aaf0139 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1283,7 +1283,6 @@ static int wm9713_soc_remove(struct platform_device *pdev) snd_soc_free_ac97_codec(codec); kfree(codec->private_data); kfree(codec->reg_cache); - kfree(codec->dai); kfree(codec); return 0; } From 16950e09cf07b54abb78dd09f8ef3c85c6bdc9de Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Dec 2008 09:31:16 +0100 Subject: [PATCH 241/367] ALSA: emu10k1 - Add capture boost mixer switch for Audigy Due to the conversion (drop) from 24bit in the DSP to 16bit in AC97, the maximum capture level on Audigy seems lower than it could be. This patch adds a workaround to enable the artificial capture boost switch. When this switch is on, the whole analog capature level is boost up. However, this results in the lower capture resolution. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index f34bbfb705f5..b0fb6c917c38 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1639,6 +1639,45 @@ static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata = .put = snd_emu10k1_shared_spdif_put }; +/* workaround for too low volume on Audigy due to 16bit/24bit conversion */ + +#define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info + +static int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + + /* FIXME: better to use a cached version */ + val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); + ucontrol->value.integer.value[0] = !!val; + return 0; +} + +static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val; + + if (ucontrol->value.integer.value[0]) + val = 0x0f0f; + else + val = 0; + return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); +} + +static struct snd_kcontrol_new snd_audigy_capture_boost __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Capture Boost", + .info = snd_audigy_capture_boost_info, + .get = snd_audigy_capture_boost_get, + .put = snd_audigy_capture_boost_put +}; + + /* */ static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) @@ -2087,5 +2126,12 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, } } + if (emu->card_capabilities->ac97_chip && emu->audigy) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, + emu)); + if (err < 0) + return err; + } + return 0; } From 6308419a199eed66086cd756ab8dc81b88d54a6b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Dec 2008 15:08:03 +0000 Subject: [PATCH 242/367] ASoC: Push workqueue data into snd_soc_card ASoC v2 does not use the struct snd_soc_device at runtime, using struct snd_soc_card as the root of the card. Begin removing data from snd_soc_device by pushing the workqueue data into snd_soc_card, using a backpointer to the snd_soc_device to keep things going for the time being. Signed-off-by: Mark Brown --- include/sound/soc.h | 7 +++++-- sound/soc/soc-core.c | 33 ++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 9356c1ce98c1..359ec49f8d0d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -349,6 +349,11 @@ struct snd_soc_card { /* CPU <--> Codec DAI links */ struct snd_soc_dai_link *dai_link; int num_links; + + struct snd_soc_device *socdev; + + struct delayed_work delayed_work; + struct work_struct deferred_resume_work; }; /* SoC Device - the audio subsystem */ @@ -358,8 +363,6 @@ struct snd_soc_device { struct snd_soc_platform *platform; struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; - struct delayed_work delayed_work; - struct work_struct deferred_resume_work; void *codec_data; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7eb2ea1fd42e..c4b22e6984e6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -247,8 +247,9 @@ out: */ static void close_delayed_work(struct work_struct *work) { - struct snd_soc_device *socdev = - container_of(work, struct snd_soc_device, delayed_work.work); + struct snd_soc_card *card = container_of(work, struct snd_soc_card, + delayed_work.work); + struct snd_soc_device *socdev = card->socdev; struct snd_soc_codec *codec = socdev->codec; struct snd_soc_dai *codec_dai; int i; @@ -299,6 +300,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; @@ -340,7 +342,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; - schedule_delayed_work(&socdev->delayed_work, + schedule_delayed_work(&card->delayed_work, msecs_to_jiffies(pmdown_time)); } else { /* capture streams can be powered down now */ @@ -366,6 +368,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; @@ -411,7 +414,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && codec_dai->pop_wait) { codec_dai->pop_wait = 0; - cancel_delayed_work(&socdev->delayed_work); + cancel_delayed_work(&card->delayed_work); } /* do we need to power up codec */ @@ -645,7 +648,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) } /* close any waiting streams and save state */ - run_delayed_work(&socdev->delayed_work); + run_delayed_work(&card->delayed_work); codec->suspend_bias_level = codec->bias_level; for (i = 0; i < codec->num_dai; i++) { @@ -679,10 +682,10 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) */ static void soc_resume_deferred(struct work_struct *work) { - struct snd_soc_device *socdev = container_of(work, - struct snd_soc_device, - deferred_resume_work); - struct snd_soc_card *card = socdev->card; + struct snd_soc_card *card = container_of(work, + struct snd_soc_card, + deferred_resume_work); + struct snd_soc_device *socdev = card->socdev; struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; @@ -746,10 +749,11 @@ static void soc_resume_deferred(struct work_struct *work) static int soc_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_card *card = socdev->card; dev_dbg(socdev->dev, "scheduling resume work\n"); - if (!schedule_work(&socdev->deferred_resume_work)) + if (!schedule_work(&card->deferred_resume_work)) dev_err(socdev->dev, "resume work item may be lost\n"); return 0; @@ -769,6 +773,9 @@ static int soc_probe(struct platform_device *pdev) struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + /* Bodge while we push things out of socdev */ + card->socdev = socdev; + if (card->probe) { ret = card->probe(pdev); if (ret < 0) @@ -797,10 +804,10 @@ static int soc_probe(struct platform_device *pdev) } /* DAPM stream work */ - INIT_DELAYED_WORK(&socdev->delayed_work, close_delayed_work); + INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work); #ifdef CONFIG_PM /* deferred resume work */ - INIT_WORK(&socdev->deferred_resume_work, soc_resume_deferred); + INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); #endif return 0; @@ -831,7 +838,7 @@ static int soc_remove(struct platform_device *pdev) struct snd_soc_platform *platform = socdev->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - run_delayed_work(&socdev->delayed_work); + run_delayed_work(&card->delayed_work); if (platform->remove) platform->remove(pdev); From 96841bae6ebfede07294447ad2de9e6385ae9fb5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Dec 2008 15:15:50 +0000 Subject: [PATCH 243/367] ALSA: ac97 - Include ac97_codec.h for ac97_bus_type declaration This fixes a sparse warning caused by the lack of a connection with the prototype for ac97_bus_type. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/ac97_bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c index 7fa37e15f196..a351dd0a09c7 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c @@ -15,6 +15,7 @@ #include #include #include +#include /* * Let drivers decide whether they want to support given codec from their From 87689d567a45f80416feea0a2aa6d3a2a6b8963a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Dec 2008 16:01:14 +0000 Subject: [PATCH 244/367] ASoC: Push platform registration down into the card As part of the deprecation of snd_soc_device push the registration of the platform down into the card structure. Signed-off-by: Mark Brown --- include/sound/soc.h | 2 +- sound/soc/atmel/playpaq_wm8510.c | 2 +- sound/soc/atmel/sam9g20_wm8731.c | 2 +- sound/soc/blackfin/bf5xx-ad1980.c | 2 +- sound/soc/blackfin/bf5xx-ad73311.c | 2 +- sound/soc/blackfin/bf5xx-ssm2602.c | 2 +- sound/soc/davinci/davinci-evm.c | 2 +- sound/soc/davinci/davinci-i2s.c | 2 +- sound/soc/davinci/davinci-sffsdr.c | 2 +- sound/soc/fsl/mpc8610_hpcd.c | 2 +- sound/soc/fsl/soc-of-simple.c | 2 +- sound/soc/omap/n810.c | 2 +- sound/soc/omap/omap2evm.c | 2 +- sound/soc/omap/omap3beagle.c | 2 +- sound/soc/omap/osk5912.c | 2 +- sound/soc/omap/overo.c | 2 +- sound/soc/omap/sdp3430.c | 2 +- sound/soc/pxa/corgi.c | 2 +- sound/soc/pxa/e800_wm9712.c | 2 +- sound/soc/pxa/em-x270.c | 2 +- sound/soc/pxa/palm27x.c | 2 +- sound/soc/pxa/poodle.c | 2 +- sound/soc/pxa/spitz.c | 2 +- sound/soc/pxa/tosa.c | 2 +- sound/soc/pxa/zylonite.c | 2 +- sound/soc/s3c24xx/ln2440sbc_alc650.c | 2 +- sound/soc/s3c24xx/neo1973_wm8753.c | 2 +- sound/soc/s3c24xx/s3c24xx_uda134x.c | 2 +- sound/soc/s3c24xx/smdk2443_wm9710.c | 2 +- sound/soc/sh/sh7760-ac97.c | 2 +- sound/soc/soc-core.c | 44 ++++++++++++++++------------ 31 files changed, 55 insertions(+), 49 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 359ec49f8d0d..ad8141acd6b0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -352,6 +352,7 @@ struct snd_soc_card { struct snd_soc_device *socdev; + struct snd_soc_platform *platform; struct delayed_work delayed_work; struct work_struct deferred_resume_work; }; @@ -360,7 +361,6 @@ struct snd_soc_card { struct snd_soc_device { struct device *dev; struct snd_soc_card *card; - struct snd_soc_platform *platform; struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; void *codec_data; diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index d40b5a52a8d2..43dd8cee83c6 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c @@ -363,6 +363,7 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = { static struct snd_soc_card snd_soc_playpaq = { .name = "LRS_PlayPaq_WM8510", + .platform = &at32_soc_platform, .dai_link = &playpaq_wm8510_dai, .num_links = 1, }; @@ -378,7 +379,6 @@ static struct wm8510_setup_data playpaq_wm8510_setup = { static struct snd_soc_device playpaq_wm8510_snd_devdata = { .card = &snd_soc_playpaq, - .platform = &at32_soc_platform, .codec_dev = &soc_codec_dev_wm8510, .codec_data = &playpaq_wm8510_setup, }; diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index fdc1d0206e0b..1fb59a9d3719 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c @@ -244,6 +244,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = { static struct snd_soc_card snd_soc_at91sam9g20ek = { .name = "WM8731", + .platform = &atmel_soc_platform, .dai_link = &at91sam9g20ek_dai, .num_links = 1, }; @@ -255,7 +256,6 @@ static struct wm8731_setup_data at91sam9g20ek_wm8731_setup = { static struct snd_soc_device at91sam9g20ek_snd_devdata = { .card = &snd_soc_at91sam9g20ek, - .platform = &atmel_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &at91sam9g20ek_wm8731_setup, }; diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index 36c569a43ce1..d8f591273778 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c @@ -69,13 +69,13 @@ static struct snd_soc_dai_link bf5xx_board_dai = { static struct snd_soc_card bf5xx_board = { .name = "bf5xx-board", + .platform = &bf5xx_ac97_soc_platform, .dai_link = &bf5xx_board_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_board_snd_devdata = { .card = &bf5xx_board, - .platform = &bf5xx_ac97_soc_platform, .codec_dev = &soc_codec_dev_ad1980, }; diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c index 57da14799375..7f2a5e199075 100644 --- a/sound/soc/blackfin/bf5xx-ad73311.c +++ b/sound/soc/blackfin/bf5xx-ad73311.c @@ -192,6 +192,7 @@ static struct snd_soc_dai_link bf5xx_ad73311_dai = { static struct snd_soc_card bf5xx_ad73311 = { .name = "bf5xx_ad73311", + .platform = &bf5xx_i2s_soc_platform, .probe = bf5xx_probe, .dai_link = &bf5xx_ad73311_dai, .num_links = 1, @@ -199,7 +200,6 @@ static struct snd_soc_card bf5xx_ad73311 = { static struct snd_soc_device bf5xx_ad73311_snd_devdata = { .card = &bf5xx_ad73311, - .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ad73311, }; diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c index 0078dfcd95b9..bc0cdded7116 100644 --- a/sound/soc/blackfin/bf5xx-ssm2602.c +++ b/sound/soc/blackfin/bf5xx-ssm2602.c @@ -137,13 +137,13 @@ static struct ssm2602_setup_data bf5xx_ssm2602_setup = { static struct snd_soc_card bf5xx_ssm2602 = { .name = "bf5xx_ssm2602", + .platform = &bf5xx_i2s_soc_platform, .dai_link = &bf5xx_ssm2602_dai, .num_links = 1, }; static struct snd_soc_device bf5xx_ssm2602_snd_devdata = { .card = &bf5xx_ssm2602, - .platform = &bf5xx_i2s_soc_platform, .codec_dev = &soc_codec_dev_ssm2602, .codec_data = &bf5xx_ssm2602_setup, }; diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 2ce34d44b15c..d87b91179cc8 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -130,6 +130,7 @@ static struct snd_soc_dai_link evm_dai = { /* davinci-evm audio machine driver */ static struct snd_soc_card snd_soc_card_evm = { .name = "DaVinci EVM", + .platform = &davinci_soc_platform, .dai_link = &evm_dai, .num_links = 1, }; @@ -143,7 +144,6 @@ static struct aic3x_setup_data evm_aic3x_setup = { /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { .card = &snd_soc_card_evm, - .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &evm_aic3x_setup, }; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index cf31b3bb96cf..8b99efbc64c6 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -112,7 +112,7 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = socdev->card->platform; u32 w; int ret; diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index e95fde1766b5..f67579d52765 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -76,6 +76,7 @@ static struct snd_soc_dai_link sffsdr_dai = { /* davinci-sffsdr audio machine driver */ static struct snd_soc_card snd_soc_sffsdr = { .name = "DaVinci SFFSDR", + .platform = &davinci_soc_platform, .dai_link = &sffsdr_dai, .num_links = 1, }; @@ -91,7 +92,6 @@ static struct pcm3008_setup_data sffsdr_pcm3008_setup = { /* sffsdr audio subsystem */ static struct snd_soc_device sffsdr_snd_devdata = { .card = &snd_soc_sffsdr, - .platform = &davinci_soc_platform, .codec_dev = &soc_codec_dev_pcm3008, .codec_data = &sffsdr_pcm3008_setup, }; diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 1cf4d6eeb538..bcec3f60bad9 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -467,7 +467,7 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, machine_data->sound_devdata.card = &mpc8610_hpcd_machine; machine_data->sound_devdata.codec_dev = &soc_codec_device_cs4270; - machine_data->sound_devdata.platform = &fsl_soc_platform; + machine_data->machine.platform = &fsl_soc_platform; sound_device->dev.platform_data = machine_data; diff --git a/sound/soc/fsl/soc-of-simple.c b/sound/soc/fsl/soc-of-simple.c index 53be6491320a..8bc5cd9e972f 100644 --- a/sound/soc/fsl/soc-of-simple.c +++ b/sound/soc/fsl/soc-of-simple.c @@ -158,7 +158,7 @@ int of_snd_soc_register_platform(struct snd_soc_platform *platform, of_soc->platform_node = node; of_soc->dai_link.cpu_dai = cpu_dai; - of_soc->device.platform = platform; + of_soc->card.platform = platform; of_soc->card.name = of_soc->dai_link.cpu_dai->name; /* Now try to register the SoC device */ diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 18e2062e3a11..25593fee9121 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -288,6 +288,7 @@ static struct snd_soc_dai_link n810_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_n810 = { .name = "N810", + .platform = &omap_soc_platform, .dai_link = &n810_dai, .num_links = 1, }; @@ -303,7 +304,6 @@ static struct aic3x_setup_data n810_aic33_setup = { /* Audio subsystem */ static struct snd_soc_device n810_snd_devdata = { .card = &snd_soc_n810, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &n810_aic33_setup, }; diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index 7b160f9d83f9..0c2322dcf02a 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -93,6 +93,7 @@ static struct snd_soc_dai_link omap2evm_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_omap2evm = { .name = "omap2evm", + .platform = &omap_soc_platform, .dai_link = &omap2evm_dai, .num_links = 1, }; @@ -100,7 +101,6 @@ static struct snd_soc_card snd_soc_omap2evm = { /* Audio subsystem */ static struct snd_soc_device omap2evm_snd_devdata = { .card = &snd_soc_omap2evm, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index 3ed25464627f..fd24a4acd2f5 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -90,6 +90,7 @@ static struct snd_soc_dai_link omap3beagle_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_omap3beagle = { .name = "omap3beagle", + .platform = &omap_soc_platform, .dai_link = &omap3beagle_dai, .num_links = 1, }; @@ -97,7 +98,6 @@ static struct snd_soc_card snd_soc_omap3beagle = { /* Audio subsystem */ static struct snd_soc_device omap3beagle_snd_devdata = { .card = &snd_soc_omap3beagle, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 7a8f14d0c772..845bf41335b9 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -145,6 +145,7 @@ static struct snd_soc_dai_link osk_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_card_osk = { .name = "OSK5912", + .platform = &omap_soc_platform, .dai_link = &osk_dai, .num_links = 1, }; @@ -152,7 +153,6 @@ static struct snd_soc_card snd_soc_card_osk = { /* Audio subsystem */ static struct snd_soc_device osk_snd_devdata = { .card = &snd_soc_card_osk, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_tlv320aic23, }; diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index eea0c372bb3f..a72dc4e159e5 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -90,6 +90,7 @@ static struct snd_soc_dai_link overo_dai = { /* Audio machine driver */ static struct snd_soc_card snd_soc_card_overo = { .name = "overo", + .platform = &omap_soc_platform, .dai_link = &overo_dai, .num_links = 1, }; @@ -97,7 +98,6 @@ static struct snd_soc_card snd_soc_card_overo = { /* Audio subsystem */ static struct snd_soc_device overo_snd_devdata = { .card = &snd_soc_card_overo, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index 85fd160bca17..ad97836818b1 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -93,6 +93,7 @@ static struct snd_soc_dai_link sdp3430_dai = { /* Audio machine driver */ static struct snd_soc_machine snd_soc_machine_sdp3430 = { .name = "SDP3430", + .platform = &omap_soc_platform, .dai_link = &sdp3430_dai, .num_links = 1, }; @@ -100,7 +101,6 @@ static struct snd_soc_machine snd_soc_machine_sdp3430 = { /* Audio subsystem */ static struct snd_soc_device sdp3430_snd_devdata = { .machine = &snd_soc_machine_sdp3430, - .platform = &omap_soc_platform, .codec_dev = &soc_codec_dev_twl4030, }; diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index e56bf4b6c2af..1ba25a559524 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -312,6 +312,7 @@ static struct snd_soc_dai_link corgi_dai = { /* corgi audio machine driver */ static struct snd_soc_card snd_soc_corgi = { .name = "Corgi", + .platform = &pxa2xx_soc_platform, .dai_link = &corgi_dai, .num_links = 1, }; @@ -325,7 +326,6 @@ static struct wm8731_setup_data corgi_wm8731_setup = { /* corgi audio subsystem */ static struct snd_soc_device corgi_snd_devdata = { .card = &snd_soc_corgi, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &corgi_wm8731_setup, }; diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 60c64861512a..2e3386dfa0f0 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -42,13 +42,13 @@ static struct snd_soc_dai_link e800_dai[] = { static struct snd_soc_card e800 = { .name = "Toshiba e800", + .platform = &pxa2xx_soc_platform, .dai_link = e800_dai, .num_links = ARRAY_SIZE(e800_dai), }; static struct snd_soc_device e800_snd_devdata = { .card = &e800, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index d6884b755d55..fe4a729ea648 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -54,13 +54,13 @@ static struct snd_soc_dai_link em_x270_dai[] = { static struct snd_soc_card em_x270 = { .name = "EM-X270", + .platform = &pxa2xx_soc_platform, .dai_link = em_x270_dai, .num_links = ARRAY_SIZE(em_x270_dai), }; static struct snd_soc_device em_x270_snd_devdata = { .card = &em_x270, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 3bb8879ac8a2..4a9cf3083af0 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -191,13 +191,13 @@ static struct snd_soc_dai_link palm27x_dai[] = { static struct snd_soc_card palm27x_asoc = { .name = "Palm/PXA27x", + .platform = &pxa2xx_soc_platform, .dai_link = palm27x_dai, .num_links = ARRAY_SIZE(palm27x_dai), }; static struct snd_soc_device palm27x_snd_devdata = { .card = &palm27x_asoc, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 03b510ab2824..6e9827189fff 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -278,6 +278,7 @@ static struct snd_soc_dai_link poodle_dai = { /* poodle audio machine driver */ static struct snd_soc_card snd_soc_poodle = { .name = "Poodle", + .platform = &pxa2xx_soc_platform, .dai_link = &poodle_dai, .num_links = 1, }; @@ -291,7 +292,6 @@ static struct wm8731_setup_data poodle_wm8731_setup = { /* poodle audio subsystem */ static struct snd_soc_device poodle_snd_devdata = { .card = &snd_soc_poodle, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8731, .codec_data = &poodle_wm8731_setup, }; diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 579d93368f14..a3b9e6bdf979 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -321,6 +321,7 @@ static struct snd_soc_dai_link spitz_dai = { /* spitz audio machine driver */ static struct snd_soc_card snd_soc_spitz = { .name = "Spitz", + .platform = &pxa2xx_soc_platform, .dai_link = &spitz_dai, .num_links = 1, }; @@ -334,7 +335,6 @@ static struct wm8750_setup_data spitz_wm8750_setup = { /* spitz audio subsystem */ static struct snd_soc_device spitz_snd_devdata = { .card = &snd_soc_spitz, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm8750, .codec_data = &spitz_wm8750_setup, }; diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 48242b32a28b..c77194f74c9b 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -252,6 +252,7 @@ static int tosa_remove(struct platform_device *dev) static struct snd_soc_card tosa = { .name = "Tosa", + .platform = &pxa2xx_soc_platform, .dai_link = tosa_dai, .num_links = ARRAY_SIZE(tosa_dai), .probe = tosa_probe, @@ -260,7 +261,6 @@ static struct snd_soc_card tosa = { static struct snd_soc_device tosa_snd_devdata = { .card = &tosa, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9712, }; diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 842d6500d61f..f8e9ecd589d3 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -175,13 +175,13 @@ static struct snd_soc_dai_link zylonite_dai[] = { static struct snd_soc_card zylonite = { .name = "Zylonite", + .platform = &pxa2xx_soc_platform, .dai_link = zylonite_dai, .num_links = ARRAY_SIZE(zylonite_dai), }; static struct snd_soc_device zylonite_snd_ac97_devdata = { .card = &zylonite, - .platform = &pxa2xx_soc_platform, .codec_dev = &soc_codec_dev_wm9713, }; diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c index a70cbc0fa070..12c71482d258 100644 --- a/sound/soc/s3c24xx/ln2440sbc_alc650.c +++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c @@ -40,13 +40,13 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = { static struct snd_soc_card ln2440sbc = { .name = "LN2440SBC", + .platform = &s3c24xx_soc_platform, .dai_link = ln2440sbc_dai, .num_links = ARRAY_SIZE(ln2440sbc_dai), }; static struct snd_soc_device ln2440sbc_snd_ac97_devdata = { .card = &ln2440sbc, - .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 3df2224a6723..45bb12e8ea44 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -580,6 +580,7 @@ static struct snd_soc_dai_link neo1973_dai[] = { static struct snd_soc_card neo1973 = { .name = "neo1973", + .platform = &s3c24xx_soc_platform, .dai_link = neo1973_dai, .num_links = ARRAY_SIZE(neo1973_dai), }; @@ -591,7 +592,6 @@ static struct wm8753_setup_data neo1973_wm8753_setup = { static struct snd_soc_device neo1973_snd_devdata = { .card = &neo1973, - .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_wm8753, .codec_data = &neo1973_wm8753_setup, }; diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c index 23325fca1f64..a0a4d1832a14 100644 --- a/sound/soc/s3c24xx/s3c24xx_uda134x.c +++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c @@ -234,6 +234,7 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = { static struct snd_soc_card snd_soc_s3c24xx_uda134x = { .name = "S3C24XX_UDA134X", + .platform = &s3c24xx_soc_platform, .dai_link = &s3c24xx_uda134x_dai_link, .num_links = 1, }; @@ -271,7 +272,6 @@ static struct uda134x_platform_data s3c24xx_uda134x = { static struct snd_soc_device s3c24xx_uda134x_snd_devdata = { .card = &snd_soc_s3c24xx_uda134x, - .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_uda134x, .codec_data = &s3c24xx_uda134x, }; diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c index 3d2e6a0417ec..a2a4f5323c17 100644 --- a/sound/soc/s3c24xx/smdk2443_wm9710.c +++ b/sound/soc/s3c24xx/smdk2443_wm9710.c @@ -36,13 +36,13 @@ static struct snd_soc_dai_link smdk2443_dai[] = { static struct snd_soc_card smdk2443 = { .name = "SMDK2443", + .platform = &s3c24xx_soc_platform, .dai_link = smdk2443_dai, .num_links = ARRAY_SIZE(smdk2443_dai), }; static struct snd_soc_device smdk2443_snd_ac97_devdata = { .card = &smdk2443, - .platform = &s3c24xx_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c index 8b44f9c8a9ff..ce7f95b59de3 100644 --- a/sound/soc/sh/sh7760-ac97.c +++ b/sound/soc/sh/sh7760-ac97.c @@ -40,13 +40,13 @@ static struct snd_soc_dai_link sh7760_ac97_dai = { static struct snd_soc_card sh7760_ac97_soc_machine = { .name = "SH7760 AC97", + .platform = &sh7760_soc_platform, .dai_link = &sh7760_ac97_dai, .num_links = 1, }; static struct snd_soc_device sh7760_ac97_snd_devdata = { .card = &sh7760_ac97_soc_machine, - .platform = &sh7760_soc_platform, .codec_dev = &soc_codec_dev_ac97, }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c4b22e6984e6..fe89260c9028 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -109,9 +109,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card = socdev->card; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret = 0; @@ -302,7 +303,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -370,7 +371,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_card *card = socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -464,7 +465,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_card *card = socdev->card; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret = 0; @@ -534,7 +536,8 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_card *card = socdev->card; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; struct snd_soc_codec *codec = socdev->codec; @@ -568,8 +571,9 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_card *card= socdev->card; struct snd_soc_dai_link *machine = rtd->dai; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; int ret; @@ -610,7 +614,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; int i; @@ -686,7 +690,7 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_card, deferred_resume_work); struct snd_soc_device *socdev = card->socdev; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; struct snd_soc_codec *codec = socdev->codec; struct platform_device *pdev = to_platform_device(socdev->dev); @@ -770,7 +774,7 @@ static int soc_probe(struct platform_device *pdev) int ret = 0, i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; /* Bodge while we push things out of socdev */ @@ -835,7 +839,7 @@ static int soc_remove(struct platform_device *pdev) int i; struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = socdev->platform; + struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; run_delayed_work(&card->delayed_work); @@ -875,6 +879,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, struct snd_soc_dai_link *dai_link, int num) { struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_card *card = socdev->card; + struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *codec_dai = dai_link->codec_dai; struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; struct snd_soc_pcm_runtime *rtd; @@ -910,13 +916,13 @@ static int soc_new_pcm(struct snd_soc_device *socdev, dai_link->pcm = pcm; pcm->private_data = rtd; - soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap; - soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer; - soc_pcm_ops.ioctl = socdev->platform->pcm_ops->ioctl; - soc_pcm_ops.copy = socdev->platform->pcm_ops->copy; - soc_pcm_ops.silence = socdev->platform->pcm_ops->silence; - soc_pcm_ops.ack = socdev->platform->pcm_ops->ack; - soc_pcm_ops.page = socdev->platform->pcm_ops->page; + soc_pcm_ops.mmap = platform->pcm_ops->mmap; + soc_pcm_ops.pointer = platform->pcm_ops->pointer; + soc_pcm_ops.ioctl = platform->pcm_ops->ioctl; + soc_pcm_ops.copy = platform->pcm_ops->copy; + soc_pcm_ops.silence = platform->pcm_ops->silence; + soc_pcm_ops.ack = platform->pcm_ops->ack; + soc_pcm_ops.page = platform->pcm_ops->page; if (playback) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); @@ -924,14 +930,14 @@ static int soc_new_pcm(struct snd_soc_device *socdev, if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); - ret = socdev->platform->pcm_new(codec->card, codec_dai, pcm); + ret = platform->pcm_new(codec->card, codec_dai, pcm); if (ret < 0) { printk(KERN_ERR "asoc: platform pcm constructor failed\n"); kfree(rtd); return ret; } - pcm->private_free = socdev->platform->pcm_free; + pcm->private_free = platform->pcm_free; printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, cpu_dai->name); return ret; From 5920b45303291057fef827f5bdafe04001c1bbae Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Tue, 2 Dec 2008 20:48:58 +0200 Subject: [PATCH 245/367] ASoC: TWL4030: Add input selection and gain controls The TWL4030 codec device has two ADCs. Both of them can have several inputs routed to them, but TRM says that only one source can be selected for every ADC, even though every source has a dedicated bit in the registers. This patch adds input source controls. It modifies default register values to have no inputs selected and ADCs disabled. When some input is selected, control handlers enable apropriate input amplifier and ADC. If a microphone is selected, bias power is automatically enabled. When some input is deselected, unused chip parts are disabled. Microphone and line input recording tested on OMAP3 pandora board. Signed-off-by: Grazvydas Ignotas Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 177 ++++++++++++++++++++++++++++++++++++- sound/soc/codecs/twl4030.h | 16 ++++ 2 files changed, 190 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ffd5120697a2..3c9fdf2c6c7b 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -46,9 +46,9 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0xc3, /* REG_OPTION (0x2) */ 0x00, /* REG_UNKNOWN (0x3) */ 0x00, /* REG_MICBIAS_CTL (0x4) */ - 0x24, /* REG_ANAMICL (0x5) */ - 0x04, /* REG_ANAMICR (0x6) */ - 0x0a, /* REG_AVADC_CTL (0x7) */ + 0x20, /* REG_ANAMICL (0x5) */ + 0x00, /* REG_ANAMICR (0x6) */ + 0x00, /* REG_AVADC_CTL (0x7) */ 0x00, /* REG_ADCMICSEL (0x8) */ 0x00, /* REG_DIGMIXING (0x9) */ 0x0c, /* REG_ATXL1PGA (0xA) */ @@ -347,6 +347,162 @@ static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, return err; } +static int twl4030_get_left_input(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); + int result = 0; + + /* one bit must be set a time */ + reg &= TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN + | TWL4030_MAINMIC_EN; + if (reg != 0) { + result++; + while ((reg & 1) == 0) { + result++; + reg >>= 1; + } + } + + ucontrol->value.integer.value[0] = result; + return 0; +} + +static int twl4030_put_left_input(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + int value = ucontrol->value.integer.value[0]; + u8 anamicl, micbias, avadc_ctl; + + anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); + anamicl &= ~(TWL4030_CKMIC_EN | TWL4030_AUXL_EN | TWL4030_HSMIC_EN + | TWL4030_MAINMIC_EN); + micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); + micbias &= ~(TWL4030_HSMICBIAS_EN | TWL4030_MICBIAS1_EN); + avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); + + switch (value) { + case 1: + anamicl |= TWL4030_MAINMIC_EN; + micbias |= TWL4030_MICBIAS1_EN; + break; + case 2: + anamicl |= TWL4030_HSMIC_EN; + micbias |= TWL4030_HSMICBIAS_EN; + break; + case 3: + anamicl |= TWL4030_AUXL_EN; + break; + case 4: + anamicl |= TWL4030_CKMIC_EN; + break; + default: + break; + } + + /* If some input is selected, enable amp and ADC */ + if (value != 0) { + anamicl |= TWL4030_MICAMPL_EN; + avadc_ctl |= TWL4030_ADCL_EN; + } else { + anamicl &= ~TWL4030_MICAMPL_EN; + avadc_ctl &= ~TWL4030_ADCL_EN; + } + + twl4030_write(codec, TWL4030_REG_ANAMICL, anamicl); + twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); + twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); + + return 1; +} + +static int twl4030_get_right_input(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); + int value = 0; + + reg &= TWL4030_SUBMIC_EN|TWL4030_AUXR_EN; + switch (reg) { + case TWL4030_SUBMIC_EN: + value = 1; + break; + case TWL4030_AUXR_EN: + value = 2; + break; + default: + break; + } + + ucontrol->value.integer.value[0] = value; + return 0; +} + +static int twl4030_put_right_input(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = kcontrol->private_data; + int value = ucontrol->value.integer.value[0]; + u8 anamicr, micbias, avadc_ctl; + + anamicr = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICR); + anamicr &= ~(TWL4030_SUBMIC_EN|TWL4030_AUXR_EN); + micbias = twl4030_read_reg_cache(codec, TWL4030_REG_MICBIAS_CTL); + micbias &= ~TWL4030_MICBIAS2_EN; + avadc_ctl = twl4030_read_reg_cache(codec, TWL4030_REG_AVADC_CTL); + + switch (value) { + case 1: + anamicr |= TWL4030_SUBMIC_EN; + micbias |= TWL4030_MICBIAS2_EN; + break; + case 2: + anamicr |= TWL4030_AUXR_EN; + break; + default: + break; + } + + if (value != 0) { + anamicr |= TWL4030_MICAMPR_EN; + avadc_ctl |= TWL4030_ADCR_EN; + } else { + anamicr &= ~TWL4030_MICAMPR_EN; + avadc_ctl &= ~TWL4030_ADCR_EN; + } + + twl4030_write(codec, TWL4030_REG_ANAMICR, anamicr); + twl4030_write(codec, TWL4030_REG_MICBIAS_CTL, micbias); + twl4030_write(codec, TWL4030_REG_AVADC_CTL, avadc_ctl); + + return 1; +} + +static const char *twl4030_left_in_sel[] = { + "None", + "Main Mic", + "Headset Mic", + "Line In", + "Carkit Mic", +}; + +static const char *twl4030_right_in_sel[] = { + "None", + "Sub Mic", + "Line In", +}; + +static const struct soc_enum twl4030_left_input_mux = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_left_in_sel), + twl4030_left_in_sel); + +static const struct soc_enum twl4030_right_input_mux = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl4030_right_in_sel), + twl4030_right_in_sel); + /* * FGAIN volume control: * from -62 to 0 dB in 1 dB steps (mute instead of -63 dB) @@ -378,6 +534,12 @@ static DECLARE_TLV_DB_SCALE(output_tvl, -1200, 600, 1); */ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); +/* + * Gain control for input amplifiers + * 0 dB to 30 dB in 6 dB steps + */ +static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); + static const struct snd_kcontrol_new twl4030_snd_controls[] = { /* Common playback gain controls */ SOC_DOUBLE_R_TLV("DAC1 Digital Fine Playback Volume", @@ -420,6 +582,15 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("Capture Volume", TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA, 0, 0x1f, 0, digital_capture_tlv), + + SOC_DOUBLE_TLV("Input Boost Volume", TWL4030_REG_ANAMIC_GAIN, + 0, 3, 5, 0, input_gain_tlv), + + /* Input source controls */ + SOC_ENUM_EXT("Left Input Source", twl4030_left_input_mux, + twl4030_get_left_input, twl4030_put_left_input), + SOC_ENUM_EXT("Right Input Source", twl4030_right_input_mux, + twl4030_get_right_input, twl4030_put_right_input), }; /* add non dapm controls */ diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index 09865d9f5203..a2065d417c2e 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -113,7 +113,16 @@ #define TWL4030_CODECPDZ 0x02 #define TWL4030_OPT_MODE 0x01 +/* TWL4030_REG_MICBIAS_CTL (0x04) Fields */ + +#define TWL4030_MICBIAS2_CTL 0x40 +#define TWL4030_MICBIAS1_CTL 0x20 +#define TWL4030_HSMICBIAS_EN 0x04 +#define TWL4030_MICBIAS2_EN 0x02 +#define TWL4030_MICBIAS1_EN 0x01 + /* ANAMICL (0x05) Fields */ + #define TWL4030_CNCL_OFFSET_START 0x80 #define TWL4030_OFFSET_CNCL_SEL 0x60 #define TWL4030_OFFSET_CNCL_SEL_ARX1 0x00 @@ -127,10 +136,17 @@ #define TWL4030_MAINMIC_EN 0x01 /* ANAMICR (0x06) Fields */ + #define TWL4030_MICAMPR_EN 0x10 #define TWL4030_AUXR_EN 0x04 #define TWL4030_SUBMIC_EN 0x01 +/* AVADC_CTL (0x07) Fields */ + +#define TWL4030_ADCL_EN 0x08 +#define TWL4030_AVADC_CLK_PRIORITY 0x04 +#define TWL4030_ADCR_EN 0x02 + /* AUDIO_IF (0x0E) Fields */ #define TWL4030_AIF_SLAVE_EN 0x80 From 4b4fffdd9d179677cb030e97869286b62df25adc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 11:21:08 +0000 Subject: [PATCH 246/367] ASoC: Fix WM8903 right mixer bypass path Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 393a4c198823..3c83b7973074 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -773,14 +773,14 @@ static const struct snd_kcontrol_new left_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), -SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 1, 1, 0), +SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_LEFT_MIX_0, 0, 1, 0), }; static const struct snd_kcontrol_new right_output_mixer[] = { SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 2, 1, 0), SOC_DAPM_SINGLE_W("Left Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), -SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 1, 1, 0), +SOC_DAPM_SINGLE_W("Right Bypass Switch", WM8903_ANALOGUE_RIGHT_MIX_0, 0, 1, 0), }; static const struct snd_kcontrol_new left_speaker_mixer[] = { @@ -788,7 +788,7 @@ SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 3, 1, 0), SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 2, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, 1, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_LEFT_0, - 1, 1, 0), + 0, 1, 0), }; static const struct snd_kcontrol_new right_speaker_mixer[] = { @@ -797,7 +797,7 @@ SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 2, 1, 0), SOC_DAPM_SINGLE("Left Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, 1, 1, 0), SOC_DAPM_SINGLE("Right Bypass Switch", WM8903_ANALOGUE_SPK_MIX_RIGHT_0, - 1, 1, 0), + 0, 1, 0), }; static const struct snd_soc_dapm_widget wm8903_dapm_widgets[] = { From 6f2a974bfc8d3be7a30674c71e2fef003b39a8d2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 3 Dec 2008 11:44:17 +0100 Subject: [PATCH 247/367] ASoC: tlv320aic3x: headset/button press support - Add aic3x_set_headset_detection() function to define the headset detection mode for tlv32aic3x chips - added aic3x_button_pressed() - Read from the real-time registers in aic3x_headset_detected() to query headset presence without an occured interrupt Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 31 +++++++++++++++++++++-- sound/soc/codecs/tlv320aic3x.h | 46 +++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 0f4067bdd4a3..341e1adc9167 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1018,14 +1018,41 @@ int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio) } EXPORT_SYMBOL_GPL(aic3x_get_gpio); +void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, + int headset_debounce, int button_debounce) +{ + u8 val; + + val = ((detect & AIC3X_HEADSET_DETECT_MASK) + << AIC3X_HEADSET_DETECT_SHIFT) | + ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK) + << AIC3X_HEADSET_DEBOUNCE_SHIFT) | + ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK) + << AIC3X_BUTTON_DEBOUNCE_SHIFT); + + if (detect & AIC3X_HEADSET_DETECT_MASK) + val |= AIC3X_HEADSET_DETECT_ENABLED; + + aic3x_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val); +} +EXPORT_SYMBOL_GPL(aic3x_set_headset_detection); + int aic3x_headset_detected(struct snd_soc_codec *codec) { u8 val; - aic3x_read(codec, AIC3X_RT_IRQ_FLAGS_REG, &val); - return (val >> 2) & 1; + aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); + return (val >> 4) & 1; } EXPORT_SYMBOL_GPL(aic3x_headset_detected); +int aic3x_button_pressed(struct snd_soc_codec *codec) +{ + u8 val; + aic3x_read(codec, AIC3X_HEADSET_DETECT_CTRL_B, &val); + return (val >> 5) & 1; +} +EXPORT_SYMBOL_GPL(aic3x_button_pressed); + #define AIC3X_RATES SNDRV_PCM_RATE_8000_96000 #define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 7e982acf3996..73e35b6ec929 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -39,7 +39,9 @@ #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 /* Audio codec digital filter control register */ #define AIC3X_CODEC_DFILT_CTRL 12 - +/* Headset/button press detection register */ +#define AIC3X_HEADSET_DETECT_CTRL_A 13 +#define AIC3X_HEADSET_DETECT_CTRL_B 14 /* ADC PGA Gain control registers */ #define LADC_VOL 15 #define RADC_VOL 16 @@ -233,7 +235,49 @@ enum { void aic3x_set_gpio(struct snd_soc_codec *codec, int gpio, int state); int aic3x_get_gpio(struct snd_soc_codec *codec, int gpio); + +/* headset detection / button API */ + +/* The AIC3x supports detection of stereo headsets (GND + left + right signal) + * and cellular headsets (GND + speaker output + microphone input). + * It is recommended to enable MIC bias for this function to work properly. + * For more information, please refer to the datasheet. */ +enum { + AIC3X_HEADSET_DETECT_OFF = 0, + AIC3X_HEADSET_DETECT_STEREO = 1, + AIC3X_HEADSET_DETECT_CELLULAR = 2, + AIC3X_HEADSET_DETECT_BOTH = 3 +}; + +enum { + AIC3X_HEADSET_DEBOUNCE_16MS = 0, + AIC3X_HEADSET_DEBOUNCE_32MS = 1, + AIC3X_HEADSET_DEBOUNCE_64MS = 2, + AIC3X_HEADSET_DEBOUNCE_128MS = 3, + AIC3X_HEADSET_DEBOUNCE_256MS = 4, + AIC3X_HEADSET_DEBOUNCE_512MS = 5 +}; + +enum { + AIC3X_BUTTON_DEBOUNCE_0MS = 0, + AIC3X_BUTTON_DEBOUNCE_8MS = 1, + AIC3X_BUTTON_DEBOUNCE_16MS = 2, + AIC3X_BUTTON_DEBOUNCE_32MS = 3 +}; + +#define AIC3X_HEADSET_DETECT_ENABLED 0x80 +#define AIC3X_HEADSET_DETECT_SHIFT 5 +#define AIC3X_HEADSET_DETECT_MASK 3 +#define AIC3X_HEADSET_DEBOUNCE_SHIFT 2 +#define AIC3X_HEADSET_DEBOUNCE_MASK 7 +#define AIC3X_BUTTON_DEBOUNCE_SHIFT 0 +#define AIC3X_BUTTON_DEBOUNCE_MASK 3 + +/* see the enums above for valid parameters to this function */ +void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect, + int headset_debounce, int button_debounce); int aic3x_headset_detected(struct snd_soc_codec *codec); +int aic3x_button_pressed(struct snd_soc_codec *codec); struct aic3x_setup_data { int i2c_bus; From 0f620830db0818ebe065b31c33892e8f0622e1b2 Mon Sep 17 00:00:00 2001 From: Peter Gruber Date: Wed, 3 Dec 2008 15:32:15 +0100 Subject: [PATCH 248/367] ALSA: Reduce stall detection timeout in riptide.c Reduce the command timeout to 0.5sec. Should be enough to allow a working command interface but removes a RCU stall and slow resume on some revisions where the AC97 revision detection stalls in resume. Signed-off-by: Peter Gruber Signed-off-by: Takashi Iwai --- sound/pci/riptide/riptide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index e9f0706ed3e4..d0ccfc68c522 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -172,7 +172,7 @@ MODULE_PARM_DESC(opl3_port, "OPL3 port # for Riptide driver."); #define MAX_WRITE_RETRY 10 /* cmd interface limits */ #define MAX_ERROR_COUNT 10 -#define CMDIF_TIMEOUT 500000 +#define CMDIF_TIMEOUT 50000 #define RESET_TRIES 5 #define READ_PORT_ULONG(p) inl((unsigned long)&(p)) From a7fe49bf01dd64b3c73ad0e172f68bd03c813d65 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 3 Dec 2008 18:26:35 +0100 Subject: [PATCH 249/367] ALSA: Add more documentation about HD-audio driver The file can be converted to PDF via asciidoc. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 535 ++++++++++++++++++++++++++ 1 file changed, 535 insertions(+) create mode 100644 Documentation/sound/alsa/HD-Audio.txt diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt new file mode 100644 index 000000000000..e758f24017bf --- /dev/null +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -0,0 +1,535 @@ +MORE NOTES ON HD-AUDIO DRIVER +============================= + Takashi Iwai + + +GENERAL +------- + +HD-audio is the new standard on-board audio component on modern PCs +after AC97. Although Linux has been supporting HD-audio since long +time ago, there are often problems with new machines. A part of the +problem is broken BIOS, and rest is the driver implementation. This +document explains the trouble-shooting and debugging methods for the +HD-audio hardware. + +The HD-audio component consists of two parts: the controller chip and +the codec chips on the HD-audio bus. Linux provides a single driver +for all controllers, snd-hda-intel. Since the HD-audio controllers +are supposed to be compatible, the single snd-hda-driver should work +in most cases. But, not surprisingly, there are known bugs and issues +specific to each controller type. The snd-hda-intel driver has a +bunch of workarounds for these as described below. + +A controller may have multiple codecs. Usually you have one audio +codec and optionally one modem codec. In some cases, there can be +multiple audio codecs, e.g. for analog and digital outputs, but the +driver might not work properly. + +The snd-hda-intel driver has several different codec parsers depending +on the codec. It has a generic parser as a fallback, but this +functionality is fairly limited until now. Instead of the generic +parser, usually the codec-specific parser (coded in patch_*.c) is used +for the codec-specific implementations. The details about the +codec-specific problems are explained in the later sections. + +If you are interested in the deep debugging of HD-audio, read the +HD-audio specification at first. The specification is found on +Intel's web page, for example: + +- http://www.intel.com/standards/hdaudio/ + + +HD-AUDIO CONTROLLER +------------------- + +DMA-Position Problem +~~~~~~~~~~~~~~~~~~~~ +The most common problem of the controller is the inaccurate DMA +pointer reporting. The DMA pointer for playback and capture can be +read in two ways, either via a LPIB register or via a position-buffer +map. As default the driver tries to reads from the io-mapped +position-buffer, and falls back to LPIB if it appears unupdated. +However, this detection isn't perfect on some devices. In such a +case, you can change the default method via `position_fix` option. + +`position_fix=1` means to use LPIB method explicitly. +`position_fix=2` means to use the position-buffer. 0 is the default +value, the automatic check. If you get a problem of repeated sounds, +this option might help. + +In addition to that, every controller is known to be broken regarding +the wake-up timing. It wakes up a few samples before actually +processing the data on the buffer. This caused a lot of problems, for +example, with ALSA dmix or JACK. Since 2.6.27 kernel, the driver puts +an artificial delay to the wake up timing. This delay is controlled +via `bdl_pos_adj` option. + +When `bdl_pos_adj` is a negative value (as default), it's assigned to +an appropriate value depending on the controller chip. For Intel +chip, it'd be 1 while it'd be 32 for others. Usually this works. +Only in case it doesn't work and you get warning messages, you should +change to other values. + + +Codec-Probing Problem +~~~~~~~~~~~~~~~~~~~~~ +A less often but a more severe problem is the codec probing. When +BIOS reports the available codec slots wrongly, the driver gets +confused and tries to access the non-existing codec slot. This often +results in the total screw-up, and destruct the further communication +with the codec chips. The symptom appears usually as the error +message like: +------------------------------------------------------------------------ + hda_intel: azx_get_response timeout, switching to polling mode: \ + last cmd=0x12345678 + hda_intel: azx_get_response timeout, switching to single_cmd mode: \ + last cmd=0x12345678 +------------------------------------------------------------------------ + +The first line is a warning, and this is usually relatively harmless. +It means that the codec response isn't notified via an IRQ. The +driver uses explicit polling method to read the response. It gives +very slight CPU overhead, but you'd unlikely notice it. + +The second line is, however, a fatal error. If this happens, usually +it means that something is really wrong. Most likely you are +accessing a non-existing codec slot. + +Thus, if the second error message appears, try to narrow the probed +codec slots via `probe_mask` option. It's a bitmask, and each bit +corresponding to the codec slot. For example, to probe only the +first slot, pass `probe_mask=1`. For the first and the third slots, +pass `probe_mask=5` (where 5 = 1 | 4), and so on. + +Since 2.6.29 kernel, the driver has a more robust probing method, so +this error might happen rarely, though. + + +Interrupt Handling +~~~~~~~~~~~~~~~~~~ +In rare but some cases, the interrupt isn't properly handled as +default. You would notice this by the DMA transfer error reported by +ALSA PCM core, for example. Using MSI might help in such a case. +Pass `enable_msi=1` option for enabling MSI. + + +HD-AUDIO CODEC +-------------- + +Model Option +~~~~~~~~~~~~ +The most common problems with the HD-audio driver is the unsupported +codec features or the mismatched device configuration. Most of +codec-specific code has several preset models, either to override the +BIOS setup or to provide more comprehensive features. + +The driver checks PCI SSID and looks through the static configuration +table until any matching entry is found. If you have a new machine, +you may see a message like below: +------------------------------------------------------------------------ + hda_codec: Unknown model for ALC880, trying auto-probe from BIOS... +------------------------------------------------------------------------ +Even if you such a message, DON'T PANIC. Take a deep breath (and keep +your towel). First of all, it's an informational message, no warning, +no error. This means that the PCI SSID of your device isn't listed in +the known preset model list. But, this doesn't mean that the driver +is broken. Many codec-driver provides the automatic configuration +based on the BIOS setup. + +The HD-audio codec has usually "pin" widgets, and BIOS sets the default +configuration of each pin, which indicates the location, the +connection type, the jack color, etc. The HD-audio driver can guess +the right connection judging from these default configuration values. +However -- some codec support codes, such as patch_analog.c, don't +support the automatic probing (yet as of 2.6.28). And, BIOS is often, +yes, pretty often broken. It sets up wrong values and screws up the +driver. + +The preset model is provided basically to override such a situation. +When the matching preset model is found in the list, the driver +assumes the static configuration of that preset and builds the mixer +and PCM based on the static information. Thus, if you have a newer +machine with a slightly different PCI SSID from the existing one, you +may have a good chance to re-use the same model. You can pass the +`model` option to specify the preset model instead of PCI SSID +look-up. + +What `model` option values are available depends on the codec chip. +Check your codec chip from the codec proc file (see "Codec Proc-File" +section below). It will show the vendor/product name of your codec +chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt file. +In the section of HD-audio driver, you can find a list of codecs and +`model` options belonging to each codec. For example, for Realtek +ALC262 codec chip, pass `model=ultra` for devices that are compatible +with Samsung Q1 Ultra. + +Thus, the first thing you can do for any brand-new, unsupported +HD-audio hardware is to check HD-audio codec and several different +`model` option values. If you have a luck, some of them might suit +with your device well. + +Some codecs such as ALC880 have a special model option `model=test`. +This configures the driver to provide as many mixer controls as +possible for every single pin feature except for the unsolicited +events (and maybe some other specials). Adjust each mixer element and +try the I/O in the way of trial-and-error until figuring out the whole +I/O pin mappings. + +Note that `model=generic` has a special meaning. It means to use the +generic parser regardless of the codec. Usually the codec-specific +parser is much better than the generic parser (as now). Thus this +option is more about the debugging purpose. + + +Speaker and Headphone Output +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +One of the most frequent (and obvious) bugs with HD-audio is the +silent output from either or both of a built-in speaker and a +headphone jack. In general, you should try a headphone output at +first. A speaker output often requires more additional controls like +the amplifier. Thus a headphone output has a slightly better chance. + +Before making a bug report, double-check whether the mixer is set up +correctly. The recent version of snd-hda-intel driver provides mostly +"Master" volume control as well as "Front" volume. In addition, there +are individual "Headphone" and "Speaker" controls. + +Ditto for the speaker output. There can be "External Amplifier" +switch on some codecs. Turn on this if present. + +Another related problem is the automatic mute of speaker output by +headphone plugging. This feature is implemented in most cases, but +not on every preset model or codec-support code. + +In anyway, try a different model option if you have such a problem. +Some other models may match better and give you more matching +functionality. If none of the available models works, send a bug +report. See the bug report section for details. + +If you are masochistic enough to debug the driver problem, note the +following: + +- The speaker (and the headphone, too) output often requires the + external amplifier. This can be set usually via EAPD verb or a + certain GPIO. If the codec pin supports EAPD, you have a better + chance via SET_EAPD_BTL verb (0x70c). On others, GPIO pin (mostly + it's either GPIO0 or GPIO1) can turn on/off EAPD. +- Some Realtek codecs require special vendor-specific coefficients to + turn on the amplifier. See patch_realtek.c. +- IDT codecs may have extra power-enable/disable controls on each + analog pin. See patch_sigmatel.c. +- Very rare but some devices don't accept the pin-detection verb until + triggered. Issuing GET_PIN_SENSE verb (0xf09) may result in the + codec-communication stall. Some examples are found in + patch_realtek.c. + + +Capture Problems +~~~~~~~~~~~~~~~~ +The capture problems are often missing setups of mixers. Thus, before +submitting a bug report, make sure that you set up the mixer +correctly. For example, both "Capture Volume" and "Capture Switch" +have to be set properly in addition to the right "Capture Source" or +"Input Source" selection. Some devices have "Mic Boost" volume or +switch. + +When the PCM device is opened via "default" PCM (without pulse-audio +plugin), you'll likely have "Digital Capture Volume" control as well. +This is provided for the extra gain/attenuation of the signal in +software, especially for the inputs without the hardware volume +control such as digital microphones. Unless really needed, this +should be set to exactly 50%, corresponding to 0dB. When you use "hw" +PCM, i.e., a raw access PCM, this control will have no influence, +though. + +It's known that some codecs / devices have fairly bad analog circuits, +and the recorded sound contains a certain DC-offset. This is no bug +of the driver. + +Most of modern laptops have no analog CD-input connection. Thus, the +recording from CD input won't work in many cases although the driver +provides it as the capture source. + +The automatic switching of the built-in and external mic per plugging +is implemented on some codec models but not on every model. Partly +because of my laziness but mostly lack of testers. Feel free to +submit the improvement patch to the author. + + +Direct Debugging +~~~~~~~~~~~~~~~~ +If no model option gives you a better result, and you are a touch guy +to fight again the evil, try debugging via hitting the raw HD-audio +codec verbs to the device. Some tools are available: hda-emu and +hda-analyzer. The detailed description is found in the sections +below. You'd need to enable hwdep for using these tools. See "Kernel +Configuration". + + +OTHER ISSUES +------------ + +Kernel Configuration +~~~~~~~~~~~~~~~~~~~~ +In general, I recommend you to enable the sound debug option, +`CONFIG_SND_DEBUG=y`, no matter whether you are debugging or not. +This enables snd_printd() macro and others, and you'll get additional +kernel messages at probing. + +In addition, you can enable `CONFIG_SND_DEBUG_VERBOSE=y`. But this +will give you far more messages. Thus turn this on only when you are +sure to want it. + +Don't forget to turn on the appropriate `CONFIG_SND_HDA_CODEC_*` +options. Note that each of them corresponds to the codec chip, not +the controller chip. Thus, even if lspci shows the Nvidia controller, +you may choose the option for other vendors. If you are unsure, just +choose all yes. + +`CONFIG_SND_HDA_HWDEP` is a useful option for debugging the driver. +When this is enabled, the driver creates hardware-dependent devices +(one per each codec), and you have a raw access to the device via +hda-verb program. For example, `hwC0D2` will be created for the card +0 codec slot #2. For debug tools such as hda-verb and hda-analyzer, +the hwdep device has to be enabled. Thus, turn this on always. + +`CONFIG_SND_HDA_RECONFIG` is a new option, and this depends on the +hwdep option above. When enabled, you'll have some sysfs files under +the corresponding hwdep directory. See "HD-audio reconfiguration" +section below. + +`CONFIG_SND_HDA_POWER_SAVE` option enables the power-saving feature. +See "Power-saving" section below. + + +Codec Proc-File +~~~~~~~~~~~~~~~ +The codec proc-file is a treasure-chest for debugging HD-audio. +It shows most of useful information of each codec widget. + +The proc file is located in /proc/asound/card*/codec#*, one file per +each codec slot. You can know the codec vendor, product id and +names, the type of each widget, capabilities and so on. +This file, however, doesn't show the jack sensing state, so far. This +is because the jack-sensing might be depending on the trigger state. + +This file will be picked up by the debug tools, and also it can be fed +to the emulator as the primary codec information. See the debug tools +section below. + +This proc file can be also used to check whether the generic parser is +used. When the generic parser is used, the vendor/product ID name +will appear as "Realtek ID 0262", instead of "Realtek ALC262". + + +HD-Audio Reconfiguration +~~~~~~~~~~~~~~~~~~~~~~~~ +This is an experimental feature to allow you re-configure the HD-audio +codec dynamically without reloading the driver. The following sysfs +files are available under each codec-hwdep device directory (e.g. +/sys/class/sound/hwC0D0): + +vendor_id:: + Shows the 32bit codec vendor-id hex number. You can change the + vendor-id value by writing to this file. +subsystem_id:: + Shows the 32bit codec subsystem-id hex number. You can change the + subsystem-id value by writing to this file. +revision_id:: + Shows the 32bit codec revision-id hex number. You can change the + revision-id value by writing to this file. +afg:: + Shows the AFG ID. This is read-only. +mfg:: + Shows the MFG ID. This is read-only. +name:: + Shows the codec name string. Can be changed by writing to this + file. +modelname:: + Shows the currently set `model` option. Can be changed by writing + to this file. +init_verbs:: + The extra verbs to execute at initialization. You can add a verb by + writing to this file. Pass tree numbers, nid, verb and parameter. +hints:: + Shows hint strings for codec parsers for any use. Right now it's + not used. +reconfig:: + Triggers the codec re-configuration. When any value is written to + this file, the driver re-initialize and parses the codec tree + again. All the changes done by the sysfs entries above are taken + into account. +clear:: + Resets the codec, removes the mixer elements and PCM stuff of the + specified codec, and clear all init verbs and hints. + + +Power-Saving +~~~~~~~~~~~~ +The power-saving is a kind of auto-suspend of the device. When the +device is inactive for a certain time, the device is automatically +turned off to save the power. The time to go down is specified via +`power_save` module option, and this option can be changed dynamically +via sysfs. + +The power-saving won't work when the analog loopback is enabled on +some codecs. Make sure that you mute all unneeded signal routes when +you want the power-saving. + +The power-saving feature might cause audible click noises at each +power-down/up depending on the device. Some of them might be +solvable, but some are hard, I'm afraid. Some distros such as +openSUSE enables the power-saving feature automatically when the power +cable is unplugged. Thus, if you hear noises, suspect first the +power-saving. See /sys/modules/snd_hda_intel/parameters/power_save to +check the current value. If it's non-zero, the feature is turned on. + + +Sending a Bug Report +~~~~~~~~~~~~~~~~~~~~ +If any model or module options don't work for your device, it's time +to send a bug report to the developers. Give the following in your +bug report: + +- Hardware vendor, product and model names +- Kernel version (and ALSA-driver version if you built externally) +- `alsa-info.sh` output; run with `--no-upload` option. See the + section below about alsa-info + +If it's a regression, at best, send alsa-info outputs of both working +and non-working kernels. This is really helpful because we can +compare the codec registers directly. + +Send a bug report either the followings: + +kernel-bugzilla:: + http://bugme.linux-foundation.org/ +alsa-devel ML:: + alsa-devel@alsa-project.org + + +DEBUG TOOLS +----------- + +This section describes some tools available for debugging HD-audio +problems. + +alsa-info +~~~~~~~~~ +The script `alsa-info.sh` is a very useful tool to gather the audio +device information. You can fetch the latest version from: + +- http://www.alsa-project.org/alsa-info.sh + +Run this script as root, and it will gather the important information +such as the module lists, module parameters, proc file contents +including the codec proc files, mixer outputs and the control +elements. As default, it will store the information onto a web server +on alsa-project.org. But, if you send a bug report, it'd be better to +run with `--no-upload` option, and attach the generated file. + +There are some other useful options. See `--help` option output for +details. + + +hda-verb +~~~~~~~~ +hda-verb is a tiny program that allows you to access the HD-audio +codec directly. It executes a HD-audio codec verb directly. +This program accesses the hwdep device, thus you need to enable the +kernel config `CONFIG_SND_HDA_HWDEP=y` beforehand. + +The hda-verb program takes four arguments: the hwdep device file, the +widget NID, the verb and the parameter. When you access to the codec +on the slot 2 of the card 0, pass /dev/snd/hwC0D2 to the first +argument, typically. (However, the real path name depends on the +system.) + +The second parameter is the widget number-id to access. The third +parameter can be either a hex/digit number or a string corresponding +to a verb. Similarly, the last parameter is the value to write, or +can be a string for the parameter type. + +------------------------------------------------------------------------ + % hda-verb /dev/snd/hwC0D0 0x12 0x701 2 + nid = 0x12, verb = 0x701, param = 0x2 + value = 0x0 + + % hda-verb /dev/snd/hwC0D0 0x0 PARAMETERS VENDOR_ID + nid = 0x0, verb = 0xf00, param = 0x0 + value = 0x10ec0262 + + % hda-verb /dev/snd/hwC0D0 2 set_a 0xb080 + nid = 0x2, verb = 0x300, param = 0xb080 + value = 0x0 +------------------------------------------------------------------------ + +Although you can issue any verbs with this program, the driver state +won't be always updated. For example, the volume values are usually +cached in the driver, and thus changing the widget amp value directly +via hda-verb won't change the mixer value. + +The hda-verb program is found in the ftp directory: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/ + +Also a git repository is available: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-verb.git + +See README file in the tarball for more details about hda-verb +program. + + +hda-analyzer +~~~~~~~~~~~~ +hda-analyzer provides a graphical interface to access the raw HD-audio +control, based on pyGTK2 binding. It's a more powerful version of +hda-verb. The program gives you a easy-to-use GUI stuff for showing +the widget information and adjusting the amp values, as well as the +proc-compatible output. + +The hda-analyzer is a part of alsa.git repository in +alsa-project.org: + +- http://git.alsa-project.org/?p=alsa.git;a=tree;f=hda-analyzer + + +hda-emu +~~~~~~~ +hda-emu is a HD-audio emulator. The main purpose of this program is +to debug an HD-audio codec without the real hardware. Thus, it +doesn't emulate the behavior with the real audio I/O, but it just +dumps the codec register changes and the ALSA-driver internal changes +at probing and operating the HD-audio driver. + +The program requires a codec proc-file to simulate. Get a proc file +for the target codec beforehand, or pick up an example codec from the +codec proc collections in the tarball. Then, run the program with the +proc file, and the hda-emu program will start parsing the codec file +and simulates the HD-audio driver: + +------------------------------------------------------------------------ + % hda-emu codecs/stac9200-dell-d820-laptop + # Parsing.. + hda_codec: Unknown model for STAC9200, using BIOS defaults + hda_codec: pin nid 08 bios pin config 40c003fa + .... +------------------------------------------------------------------------ + +The program gives you only a very dumb command-line interface. You +can get a proc-file dump at the current state, get a list of control +(mixer) elements, set/get the control element value, simulate the PCM +operation, the jack plugging simulation, etc. + +The package is found in: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/misc/ + +A git repository is available: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-emu.git + +See README file in the tarball for more details about hda-emu +program. From 384c89e2e4cb5879b86a38414d1b3bb2b23ec8ee Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 17:34:03 +0000 Subject: [PATCH 250/367] ASoC: Push debugfs files out of the snd_soc_device structure This is in preparation for the removal of struct snd_soc_device. The pop time configuration should really be a property of the card not the codec but since DAPM currently uses the codec rather than the card using the codec is fine for now. Signed-off-by: Mark Brown --- include/sound/soc.h | 8 +++-- sound/soc/soc-core.c | 71 +++++++++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ad8141acd6b0..3ee608dce2f8 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -279,6 +279,11 @@ struct snd_soc_codec { /* codec DAI's */ struct snd_soc_dai *dai; unsigned int num_dai; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_reg; + struct dentry *debugfs_pop_time; +#endif }; /* codec device */ @@ -364,9 +369,6 @@ struct snd_soc_device { struct snd_soc_codec *codec; struct snd_soc_codec_device *codec_dev; void *codec_data; -#ifdef CONFIG_DEBUG_FS - struct dentry *debugfs_root; -#endif }; /* runtime channel data */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fe89260c9028..34114398b914 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -39,6 +39,10 @@ static DEFINE_MUTEX(pcm_mutex); static DEFINE_MUTEX(io_mutex); static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); +#ifdef CONFIG_DEBUG_FS +static struct dentry *debugfs_root; +#endif + /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -1002,7 +1006,9 @@ static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { ssize_t ret; - struct snd_soc_device *devdata = file->private_data; + struct snd_soc_codec *codec = file->private_data; + struct device *card_dev = codec->card->dev; + struct snd_soc_device *devdata = card_dev->driver_data; char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1021,8 +1027,7 @@ static ssize_t codec_reg_write_file(struct file *file, char *start = buf; unsigned long reg, value; int step = 1; - struct snd_soc_device *devdata = file->private_data; - struct snd_soc_codec *codec = devdata->codec; + struct snd_soc_codec *codec = file->private_data; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) @@ -1051,44 +1056,36 @@ static const struct file_operations codec_reg_fops = { .write = codec_reg_write_file, }; -static void soc_init_debugfs(struct snd_soc_device *socdev) +static void soc_init_codec_debugfs(struct snd_soc_codec *codec) { - struct dentry *root, *file; - struct snd_soc_codec *codec = socdev->codec; - root = debugfs_create_dir(dev_name(socdev->dev), NULL); - if (IS_ERR(root) || !root) - goto exit1; + codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, + debugfs_root, codec, + &codec_reg_fops); + if (!codec->debugfs_reg) + printk(KERN_WARNING + "ASoC: Failed to create codec register debugfs file\n"); - file = debugfs_create_file("codec_reg", 0644, - root, socdev, &codec_reg_fops); - if (!file) - goto exit2; - - file = debugfs_create_u32("dapm_pop_time", 0744, - root, &codec->pop_time); - if (!file) - goto exit2; - socdev->debugfs_root = root; - return; -exit2: - debugfs_remove_recursive(root); -exit1: - dev_err(socdev->dev, "debugfs is not available\n"); + codec->debugfs_pop_time = debugfs_create_u32("dapm_pop_time", 0744, + debugfs_root, + &codec->pop_time); + if (!codec->debugfs_pop_time) + printk(KERN_WARNING + "Failed to create pop time debugfs file\n"); } -static void soc_cleanup_debugfs(struct snd_soc_device *socdev) +static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) { - debugfs_remove_recursive(socdev->debugfs_root); - socdev->debugfs_root = NULL; + debugfs_remove(codec->debugfs_pop_time); + debugfs_remove(codec->debugfs_reg); } #else -static inline void soc_init_debugfs(struct snd_soc_device *socdev) +static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) { } -static inline void soc_cleanup_debugfs(struct snd_soc_device *socdev) +static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) { } #endif @@ -1305,7 +1302,7 @@ int snd_soc_init_card(struct snd_soc_device *socdev) if (err < 0) printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); - soc_init_debugfs(socdev); + soc_init_codec_debugfs(socdev->codec); mutex_unlock(&codec->mutex); out: @@ -1329,7 +1326,7 @@ void snd_soc_free_pcms(struct snd_soc_device *socdev) #endif mutex_lock(&codec->mutex); - soc_cleanup_debugfs(socdev); + soc_cleanup_codec_debugfs(socdev->codec); #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; @@ -1962,11 +1959,23 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); static int __devinit snd_soc_init(void) { +#ifdef CONFIG_DEBUG_FS + debugfs_root = debugfs_create_dir("asoc", NULL); + if (IS_ERR(debugfs_root) || !debugfs_root) { + printk(KERN_WARNING + "ASoC: Failed to create debugfs directory\n"); + debugfs_root = NULL; + } +#endif + return platform_driver_register(&soc_driver); } static void __exit snd_soc_exit(void) { +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(debugfs_root); +#endif platform_driver_unregister(&soc_driver); } From 07c84d0409f3551b79d676630d8ee76bb551598d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 18:17:28 +0000 Subject: [PATCH 251/367] ASoC: Remove device from platform suspend and resume operations None of the platforms are actually using the SoC device so remove it (only atmel actually has a suspend method). Signed-off-by: Mark Brown --- include/sound/soc.h | 6 ++---- sound/soc/atmel/atmel-pcm.c | 6 ++---- sound/soc/soc-core.c | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3ee608dce2f8..8ec63c02dc10 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -300,10 +300,8 @@ struct snd_soc_platform { int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); - int (*suspend)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*resume)(struct platform_device *pdev, - struct snd_soc_dai *dai); + int (*suspend)(struct snd_soc_dai *dai); + int (*resume)(struct snd_soc_dai *dai); /* pcm creation and destruction */ int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 394412fb396f..8507aa1cd811 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -417,8 +417,7 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) } #ifdef CONFIG_PM -static int atmel_pcm_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int atmel_pcm_suspend(struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = dai->runtime; struct atmel_runtime_data *prtd; @@ -442,8 +441,7 @@ static int atmel_pcm_suspend(struct platform_device *pdev, return 0; } -static int atmel_pcm_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int atmel_pcm_resume(struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = dai->runtime; struct atmel_runtime_data *prtd; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 34114398b914..f83852f11463 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -652,7 +652,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) if (cpu_dai->suspend && !cpu_dai->ac97_control) cpu_dai->suspend(pdev, cpu_dai); if (platform->suspend) - platform->suspend(pdev, cpu_dai); + platform->suspend(cpu_dai); } /* close any waiting streams and save state */ @@ -741,7 +741,7 @@ static void soc_resume_deferred(struct work_struct *work) if (cpu_dai->resume && !cpu_dai->ac97_control) cpu_dai->resume(pdev, cpu_dai); if (platform->resume) - platform->resume(pdev, cpu_dai); + platform->resume(cpu_dai); } if (card->resume_post) From dc7d7b830ee1f4111696e73d1c25da683b461548 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 18:21:52 +0000 Subject: [PATCH 252/367] ASoC: Remove platform device from DAI suspend and resume operations None of the DAIs use it except s3c2412-i2s which only uses it for dev_() printouts. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 6 ++---- sound/soc/atmel/atmel_ssc_dai.c | 6 ++---- sound/soc/au1x/psc-ac97.c | 6 ++---- sound/soc/au1x/psc-i2s.c | 6 ++---- sound/soc/blackfin/bf5xx-ac97.c | 6 ++---- sound/soc/blackfin/bf5xx-i2s.c | 6 ++---- sound/soc/pxa/pxa-ssp.c | 6 ++---- sound/soc/pxa/pxa2xx-ac97.c | 6 ++---- sound/soc/pxa/pxa2xx-i2s.c | 6 ++---- sound/soc/s3c24xx/s3c2412-i2s.c | 16 +++++++--------- sound/soc/s3c24xx/s3c24xx-i2s.c | 6 ++---- sound/soc/soc-core.c | 8 ++++---- 12 files changed, 31 insertions(+), 53 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index a01a24b10196..e2d5f76838c6 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -191,10 +191,8 @@ struct snd_soc_dai { struct snd_soc_dai *dai); void (*remove)(struct platform_device *pdev, struct snd_soc_dai *dai); - int (*suspend)(struct platform_device *pdev, - struct snd_soc_dai *dai); - int (*resume)(struct platform_device *pdev, - struct snd_soc_dai *dai); + int (*suspend)(struct snd_soc_dai *dai); + int (*resume)(struct snd_soc_dai *dai); /* ops */ struct snd_soc_dai_ops ops; diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 0bb18dfa9495..d9b874c5bf37 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -628,8 +628,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream, #ifdef CONFIG_PM -static int atmel_ssc_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai) { struct atmel_ssc_info *ssc_p; @@ -657,8 +656,7 @@ static int atmel_ssc_suspend(struct platform_device *pdev, -static int atmel_ssc_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai) { struct atmel_ssc_info *ssc_p; u32 cr; diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index a0bcfeaf5f86..a1e824d29cf9 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -314,8 +314,7 @@ static void au1xpsc_ac97_remove(struct platform_device *pdev, au1xpsc_ac97_workdata = NULL; } -static int au1xpsc_ac97_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int au1xpsc_ac97_suspend(struct snd_soc_dai *dai) { /* save interesting registers and disable PSC */ au1xpsc_ac97_workdata->pm[0] = @@ -329,8 +328,7 @@ static int au1xpsc_ac97_suspend(struct platform_device *pdev, return 0; } -static int au1xpsc_ac97_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int au1xpsc_ac97_resume(struct snd_soc_dai *dai) { /* restore PSC clock config */ au_writel(au1xpsc_ac97_workdata->pm[0] | PSC_SEL_PS_AC97MODE, diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index f4217e70a787..16f97462ea15 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -339,8 +339,7 @@ static void au1xpsc_i2s_remove(struct platform_device *pdev, au1xpsc_i2s_workdata = NULL; } -static int au1xpsc_i2s_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_suspend(struct snd_soc_dai *cpu_dai) { /* save interesting register and disable PSC */ au1xpsc_i2s_workdata->pm[0] = @@ -354,8 +353,7 @@ static int au1xpsc_i2s_suspend(struct platform_device *pdev, return 0; } -static int au1xpsc_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int au1xpsc_i2s_resume(struct snd_soc_dai *cpu_dai) { /* select I2S mode and PSC clock */ au_writel(PSC_CTRL_DISABLE, PSC_CTRL(au1xpsc_i2s_workdata)); diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 709bdf08e398..c602ce109d52 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -269,8 +269,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = { EXPORT_SYMBOL_GPL(soc_ac97_ops); #ifdef CONFIG_PM -static int bf5xx_ac97_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) { struct sport_device *sport = (struct sport_device *)dai->private_data; @@ -285,8 +284,7 @@ static int bf5xx_ac97_suspend(struct platform_device *pdev, return 0; } -static int bf5xx_ac97_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int bf5xx_ac97_resume(struct snd_soc_dai *dai) { int ret; struct sport_device *sport = diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 6e5036bf9245..9f8ce87cc6c6 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -222,16 +222,14 @@ static int bf5xx_i2s_probe(struct platform_device *pdev, return 0; } -static void bf5xx_i2s_remove(struct platform_device *pdev, - struct snd_soc_dai *dai) +static void bf5xx_i2s_remove(struct snd_soc_dai *dai) { pr_debug("%s enter\n", __func__); peripheral_free_list(&sport_req[sport_num][0]); } #ifdef CONFIG_PM -static int bf5xx_i2s_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) +static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) { struct sport_device *sport = (struct sport_device *)dai->private_data; diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 402fc5ba65e7..73fa10defcca 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -244,8 +244,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, #ifdef CONFIG_PM -static int pxa_ssp_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = cpu_dai->private_data; @@ -257,8 +256,7 @@ static int pxa_ssp_suspend(struct platform_device *pdev, return 0; } -static int pxa_ssp_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = cpu_dai->private_data; diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index bffbe288634c..8eed80d5675d 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -87,14 +87,12 @@ static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = { }; #ifdef CONFIG_PM -static int pxa2xx_ac97_suspend(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int pxa2xx_ac97_suspend(struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_suspend(); } -static int pxa2xx_ac97_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int pxa2xx_ac97_resume(struct snd_soc_dai *dai) { return pxa2xx_ac97_hw_resume(); } diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index f9a9e2ebafa1..314973ace6dc 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -293,8 +293,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, } #ifdef CONFIG_PM -static int pxa2xx_i2s_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) +static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai) { if (!dai->active) return 0; @@ -311,8 +310,7 @@ static int pxa2xx_i2s_suspend(struct platform_device *dev, return 0; } -static int pxa2xx_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int pxa2xx_i2s_resume(struct snd_soc_dai *dai) { if (!dai->active) return 0; diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 1c741047ae35..75f87c3c74d0 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -649,8 +649,7 @@ static int s3c2412_i2s_probe(struct platform_device *pdev, } #ifdef CONFIG_PM -static int s3c2412_i2s_suspend(struct platform_device *dev, - struct snd_soc_dai *dai) +static int s3c2412_i2s_suspend(struct snd_soc_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; u32 iismod; @@ -665,25 +664,24 @@ static int s3c2412_i2s_suspend(struct platform_device *dev, iismod = readl(i2s->regs + S3C2412_IISMOD); if (iismod & S3C2412_IISCON_RXDMA_ACTIVE) - dev_warn(&dev->dev, "%s: RXDMA active?\n", __func__); + pr_warning("%s: RXDMA active?\n", __func__); if (iismod & S3C2412_IISCON_TXDMA_ACTIVE) - dev_warn(&dev->dev, "%s: TXDMA active?\n", __func__); + pr_warning("%s: TXDMA active?\n", __func__); if (iismod & S3C2412_IISCON_IIS_ACTIVE) - dev_warn(&dev->dev, "%s: IIS active\n", __func__); + pr_warning("%s: IIS active\n", __func__); } return 0; } -static int s3c2412_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *dai) +static int s3c2412_i2s_resume(struct snd_soc_dai *dai) { struct s3c2412_i2s_info *i2s = &s3c2412_i2s; - dev_info(&pdev->dev, "dai_active %d, IISMOD %08x, IISCON %08x\n", - dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); + pr_info("dai_active %d, IISMOD %08x, IISCON %08x\n", + dai->active, i2s->suspend_iismod, i2s->suspend_iiscon); if (dai->active) { writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON); diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 8d9135f41bc9..45fe8f7c88ab 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -419,8 +419,7 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev, } #ifdef CONFIG_PM -static int s3c24xx_i2s_suspend(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) { DBG("Entered %s\n", __func__); @@ -434,8 +433,7 @@ static int s3c24xx_i2s_suspend(struct platform_device *pdev, return 0; } -static int s3c24xx_i2s_resume(struct platform_device *pdev, - struct snd_soc_dai *cpu_dai) +static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) { DBG("Entered %s\n", __func__); clk_enable(s3c24xx_i2s.iis_clk); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f83852f11463..2f2a8d93bbf0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -650,7 +650,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->suspend && !cpu_dai->ac97_control) - cpu_dai->suspend(pdev, cpu_dai); + cpu_dai->suspend(cpu_dai); if (platform->suspend) platform->suspend(cpu_dai); } @@ -676,7 +676,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->suspend && cpu_dai->ac97_control) - cpu_dai->suspend(pdev, cpu_dai); + cpu_dai->suspend(cpu_dai); } if (card->suspend_post) @@ -712,7 +712,7 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->resume && cpu_dai->ac97_control) - cpu_dai->resume(pdev, cpu_dai); + cpu_dai->resume(cpu_dai); } if (codec_dev->resume) @@ -739,7 +739,7 @@ static void soc_resume_deferred(struct work_struct *work) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; if (cpu_dai->resume && !cpu_dai->ac97_control) - cpu_dai->resume(pdev, cpu_dai); + cpu_dai->resume(cpu_dai); if (platform->resume) platform->resume(cpu_dai); } From e5f73435683122612742eb17252a6854b28f2511 Mon Sep 17 00:00:00 2001 From: Scott Waye Date: Thu, 4 Dec 2008 07:43:18 +0100 Subject: [PATCH 253/367] ALSA: hda - Add MCP67 HDMI support Added id for MCP67 HDMI codec. Signed-off-by: Scott Waye Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index e23de5594b6e..5e6cc41a559d 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -161,6 +161,7 @@ static int patch_nvhdmi(struct hda_codec *codec) static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0067, .name = "NVIDIA MCP67 HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; From 4151d154efc2eb1e48b0950e93660691426dd23f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Dec 2008 07:49:15 +0100 Subject: [PATCH 254/367] ALSA: hda - Add forgotten module alias for Nvidia MCP67 HDMI Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 5e6cc41a559d..0cd53063e62e 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -167,6 +167,7 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { MODULE_ALIAS("snd-hda-codec-id:10de0002"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); +MODULE_ALIAS("snd-hda-codec-id:10de0067"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); From 4e7c4d7b6d980264194c2aecbbb1e1e4c7302b63 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Dec 2008 10:25:37 +0100 Subject: [PATCH 255/367] ALSA: hda - Add reference to HD-Audio.txt in ALSA-Configuration.txt Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 3cd2ad958176..3f2bdd533c3f 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -778,6 +778,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. specify a certain model in such a case. There are different models depending on the codec chip. + See Documentation/sound/alsa/HD-Audio.txt for some details. + Model name Description ---------- ----------- ALC880 From 32c8dabc97d436582298ebd0e33af041c69f5a4b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 19:41:13 +0000 Subject: [PATCH 256/367] ASoC: Remove obsolete declaration of struct snd_soc_clock_info The struct is never defined. Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 8ec63c02dc10..79d855d2bddd 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -152,7 +152,6 @@ struct snd_soc_dai; struct snd_soc_codec; struct soc_enum; struct snd_soc_ac97_ops; -struct snd_soc_clock_info; typedef int (*hw_write_t)(void *,const char* ,int); typedef int (*hw_read_t)(void *,char* ,int); From 5da95273c2e63c9607652b5e8dd39808b6992d7c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 24 Nov 2008 14:06:08 +0100 Subject: [PATCH 257/367] ALSA: ca0106 - Add power-management support Added the missing PM support for snd-ca0106 driver. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106.h | 15 +- sound/pci/ca0106/ca0106_main.c | 521 +++++++++++++++++++------------- sound/pci/ca0106/ca0106_mixer.c | 182 +++++++---- 3 files changed, 451 insertions(+), 267 deletions(-) diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 74175fc80c7f..1c14ff424116 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -686,7 +686,7 @@ struct snd_ca0106 { spinlock_t emu_lock; struct snd_ac97 *ac97; - struct snd_pcm *pcm; + struct snd_pcm *pcm[4]; struct snd_ca0106_channel playback_channels[4]; struct snd_ca0106_channel capture_channels[4]; @@ -703,6 +703,11 @@ struct snd_ca0106 { struct snd_ca_midi midi2; u16 spi_dac_reg[16]; + +#ifdef CONFIG_PM +#define NUM_SAVED_VOLUMES 9 + unsigned int saved_vol[NUM_SAVED_VOLUMES]; +#endif }; int snd_ca0106_mixer(struct snd_ca0106 *emu); @@ -721,3 +726,11 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value); int snd_ca0106_spi_write(struct snd_ca0106 * emu, unsigned int data); + +#ifdef CONFIG_PM +void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip); +void snd_ca0106_mixer_resume(struct snd_ca0106 *chip); +#else +#define snd_ca0106_mixer_suspend(chip) do { } while (0) +#define snd_ca0106_mixer_resume(chip) do { } while (0) +#endif diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 88fbf285d2b7..cea8a7cdb1d5 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -847,15 +847,18 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, struct snd_pcm_substream *s; u32 basic = 0; u32 extended = 0; - int running=0; + u32 bits; + int running = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: - running=1; + case SNDRV_PCM_TRIGGER_RESUME: + running = 1; break; case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: default: - running=0; + running = 0; break; } snd_pcm_group_for_each_entry(s, substream) { @@ -865,22 +868,32 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, runtime = s->runtime; epcm = runtime->private_data; channel = epcm->channel_id; - //snd_printk("channel=%d\n",channel); + /* snd_printk("channel=%d\n",channel); */ epcm->running = running; - basic |= (0x1<ac97); } +static void ca0106_stop_chip(struct snd_ca0106 *chip); + static int snd_ca0106_free(struct snd_ca0106 *chip) { - if (chip->res_port != NULL) { /* avoid access to already used hardware */ - // disable interrupts - snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); - outl(0, chip->port + INTE); - snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); - udelay(1000); - // disable audio - //outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); - outl(0, chip->port + HCFG); - /* FIXME: We need to stop and DMA transfers here. - * But as I am not sure how yet, we cannot from the dma pages. - * So we can fix: snd-malloc: Memory leak? pages not freed = 8 - */ + if (chip->res_port != NULL) { + /* avoid access to already used hardware */ + ca0106_stop_chip(chip); } if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1203,15 +1208,14 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct snd_pcm **rpcm) +static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; - if (rpcm) - *rpcm = NULL; - if ((err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm)) < 0) + err = snd_pcm_new(emu->card, "ca0106", device, 1, 1, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -1238,7 +1242,6 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "CA0106"); - emu->pcm = pcm; for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; @@ -1260,8 +1263,7 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device, struct s return err; } - if (rpcm) - *rpcm = pcm; + emu->pcm[device] = pcm; return 0; } @@ -1301,89 +1303,9 @@ static unsigned int i2c_adc_init[][2] = { { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ }; -static int __devinit snd_ca0106_create(int dev, struct snd_card *card, - struct pci_dev *pci, - struct snd_ca0106 **rchip) +static void ca0106_init_chip(struct snd_ca0106 *chip) { - struct snd_ca0106 *chip; - struct snd_ca0106_details *c; - int err; int ch; - static struct snd_device_ops ops = { - .dev_free = snd_ca0106_dev_free, - }; - - *rchip = NULL; - - if ((err = pci_enable_device(pci)) < 0) - return err; - if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || - pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { - printk(KERN_ERR "error to set 32bit mask DMA\n"); - pci_disable_device(pci); - return -ENXIO; - } - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } - - chip->card = card; - chip->pci = pci; - chip->irq = -1; - - spin_lock_init(&chip->emu_lock); - - chip->port = pci_resource_start(pci, 0); - if ((chip->res_port = request_region(chip->port, 0x20, - "snd_ca0106")) == NULL) { - snd_ca0106_free(chip); - printk(KERN_ERR "cannot allocate the port\n"); - return -EBUSY; - } - - if (request_irq(pci->irq, snd_ca0106_interrupt, - IRQF_SHARED, "snd_ca0106", chip)) { - snd_ca0106_free(chip); - printk(KERN_ERR "cannot grab irq\n"); - return -EBUSY; - } - chip->irq = pci->irq; - - /* This stores the periods table. */ - if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &chip->buffer) < 0) { - snd_ca0106_free(chip); - return -ENOMEM; - } - - pci_set_master(pci); - /* read serial */ - pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); - pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); -#if 1 - printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model, - pci->revision, chip->serial); -#endif - strcpy(card->driver, "CA0106"); - strcpy(card->shortname, "CA0106"); - - for (c = ca0106_chip_details; c->serial; c++) { - if (subsystem[dev]) { - if (c->serial == subsystem[dev]) - break; - } else if (c->serial == chip->serial) - break; - } - chip->details = c; - if (subsystem[dev]) { - printk(KERN_INFO "snd-ca0106: Sound card name=%s, subsystem=0x%x. Forced to subsystem=0x%x\n", - c->name, chip->serial, subsystem[dev]); - } - - sprintf(card->longname, "%s at 0x%lx irq %i", - c->name, chip->port, chip->irq); outl(0, chip->port + INTE); @@ -1401,31 +1323,31 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, * AN = 0 (Audio data) * P = 0 (Consumer) */ - snd_ca0106_ptr_write(chip, SPCS0, 0, - chip->spdif_bits[0] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + chip->spdif_bits[0] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); /* Only SPCS1 has been tested */ - snd_ca0106_ptr_write(chip, SPCS1, 0, - chip->spdif_bits[1] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); - snd_ca0106_ptr_write(chip, SPCS2, 0, - chip->spdif_bits[2] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); - snd_ca0106_ptr_write(chip, SPCS3, 0, - chip->spdif_bits[3] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); + chip->spdif_bits[1] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); + chip->spdif_bits[2] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); + chip->spdif_bits[3] = + SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | + SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | + SPCS_GENERATIONSTATUS | 0x00001200 | + 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); @@ -1433,36 +1355,53 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, /* Write 0x8000 to AC97_REC_GAIN to mute it. */ outb(AC97_REC_GAIN, chip->port + AC97ADDRESS); outw(0x8000, chip->port + AC97DATA); -#if 0 +#if 0 /* FIXME: what are these? */ snd_ca0106_ptr_write(chip, SPCS0, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x42, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x43, 0, 0x2108006); snd_ca0106_ptr_write(chip, 0x44, 0, 0x2108006); #endif - //snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); /* OSS drivers set this. */ + /* OSS drivers set this. */ + /* snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0xf0f003f); */ + /* Analog or Digital output */ snd_ca0106_ptr_write(chip, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. Use 0x000f0000 for surround71 */ - chip->spdif_enable = 0; /* Set digital SPDIF output off */ - //snd_ca0106_ptr_write(chip, 0x45, 0, 0); /* Analogue out */ - //snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00); /* Digital out */ + /* 0x0b000000 for digital, 0x000b0000 for analog, from win2000 drivers. + * Use 0x000f0000 for surround71 + */ + snd_ca0106_ptr_write(chip, SPDIF_SELECT2, 0, 0x000f0000); + + chip->spdif_enable = 0; /* Set digital SPDIF output off */ + /*snd_ca0106_ptr_write(chip, 0x45, 0, 0);*/ /* Analogue out */ + /*snd_ca0106_ptr_write(chip, 0x45, 0, 0xf00);*/ /* Digital out */ + + /* goes to 0x40c80000 when doing SPDIF IN/OUT */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); + /* (Mute) CAPTURE feedback into PLAYBACK volume. + * Only lower 16 bits matter. + */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); + /* SPDIF IN Volume */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); + /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ + snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 0, 0x40c81000); /* goes to 0x40c80000 when doing SPDIF IN/OUT */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 1, 0xffffffff); /* (Mute) CAPTURE feedback into PLAYBACK volume. Only lower 16 bits matter. */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 2, 0x30300000); /* SPDIF IN Volume */ - snd_ca0106_ptr_write(chip, CAPTURE_CONTROL, 3, 0x00700000); /* SPDIF IN Volume, 0x70 = (vol & 0x3f) | 0x40 */ snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, PLAYBACK_ROUTING2, 0, 0x76767676); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING1, 0, 0x32765410); snd_ca0106_ptr_write(chip, CAPTURE_ROUTING2, 0, 0x76767676); - for(ch = 0; ch < 4; ch++) { - snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); /* Only high 16 bits matter */ + + for (ch = 0; ch < 4; ch++) { + /* Only high 16 bits matter */ + snd_ca0106_ptr_write(chip, CAPTURE_VOLUME1, ch, 0x30303030); snd_ca0106_ptr_write(chip, CAPTURE_VOLUME2, ch, 0x30303030); - //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); /* Mute */ - //snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); /* Mute */ - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); /* Mute */ - snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); /* Mute */ +#if 0 /* Mute */ + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0x40404040); + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0x40404040); + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME1, ch, 0xffffffff); + snd_ca0106_ptr_write(chip, PLAYBACK_VOLUME2, ch, 0xffffffff); +#endif } if (chip->details->i2c_adc == 1) { /* Select MIC, Line in, TAD in, AUX in */ @@ -1481,44 +1420,56 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, chip->capture_source = 3; } - if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ - /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ + if (chip->details->gpio_type == 2) { + /* The SB0438 use GPIO differently. */ + /* FIXME: Still need to find out what the other GPIO bits do. + * E.g. For digital spdif out. + */ outl(0x0, chip->port+GPIO); - //outl(0x00f0e000, chip->port+GPIO); /* Analog */ + /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ - } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ - /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ + } else if (chip->details->gpio_type == 1) { + /* The SB0410 and SB0413 use GPIO differently. */ + /* FIXME: Still need to find out what the other GPIO bits do. + * E.g. For digital spdif out. + */ outl(0x0, chip->port+GPIO); - //outl(0x00f0e000, chip->port+GPIO); /* Analog */ + /* outl(0x00f0e000, chip->port+GPIO); */ /* Analog */ outl(0x005f5301, chip->port+GPIO); /* Analog */ } else { outl(0x0, chip->port+GPIO); outl(0x005f03a3, chip->port+GPIO); /* Analog */ - //outl(0x005f02a2, chip->port+GPIO); /* SPDIF */ + /* outl(0x005f02a2, chip->port+GPIO); */ /* SPDIF */ } snd_ca0106_intr_enable(chip, 0x105); /* Win2000 uses 0x1e0 */ - //outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); - //outl(0x00001409, chip->port+HCFG); /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ - //outl(0x00000009, chip->port+HCFG); - outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ + /* outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); */ + /* 0x1000 causes AC3 to fails. Maybe it effects 24 bit output. */ + /* outl(0x00001409, chip->port+HCFG); */ + /* outl(0x00000009, chip->port+HCFG); */ + /* AC97 2.0, Enable outputs. */ + outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); - if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ + if (chip->details->i2c_adc == 1) { + /* The SB0410 and SB0413 use I2C to control ADC. */ int size, n; size = ARRAY_SIZE(i2c_adc_init); - //snd_printk("I2C:array size=0x%x\n", size); - for (n=0; n < size; n++) { - snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); + /* snd_printk("I2C:array size=0x%x\n", size); */ + for (n = 0; n < size; n++) + snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], + i2c_adc_init[n][1]); + for (n = 0; n < 4; n++) { + chip->i2c_capture_volume[n][0] = 0xcf; + chip->i2c_capture_volume[n][1] = 0xcf; } - for (n=0; n < 4; n++) { - chip->i2c_capture_volume[n][0]= 0xcf; - chip->i2c_capture_volume[n][1]= 0xcf; - } - chip->i2c_capture_source=2; /* Line in */ - //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ + chip->i2c_capture_source = 2; /* Line in */ + /* Enable Line-in capture. MIC in currently untested. */ + /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ } - if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ + + if (chip->details->spi_dac == 1) { + /* The SB0570 use SPI to control DAC. */ int size, n; size = ARRAY_SIZE(spi_dac_init); @@ -1530,9 +1481,112 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, chip->spi_dac_reg[reg] = spi_dac_init[n]; } } +} - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &ops)) < 0) { +static void ca0106_stop_chip(struct snd_ca0106 *chip) +{ + /* disable interrupts */ + snd_ca0106_ptr_write(chip, BASIC_INTERRUPT, 0, 0); + outl(0, chip->port + INTE); + snd_ca0106_ptr_write(chip, EXTENDED_INT_MASK, 0, 0); + udelay(1000); + /* disable audio */ + /* outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); */ + outl(0, chip->port + HCFG); + /* FIXME: We need to stop and DMA transfers here. + * But as I am not sure how yet, we cannot from the dma pages. + * So we can fix: snd-malloc: Memory leak? pages not freed = 8 + */ +} + +static int __devinit snd_ca0106_create(int dev, struct snd_card *card, + struct pci_dev *pci, + struct snd_ca0106 **rchip) +{ + struct snd_ca0106 *chip; + struct snd_ca0106_details *c; + int err; + static struct snd_device_ops ops = { + .dev_free = snd_ca0106_dev_free, + }; + + *rchip = NULL; + + err = pci_enable_device(pci); + if (err < 0) + return err; + if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) { + printk(KERN_ERR "error to set 32bit mask DMA\n"); + pci_disable_device(pci); + return -ENXIO; + } + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + pci_disable_device(pci); + return -ENOMEM; + } + + chip->card = card; + chip->pci = pci; + chip->irq = -1; + + spin_lock_init(&chip->emu_lock); + + chip->port = pci_resource_start(pci, 0); + chip->res_port = request_region(chip->port, 0x20, "snd_ca0106"); + if (!chip->res_port) { + snd_ca0106_free(chip); + printk(KERN_ERR "cannot allocate the port\n"); + return -EBUSY; + } + + if (request_irq(pci->irq, snd_ca0106_interrupt, + IRQF_SHARED, "snd_ca0106", chip)) { + snd_ca0106_free(chip); + printk(KERN_ERR "cannot grab irq\n"); + return -EBUSY; + } + chip->irq = pci->irq; + + /* This stores the periods table. */ + if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), + 1024, &chip->buffer) < 0) { + snd_ca0106_free(chip); + return -ENOMEM; + } + + pci_set_master(pci); + /* read serial */ + pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); + pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); + printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", + chip->model, pci->revision, chip->serial); + strcpy(card->driver, "CA0106"); + strcpy(card->shortname, "CA0106"); + + for (c = ca0106_chip_details; c->serial; c++) { + if (subsystem[dev]) { + if (c->serial == subsystem[dev]) + break; + } else if (c->serial == chip->serial) + break; + } + chip->details = c; + if (subsystem[dev]) { + printk(KERN_INFO "snd-ca0106: Sound card name=%s, " + "subsystem=0x%x. Forced to subsystem=0x%x\n", + c->name, chip->serial, subsystem[dev]); + } + + sprintf(card->longname, "%s at 0x%lx irq %i", + c->name, chip->port, chip->irq); + + ca0106_init_chip(chip); + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { snd_ca0106_free(chip); return err; } @@ -1629,7 +1683,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, static int dev; struct snd_card *card; struct snd_ca0106 *chip; - int err; + int i, err; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -1642,44 +1696,30 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, if (card == NULL) return -ENOMEM; - if ((err = snd_ca0106_create(dev, card, pci, &chip)) < 0) { - snd_card_free(card); - return err; + err = snd_ca0106_create(dev, card, pci, &chip); + if (err < 0) + goto error; + + for (i = 0; i < 4; i++) { + err = snd_ca0106_pcm(chip, i); + if (err < 0) + goto error; } - if ((err = snd_ca0106_pcm(chip, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_ca0106_pcm(chip, 1, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_ca0106_pcm(chip, 2, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_ca0106_pcm(chip, 3, NULL)) < 0) { - snd_card_free(card); - return err; - } - if (chip->details->ac97 == 1) { /* The SB0410 and SB0413 do not have an AC97 chip. */ - if ((err = snd_ca0106_ac97(chip)) < 0) { - snd_card_free(card); - return err; - } - } - if ((err = snd_ca0106_mixer(chip)) < 0) { - snd_card_free(card); - return err; + if (chip->details->ac97 == 1) { + /* The SB0410 and SB0413 do not have an AC97 chip. */ + err = snd_ca0106_ac97(chip); + if (err < 0) + goto error; } + err = snd_ca0106_mixer(chip); + if (err < 0) + goto error; snd_printdd("ca0106: probe for MIDI channel A ..."); - if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) { - snd_card_free(card); - snd_printdd(" failed, err=0x%x\n",err); - return err; - } + err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A); + if (err < 0) + goto error; snd_printdd(" done.\n"); #ifdef CONFIG_PROC_FS @@ -1688,14 +1728,17 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, snd_card_set_dev(card, &pci->dev); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + err = snd_card_register(card); + if (err < 0) + goto error; pci_set_drvdata(pci, card); dev++; return 0; + + error: + snd_card_free(card); + return err; } static void __devexit snd_ca0106_remove(struct pci_dev *pci) @@ -1704,6 +1747,52 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } +#ifdef CONFIG_PM +static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ca0106 *chip = card->private_data; + int i; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + for (i = 0; i < 4; i++) + snd_pcm_suspend_all(chip->pcm[i]); + snd_ac97_suspend(chip->ac97); + snd_ca0106_mixer_suspend(chip); + + ca0106_stop_chip(chip); + + pci_disable_device(pci); + pci_save_state(pci); + pci_set_power_state(pci, pci_choose_state(pci, state)); + return 0; +} + +static int snd_ca0106_resume(struct pci_dev *pci) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ca0106 *chip = card->private_data; + int i; + + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); + pci_enable_device(pci); + pci_set_master(pci); + + ca0106_init_chip(chip); + + snd_ac97_resume(chip->ac97); + snd_ca0106_mixer_resume(chip); + if (chip->details->spi_dac) { + for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) + snd_ca0106_spi_write(chip, chip->spi_dac_reg[i]); + } + + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; +} +#endif + // PCI IDs static struct pci_device_id snd_ca0106_ids[] = { { 0x1102, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Audigy LS or Live 24bit */ @@ -1717,6 +1806,10 @@ static struct pci_driver driver = { .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove), +#ifdef CONFIG_PM + .suspend = snd_ca0106_suspend, + .resume = snd_ca0106_resume, +#endif }; // initialization of the module diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 3025ed1b6e1e..cccc32cdb943 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -75,6 +75,84 @@ #include "ca0106.h" +static void ca0106_spdif_enable(struct snd_ca0106 *emu) +{ + unsigned int val; + + if (emu->spdif_enable) { + /* Digital */ + snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); + val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; + snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); + val = inl(emu->port + GPIO) & ~0x101; + outl(val, emu->port + GPIO); + + } else { + /* Analog */ + snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); + snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); + val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; + snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); + val = inl(emu->port + GPIO) | 0x101; + outl(val, emu->port + GPIO); + } +} + +static void ca0106_set_capture_source(struct snd_ca0106 *emu) +{ + unsigned int val = emu->capture_source; + unsigned int source, mask; + source = (val << 28) | (val << 24) | (val << 20) | (val << 16); + mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; + snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); +} + +static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu, + unsigned int val, int force) +{ + unsigned int ngain, ogain; + u32 source; + + snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ + ngain = emu->i2c_capture_volume[val][0]; /* Left */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ + if (force || ngain != ogain) + snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff); + ngain = emu->i2c_capture_volume[val][1]; /* Right */ + ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ + if (force || ngain != ogain) + snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff); + source = 1 << val; + snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ + emu->i2c_capture_source = val; +} + +static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) +{ + u32 tmp; + + if (emu->capture_mic_line_in) { + /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + tmp = tmp | 0x400; + outl(tmp, emu->port+GPIO); + /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */ + } else { + /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ + tmp = inl(emu->port+GPIO) & ~0x400; + outl(tmp, emu->port+GPIO); + /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */ + } +} + +static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) +{ + snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); +} + +/* + */ static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); @@ -95,30 +173,12 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; - u32 mask; val = !!ucontrol->value.integer.value[0]; change = (emu->spdif_enable != val); if (change) { emu->spdif_enable = val; - if (val) { - /* Digital */ - snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); - snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, - snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000); - mask = inl(emu->port + GPIO) & ~0x101; - outl(mask, emu->port + GPIO); - - } else { - /* Analog */ - snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); - snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); - snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, - snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); - mask = inl(emu->port + GPIO) | 0x101; - outl(mask, emu->port + GPIO); - } + ca0106_spdif_enable(emu); } return change; } @@ -154,8 +214,6 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; - u32 mask; - u32 source; val = ucontrol->value.enumerated.item[0] ; if (val >= 6) @@ -163,9 +221,7 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, change = (emu->capture_source != val); if (change) { emu->capture_source = val; - source = (val << 28) | (val << 24) | (val << 20) | (val << 16); - mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; - snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); + ca0106_set_capture_source(emu); } return change; } @@ -200,9 +256,7 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, { struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int source_id; - unsigned int ngain, ogain; int change = 0; - u32 source; /* If the capture source has changed, * update the capture volume from the cached value * for the particular source. @@ -212,18 +266,7 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, return -EINVAL; change = (emu->i2c_capture_source != source_id); if (change) { - snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ - ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ - if (ngain != ogain) - snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); - ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ - ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ - if (ngain != ogain) - snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); - source = 1 << source_id; - snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ - emu->i2c_capture_source = source_id; + ca0106_set_i2c_capture_source(emu, source_id, 0); } return change; } @@ -271,7 +314,6 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; - u32 tmp; val = ucontrol->value.enumerated.item[0] ; if (val > 1) @@ -279,18 +321,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, change = (emu->capture_mic_line_in != val); if (change) { emu->capture_mic_line_in = val; - if (val) { - //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - tmp = inl(emu->port+GPIO) & ~0x400; - tmp = tmp | 0x400; - outl(tmp, emu->port+GPIO); - //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); - } else { - //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - tmp = inl(emu->port+GPIO) & ~0x400; - outl(tmp, emu->port+GPIO); - //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); - } + ca0106_set_capture_mic_line_in(emu); } return change; } @@ -359,8 +390,8 @@ static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, (ucontrol->value.iec958.status[3] << 24); change = val != emu->spdif_bits[idx]; if (change) { - snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val); emu->spdif_bits[idx] = val; + ca0106_set_spdif_bits(emu, idx); } return change; } @@ -773,3 +804,50 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) return 0; } +#ifdef CONFIG_PM +struct ca0106_vol_tbl { + unsigned int reg; + unsigned int channel_id; +}; + +static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { + { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 }, + { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 }, + { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 }, + { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 }, + { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 }, + { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 }, + { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 }, + { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 }, + { 1, CAPTURE_CONTROL }, +}; + +void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip) +{ + int i; + + /* save volumes */ + for (i = 0; i < NUM_SAVED_VOLUMES; i++) + chip->saved_vol[i] = + snd_ca0106_ptr_read(chip, saved_volumes[i].reg, + saved_volumes[i].channel_id); +} + +void snd_ca0106_mixer_resume(struct snd_ca0106 *chip) +{ + int i; + + for (i = 0; i < NUM_SAVED_VOLUMES; i++) + snd_ca0106_ptr_write(chip, saved_volumes[i].reg, + saved_volumes[i].channel_id, + chip->saved_vol[i]); + + ca0106_spdif_enable(chip); + ca0106_set_capture_source(chip); + ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1); + for (i = 0; i < 4; i++) + ca0106_set_spdif_bits(chip, i); + if (chip->details->i2c_adc) + ca0106_set_capture_mic_line_in(chip); +} +#endif /* CONFIG_PM */ From e6e3ea25b1679b55728a8a470a50a8fff61e8a45 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Dec 2008 12:54:56 +0100 Subject: [PATCH 258/367] ALSA: hda - Fix pin-detection in patch_sigmatel.c The pin-detection function used in patch_sigmatel.c shouldn't be specific to HP pin because it's used for input pins in general, too. This patch fixes the detection function, removes the HP check from it and moves to stac92xx_hp_detect(). Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f98c7e997877..08170dff75e0 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4061,20 +4061,13 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, pin_ctl & ~flag); } -static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid) +static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) { if (!nid) return 0; if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) - & (1 << 31)) { - unsigned int pinctl; - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pinctl & AC_PINCTL_IN_EN) - return 0; /* mic- or line-input */ - else - return 1; /* HP-output */ - } + & (1 << 31)) + return 1; return 0; } @@ -4114,7 +4107,14 @@ static void stac92xx_hp_detect(struct hda_codec *codec) break; if (no_hp_sensing(spec, i)) continue; - presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); + 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) { @@ -4191,7 +4191,7 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) { - stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid)); + stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); } static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) @@ -4213,7 +4213,7 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) type = (pin_ctl & AC_PINCTL_HP_EN) ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT; snd_jack_report(jacks->jack, - get_hp_pin_presence(codec, nid) + get_pin_presence(codec, nid) ? type : 0); } jacks++; @@ -5349,7 +5349,7 @@ static int stac9872_vaio_init(struct hda_codec *codec) static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) { - if (get_hp_pin_presence(codec, 0x0a)) { + if (get_pin_presence(codec, 0x0a)) { stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); } else { From 12dde4c6d6e9092cf63094e84dc1fe4e505dd6d0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Dec 2008 13:09:27 +0100 Subject: [PATCH 259/367] ALSA: hda - Proper power-map toggling for input pins The current code overrides the event type on input pins always to PWR_EVENT. Although this still works (PWR_EVENT and INSERT_EVENT are handled samely), it'd be better to avoid such overrides. Also, currently the unsol events are registered even for fixed pins which will never raise the pin-detection event. This patch fixes both issues. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 08170dff75e0..4c851fd55565 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3915,24 +3915,36 @@ static int stac92xx_init(struct hda_codec *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); } for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = cfg->input_pins[i]; if (nid) { - unsigned int pinctl; + unsigned int pinctl, conf; if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { /* for mic pins, force to initialize */ pinctl = stac92xx_get_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 */ - if (pinctl & AC_PINCTL_IN_EN) - continue; + if (!(pinctl & AC_PINCTL_IN_EN)) { + pinctl |= AC_PINCTL_IN_EN; + stac92xx_auto_set_pinctl(codec, nid, + pinctl); + } + } + conf = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { + enable_pin_detect(codec, nid, + STAC_INSERT_EVENT); + stac_issue_unsol_event(codec, nid, + STAC_INSERT_EVENT); } - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, pinctl); - enable_pin_detect(codec, nid, STAC_INSERT_EVENT); } } for (i = 0; i < spec->num_dmics; i++) @@ -3969,8 +3981,10 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } - enable_pin_detect(codec, nid, STAC_PWR_EVENT); - stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); + if (!stac_get_event(codec, nid, STAC_INSERT_EVENT)) { + enable_pin_detect(codec, nid, STAC_PWR_EVENT); + stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); + } } if (spec->dac_list) stac92xx_power_down(codec); From 68fb740774a429ecbccd4d8b3287cf4883ad3ec2 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Thu, 4 Dec 2008 22:39:54 +0200 Subject: [PATCH 260/367] ASoC: Add support for OMAP3 Pandora This patch adds basic support for OMAP3 Pandora. Signed-off-by: Grazvydas Ignotas Signed-off-by: Mark Brown --- sound/soc/omap/Kconfig | 8 + sound/soc/omap/Makefile | 2 + sound/soc/omap/omap3pandora.c | 311 ++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 sound/soc/omap/omap3pandora.c diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index da39f27c6613..a7b1d77b2105 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig @@ -46,3 +46,11 @@ config SND_OMAP_SOC_SDP3430 help Say Y if you want to add support for SoC audio on Texas Instruments SDP3430. + +config SND_OMAP_SOC_OMAP3_PANDORA + tristate "SoC Audio support for OMAP3 Pandora" + depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA + select SND_OMAP_SOC_MCBSP + select SND_SOC_TWL4030 + help + Say Y if you want to add support for SoC audio on the OMAP3 Pandora. diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 29cf3a856c89..76fedd96e365 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile @@ -11,9 +11,11 @@ snd-soc-osk5912-objs := osk5912.o snd-soc-overo-objs := overo.o snd-soc-omap2evm-objs := omap2evm.o snd-soc-sdp3430-objs := sdp3430.o +snd-soc-omap3pandora-objs := omap3pandora.o obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o obj-$(CONFIG_MACH_OMAP2EVM) += snd-soc-omap2evm.o obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o +obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c new file mode 100644 index 000000000000..bd91594496b1 --- /dev/null +++ b/sound/soc/omap/omap3pandora.c @@ -0,0 +1,311 @@ +/* + * omap3pandora.c -- SoC audio for Pandora Handheld Console + * + * Author: Gražvydas Ignotas + * + * 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. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "omap-mcbsp.h" +#include "omap-pcm.h" +#include "../codecs/twl4030.h" + +#define OMAP3_PANDORA_DAC_POWER_GPIO 118 +#define OMAP3_PANDORA_AMP_POWER_GPIO 14 + +#define PREFIX "ASoC omap3pandora: " + +static int omap3pandora_cmn_hw_params(struct snd_soc_dai *codec_dai, + struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + int ret; + + /* Set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, fmt); + if (ret < 0) { + pr_err(PREFIX "can't set codec DAI configuration\n"); + return ret; + } + + /* Set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_err(PREFIX "can't set cpu DAI configuration\n"); + return ret; + } + + /* Set the codec system clock for DAC and ADC */ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000, + SND_SOC_CLOCK_IN); + if (ret < 0) { + pr_err(PREFIX "can't set codec system clock\n"); + return ret; + } + + /* Set McBSP clock to external */ + ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT, 0, + SND_SOC_CLOCK_IN); + if (ret < 0) { + pr_err(PREFIX "can't set cpu system clock\n"); + return ret; + } + + ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8); + if (ret < 0) { + pr_err(PREFIX "can't set SRG clock divider\n"); + return ret; + } + + return 0; +} + +static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFS); +} + +static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + + return omap3pandora_cmn_hw_params(codec_dai, cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); +} + +static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); + gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1); + } else { + gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0); + mdelay(1); + gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0); + } + + return 0; +} + +/* + * Audio paths on Pandora board: + * + * |O| ---> PCM DAC +-> AMP -> Headphone Jack + * |M| A +--------> Line Out + * |A| <~~clk~~+ + * |P| <--- TWL4030 <--------- Line In and MICs + */ +static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = { + SND_SOC_DAPM_DAC("PCM DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM, + 0, 0, NULL, 0, omap3pandora_hp_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), +}; + +static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic (Internal)", NULL), + SND_SOC_DAPM_MIC("Mic (external)", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), +}; + +static const struct snd_soc_dapm_route omap3pandora_out_map[] = { + {"Headphone Amplifier", NULL, "PCM DAC"}, + {"Line Out", NULL, "PCM DAC"}, + {"Headphone Jack", NULL, "Headphone Amplifier"}, +}; + +static const struct snd_soc_dapm_route omap3pandora_in_map[] = { + {"INL", NULL, "Line In"}, + {"INR", NULL, "Line In"}, + {"INL", NULL, "Mic (Internal)"}, + {"INR", NULL, "Mic (external)"}, +}; + +static int omap3pandora_out_init(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets, + ARRAY_SIZE(omap3pandora_out_dapm_widgets)); + if (ret < 0) + return ret; + + snd_soc_dapm_add_routes(codec, omap3pandora_out_map, + ARRAY_SIZE(omap3pandora_out_map)); + + return snd_soc_dapm_sync(codec); +} + +static int omap3pandora_in_init(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets, + ARRAY_SIZE(omap3pandora_in_dapm_widgets)); + if (ret < 0) + return ret; + + snd_soc_dapm_add_routes(codec, omap3pandora_in_map, + ARRAY_SIZE(omap3pandora_in_map)); + + return snd_soc_dapm_sync(codec); +} + +static struct snd_soc_ops omap3pandora_out_ops = { + .hw_params = omap3pandora_out_hw_params, +}; + +static struct snd_soc_ops omap3pandora_in_ops = { + .hw_params = omap3pandora_in_hw_params, +}; + +/* Digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link omap3pandora_dai[] = { + { + .name = "PCM1773", + .stream_name = "HiFi Out", + .cpu_dai = &omap_mcbsp_dai[0], + .codec_dai = &twl4030_dai, + .ops = &omap3pandora_out_ops, + .init = omap3pandora_out_init, + }, { + .name = "TWL4030", + .stream_name = "Line/Mic In", + .cpu_dai = &omap_mcbsp_dai[1], + .codec_dai = &twl4030_dai, + .ops = &omap3pandora_in_ops, + .init = omap3pandora_in_init, + } +}; + +/* SoC card */ +static struct snd_soc_card snd_soc_card_omap3pandora = { + .name = "omap3pandora", + .platform = &omap_soc_platform, + .dai_link = omap3pandora_dai, + .num_links = ARRAY_SIZE(omap3pandora_dai), +}; + +/* Audio subsystem */ +static struct snd_soc_device omap3pandora_snd_data = { + .card = &snd_soc_card_omap3pandora, + .codec_dev = &soc_codec_dev_twl4030, +}; + +static struct platform_device *omap3pandora_snd_device; + +static int __init omap3pandora_soc_init(void) +{ + int ret; + + if (!machine_is_omap3_pandora()) { + pr_debug(PREFIX "Not OMAP3 Pandora\n"); + return -ENODEV; + } + pr_info("OMAP3 Pandora SoC init\n"); + + ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power"); + if (ret) { + pr_err(PREFIX "Failed to get DAC power GPIO\n"); + return ret; + } + + ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0); + if (ret) { + pr_err(PREFIX "Failed to set DAC power GPIO direction\n"); + goto fail0; + } + + ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power"); + if (ret) { + pr_err(PREFIX "Failed to get amp power GPIO\n"); + goto fail0; + } + + ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0); + if (ret) { + pr_err(PREFIX "Failed to set amp power GPIO direction\n"); + goto fail1; + } + + omap3pandora_snd_device = platform_device_alloc("soc-audio", -1); + if (omap3pandora_snd_device == NULL) { + pr_err(PREFIX "Platform device allocation failed\n"); + ret = -ENOMEM; + goto fail1; + } + + platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data); + omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev; + *(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */ + *(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */ + + ret = platform_device_add(omap3pandora_snd_device); + if (ret) { + pr_err(PREFIX "Unable to add platform device\n"); + goto fail2; + } + + return 0; + +fail2: + platform_device_put(omap3pandora_snd_device); +fail1: + gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); +fail0: + gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); + return ret; +} +module_init(omap3pandora_soc_init); + +static void __exit omap3pandora_soc_exit(void) +{ + platform_device_unregister(omap3pandora_snd_device); + gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO); + gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO); +} +module_exit(omap3pandora_soc_exit); + +MODULE_AUTHOR("Grazvydas Ignotas "); +MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora"); +MODULE_LICENSE("GPL"); From 28a1d869560a49d960ba2a3b450ec965712e5560 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 5 Dec 2008 17:31:00 +0100 Subject: [PATCH 261/367] ASoC: tlv320aic3x: control additions and cleanups - split "Line Playback Switch" into "LineL Playback Switch" and "LineR Playback Switch" - split "Line PGA Bypass Playback Volume" into "LineL Left PGA Bypass Playback Volume" and "LineR Right PGA Bypass Playback Volume" - split "Line Line2 Bypass Playback Volume" into "LineL Line2 Bypass Playback Volume" and "LineR Line2 Bypass Playback Volume" - Added "HP Right PGA Bypass Playback Volume" Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 341e1adc9167..6a058298a3c3 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -253,11 +253,17 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_DOUBLE_R("Line DAC Playback Volume", DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL, 0, 0x7f, 1), - SOC_DOUBLE_R("Line DAC Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3, - 0x01, 0), - SOC_DOUBLE_R("Line PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, - PGAR_2_RLOPM_VOL, 0, 0x7f, 1), - SOC_DOUBLE_R("Line Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, + SOC_SINGLE("LineL Playback Switch", LLOPM_CTRL, 3, 0x01, 0), + SOC_SINGLE("LineR Playback Switch", RLOPM_CTRL, 3, 0x01, 0), + SOC_DOUBLE_R("LineL DAC Playback Volume", DACL1_2_LLOPM_VOL, + DACR1_2_LLOPM_VOL, 0, 0x7f, 1), + SOC_SINGLE("LineL Left PGA Bypass Playback Volume", PGAL_2_LLOPM_VOL, + 0, 0x7f, 1), + SOC_SINGLE("LineR Right PGA Bypass Playback Volume", PGAR_2_RLOPM_VOL, + 0, 0x7f, 1), + SOC_DOUBLE_R("LineL Line2 Bypass Playback Volume", LINE2L_2_LLOPM_VOL, + LINE2R_2_LLOPM_VOL, 0, 0x7f, 1), + SOC_DOUBLE_R("LineR Line2 Bypass Playback Volume", LINE2L_2_RLOPM_VOL, LINE2R_2_RLOPM_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("Mono DAC Playback Volume", DACL1_2_MONOLOPM_VOL, @@ -272,6 +278,8 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { DACR1_2_HPROUT_VOL, 0, 0x7f, 1), SOC_DOUBLE_R("HP DAC Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3, 0x01, 0), + SOC_DOUBLE_R("HP Right PGA Bypass Playback Volume", PGAR_2_HPLOUT_VOL, + PGAR_2_HPROUT_VOL, 0, 0x7f, 1), SOC_SINGLE("HPL PGA Bypass Playback Volume", PGAL_2_HPLOUT_VOL, 0, 0x7f, 1), SOC_SINGLE("HPR PGA Bypass Playback Volume", PGAL_2_HPROUT_VOL, From 32e176c14d7a425b681ef003c9061001ddb7fc7b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 6 Dec 2008 15:09:08 +0100 Subject: [PATCH 262/367] Sound: hda - Restore PCI configuration space with interrupts off Move the restoration of the standard PCI configuration registers in the snd_hda_intel driver to a ->resume_early() callback executed with interrupts disabled, since doing that with interrupts enabled may lead to problems in some cases. This patch addresses the regression from 2.6.26 tracked as http://bugzilla.kernel.org/show_bug.cgi?id=12121 . Signed-off-by: Rafael J. Wysocki Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 35722ec920cb..a06b0538fc90 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1951,13 +1951,16 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) return 0; } +static int azx_resume_early(struct pci_dev *pci) +{ + return pci_restore_state(pci); +} + static int azx_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; - pci_set_power_state(pci, PCI_D0); - pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "hda-intel: pci_enable_device failed, " "disabling device\n"); @@ -2465,6 +2468,7 @@ static struct pci_driver driver = { .remove = __devexit_p(azx_remove), #ifdef CONFIG_PM .suspend = azx_suspend, + .resume_early = azx_resume_early, .resume = azx_resume, #endif }; From 647808a6b932d85c3e85df6dcf0e34c1e53cc953 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 8 Dec 2008 12:16:58 +0100 Subject: [PATCH 263/367] ALSA: timer - Add comments and use ns_to_ktime() Add the license and misc comments at the beginning of the code. Also, use ns_to_ktime() for simplification. Signed-off-by: Takashi Iwai --- sound/core/hrtimer.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index b712d7f211ff..866c80c4499d 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -1,4 +1,21 @@ /* + * ALSA timer back-end using hrtimer + * Copyright (C) 2008 Takashi Iwai + * + * 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 @@ -26,7 +43,7 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) { struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); struct snd_timer *t = stime->timer; - hrtimer_forward_now(hrt, ktime_set(0, t->sticks * resolution)); + hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); snd_timer_interrupt(stime->timer, t->sticks); return HRTIMER_RESTART; } @@ -62,7 +79,7 @@ static int snd_hrtimer_start(struct snd_timer *t) { struct snd_hrtimer *stime = t->private_data; - hrtimer_start(&stime->hrt, ktime_set(0, t->sticks * resolution), + hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), HRTIMER_MODE_REL); return 0; } From 5e03c54eeb016cf1b066e9e48d30116814ca2459 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 8 Dec 2008 12:40:56 +0100 Subject: [PATCH 264/367] ALSA: hrtimer - Use hard-irq callback Use the hard-irq mode for the callback (for possible removal of soft-irq mode in future). Signed-off-by: Takashi Iwai --- sound/core/hrtimer.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index 866c80c4499d..c1d285921f80 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -57,7 +57,7 @@ static int snd_hrtimer_open(struct snd_timer *t) return -ENOMEM; hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); stime->timer = t; - stime->hrt.cb_mode = HRTIMER_CB_SOFTIRQ; + stime->hrt.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED; stime->hrt.function = snd_hrtimer_callback; t->private_data = stime; return 0; @@ -93,9 +93,7 @@ static int snd_hrtimer_stop(struct snd_timer *t) } static struct snd_timer_hardware hrtimer_hw = { - .flags = (SNDRV_TIMER_HW_AUTO | - /*SNDRV_TIMER_HW_FIRST |*/ - SNDRV_TIMER_HW_TASKLET), + .flags = SNDRV_TIMER_HW_AUTO, .open = snd_hrtimer_open, .close = snd_hrtimer_close, .start = snd_hrtimer_start, From 30bc4481de890e97dc001ee123761d89638cbc50 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Dec 2008 08:23:45 +0100 Subject: [PATCH 265/367] ALSA: Updates about bug-reporting in ALSA-Configuration.txt Updated the information about bug-reporting for HD-audio. Mentioned alsa-info.sh and kernel bugzilla. Removed ALSA BTS address not to flood the unhandled reports any more. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 3f2bdd533c3f..1c7334a3054e 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1091,8 +1091,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. "codec-patch". It's sometimes good for testing and debugging. If the default configuration doesn't work and one of the above - matches with your device, report it together with the PCI - subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel + matches with your device, report it together with alsa-info.sh + output (with --no-upload option) to kernel bugzilla or alsa-devel ML (see the section "Links and Addresses"). power_save and power_save_controller options are for power-saving @@ -2409,8 +2409,11 @@ Links and Addresses ALSA project homepage http://www.alsa-project.org - ALSA Bug Tracking System - https://bugtrack.alsa-project.org/bugs/ + Kernel Bugzilla + http://bugzilla.kernel.org/ ALSA Developers ML mailto:alsa-devel@alsa-project.org + + alsa-info.sh script + http://www.alsa-project.org/alsa-info.sh From 53b5047d994edfcafabc0e95bb681ae70d6e8604 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 08:45:43 +0200 Subject: [PATCH 266/367] ASoC: TWL4030: Correct DAPM_DAC with power control Add all four DACs to dapm_widgets with power switch. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 3c9fdf2c6c7b..3543bf6e258f 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -616,8 +616,15 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), - SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0), + /* DACs */ + SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", + TWL4030_REG_AVDAC_CTL, 0, 0), + SND_SOC_DAPM_DAC("DACL1", "Left Front Playback", + TWL4030_REG_AVDAC_CTL, 1, 0), + SND_SOC_DAPM_DAC("DACR2", "Right Rear Playback", + TWL4030_REG_AVDAC_CTL, 2, 0), + SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", + TWL4030_REG_AVDAC_CTL, 3, 0), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -625,8 +632,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { static const struct snd_soc_dapm_route intercon[] = { /* outputs */ - {"OUTL", NULL, "DACL"}, - {"OUTR", NULL, "DACR"}, + {"OUTL", NULL, "DACL2"}, + {"OUTR", NULL, "DACR2"}, /* inputs */ {"ADCL", NULL, "INL"}, From 44c5587035fbbdd368a3d5d8d11997d43758078a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 08:45:44 +0200 Subject: [PATCH 267/367] ASoC: TWL4030: Add Analog PGA control switch to DAPM Add all four APGA switch to DAPM routing and widgets. Add user control for DA enable for all APGA as normal control. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 3543bf6e258f..4293ec7b5021 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -562,6 +562,12 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { SOC_DOUBLE_R_TLV("DAC2 Analog Playback Volume", TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, 3, 0x12, 1, analog_tlv), + SOC_DOUBLE_R("DAC1 Analog Playback Switch", + TWL4030_REG_ARXL1_APGA_CTL, TWL4030_REG_ARXR1_APGA_CTL, + 1, 1, 0), + SOC_DOUBLE_R("DAC2 Analog Playback Switch", + TWL4030_REG_ARXL2_APGA_CTL, TWL4030_REG_ARXR2_APGA_CTL, + 1, 1, 0), /* Separate output gain controls */ SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", @@ -626,14 +632,29 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", TWL4030_REG_AVDAC_CTL, 3, 0), + /* Analog PGAs */ + SND_SOC_DAPM_PGA("ARXR1_APGA", TWL4030_REG_ARXR1_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXL1_APGA", TWL4030_REG_ARXL1_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXR2_APGA", TWL4030_REG_ARXR2_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, + 0, 0, NULL, 0), + SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), }; static const struct snd_soc_dapm_route intercon[] = { + {"ARXL1_APGA", NULL, "DACL1"}, + {"ARXR1_APGA", NULL, "DACR1"}, + {"ARXL2_APGA", NULL, "DACL2"}, + {"ARXR2_APGA", NULL, "DACR2"}, + /* outputs */ - {"OUTL", NULL, "DACL2"}, - {"OUTR", NULL, "DACR2"}, + {"OUTL", NULL, "ARXL2_APGA"}, + {"OUTR", NULL, "ARXR2_APGA"}, /* inputs */ {"ADCL", NULL, "INL"}, From e8ff9c417ad6e8f7ef253e36f9d6e22dc2aa2512 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:46 +0200 Subject: [PATCH 268/367] ASoC: TWL4030: Add DAPM event handler for output MUX selection DAPM event handler is set to filter out invalid MUX settings for certain outputs. Earpiece: - 0 = Off - 1 = DACL1 - 2 = DACL2 - 3 = *** Invalid *** - 4 = DACR1 PreDriveL/R: - 0 = Off/Off - 1 = DACL1/DACR1 - 2 = DACL2/DACR2 - 3 = *** Invalid/Invalid *** - 4 = DACR2/DACL2 Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4293ec7b5021..9d1078325c3d 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -190,6 +190,30 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } +static int outmixer_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int ret = 0; + int val; + + switch (e->reg) { + case TWL4030_REG_PREDL_CTL: + case TWL4030_REG_PREDR_CTL: + case TWL4030_REG_EAR_CTL: + val = w->value >> e->shift_l; + if (val == 3) { + printk(KERN_WARNING + "Invalid MUX setting for register 0x%02x (%d)\n", + e->reg, val); + ret = -1; + } + break; + } + + return ret; +} + /* * Some of the gain controls in TWL (mostly those which are associated with * the outputs) are implemented in an interesting way: From 5e98a46449cd028b9b97a8ef2c2448c8f473d6c5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:47 +0200 Subject: [PATCH 269/367] ASoC: TWL4030: DAPM mapping of the Earpiece output Adds DAPM muxing, routing for the Earpiece output. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 9d1078325c3d..1da46175519e 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -190,6 +190,19 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } +/* Earpiece */ +static const char *twl4030_earpiece_texts[] = + {"Off", "DACL1", "DACL2", "Invalid", + "DACR1"}; + +static const struct soc_enum twl4030_earpiece_enum = + SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, + ARRAY_SIZE(twl4030_earpiece_texts), + twl4030_earpiece_texts); + +static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = +SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -645,6 +658,7 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), + SND_SOC_DAPM_OUTPUT("EARPIECE"), /* DACs */ SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", @@ -666,6 +680,12 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_PGA("ARXL2_APGA", TWL4030_REG_ARXL2_APGA_CTL, 0, 0, NULL, 0), + /* Output MUX controls */ + /* Earpiece */ + SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_earpiece_control, outmixer_event, + SND_SOC_DAPM_PRE_REG), + SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), }; @@ -676,9 +696,16 @@ static const struct snd_soc_dapm_route intercon[] = { {"ARXL2_APGA", NULL, "DACL2"}, {"ARXR2_APGA", NULL, "DACR2"}, + /* Internal playback routings */ + /* Earpiece */ + {"Earpiece Mux", "DACL1", "ARXL1_APGA"}, + {"Earpiece Mux", "DACL2", "ARXL2_APGA"}, + {"Earpiece Mux", "DACR1", "ARXR1_APGA"}, + /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, {"OUTR", NULL, "ARXR2_APGA"}, + {"EARPIECE", NULL, "Earpiece Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, From 2a6f5c5892dcd17c81204fe5e26b92a37d2daafa Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:48 +0200 Subject: [PATCH 270/367] ASoC: TWL4030: DAPM mapping of the PreDriv outputs Adds DAPM muxing, routing for the PreDrive outputs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1da46175519e..c508344241e9 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -203,6 +203,32 @@ static const struct soc_enum twl4030_earpiece_enum = static const struct snd_kcontrol_new twl4030_dapm_earpiece_control = SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); +/* PreDrive Left */ +static const char *twl4030_predrivel_texts[] = + {"Off", "DACL1", "DACL2", "Invalid", + "DACR2"}; + +static const struct soc_enum twl4030_predrivel_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, + ARRAY_SIZE(twl4030_predrivel_texts), + twl4030_predrivel_texts); + +static const struct snd_kcontrol_new twl4030_dapm_predrivel_control = +SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); + +/* PreDrive Right */ +static const char *twl4030_predriver_texts[] = + {"Off", "DACR1", "DACR2", "Invalid", + "DACL2"}; + +static const struct soc_enum twl4030_predriver_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, + ARRAY_SIZE(twl4030_predriver_texts), + twl4030_predriver_texts); + +static const struct snd_kcontrol_new twl4030_dapm_predriver_control = +SOC_DAPM_ENUM("Route", twl4030_predriver_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -659,6 +685,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_OUTPUT("OUTR"), SND_SOC_DAPM_OUTPUT("EARPIECE"), + SND_SOC_DAPM_OUTPUT("PREDRIVEL"), + SND_SOC_DAPM_OUTPUT("PREDRIVER"), /* DACs */ SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", @@ -685,6 +713,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_earpiece_control, outmixer_event, SND_SOC_DAPM_PRE_REG), + /* PreDrivL/R */ + SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predrivel_control, outmixer_event, + SND_SOC_DAPM_PRE_REG), + SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_predriver_control, outmixer_event, + SND_SOC_DAPM_PRE_REG), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -701,11 +736,21 @@ static const struct snd_soc_dapm_route intercon[] = { {"Earpiece Mux", "DACL1", "ARXL1_APGA"}, {"Earpiece Mux", "DACL2", "ARXL2_APGA"}, {"Earpiece Mux", "DACR1", "ARXR1_APGA"}, + /* PreDrivL */ + {"PredriveL Mux", "DACL1", "ARXL1_APGA"}, + {"PredriveL Mux", "DACL2", "ARXL2_APGA"}, + {"PredriveL Mux", "DACR2", "ARXR2_APGA"}, + /* PreDrivR */ + {"PredriveR Mux", "DACR1", "ARXR1_APGA"}, + {"PredriveR Mux", "DACR2", "ARXR2_APGA"}, + {"PredriveR Mux", "DACL2", "ARXL2_APGA"}, /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, {"OUTR", NULL, "ARXR2_APGA"}, {"EARPIECE", NULL, "Earpiece Mux"}, + {"PREDRIVEL", NULL, "PredriveL Mux"}, + {"PREDRIVER", NULL, "PredriveR Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, From dfad21a26f5b3cc379fbec9c5d12b5106dd1f9c5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:49 +0200 Subject: [PATCH 271/367] ASoC: TWL4030: DAPM mapping of the Headset outputs Adds DAPM muxing, routing for the Headset outputs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c508344241e9..86ff5a9ffa7f 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -229,6 +229,30 @@ static const struct soc_enum twl4030_predriver_enum = static const struct snd_kcontrol_new twl4030_dapm_predriver_control = SOC_DAPM_ENUM("Route", twl4030_predriver_enum); +/* Headset Left */ +static const char *twl4030_hsol_texts[] = + {"Off", "DACL1", "DACL2"}; + +static const struct soc_enum twl4030_hsol_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 1, + ARRAY_SIZE(twl4030_hsol_texts), + twl4030_hsol_texts); + +static const struct snd_kcontrol_new twl4030_dapm_hsol_control = +SOC_DAPM_ENUM("Route", twl4030_hsol_enum); + +/* Headset Right */ +static const char *twl4030_hsor_texts[] = + {"Off", "DACR1", "DACR2"}; + +static const struct soc_enum twl4030_hsor_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HS_SEL, 4, + ARRAY_SIZE(twl4030_hsor_texts), + twl4030_hsor_texts); + +static const struct snd_kcontrol_new twl4030_dapm_hsor_control = +SOC_DAPM_ENUM("Route", twl4030_hsor_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -687,6 +711,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("EARPIECE"), SND_SOC_DAPM_OUTPUT("PREDRIVEL"), SND_SOC_DAPM_OUTPUT("PREDRIVER"), + SND_SOC_DAPM_OUTPUT("HSOL"), + SND_SOC_DAPM_OUTPUT("HSOR"), /* DACs */ SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", @@ -720,6 +746,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_predriver_control, outmixer_event, SND_SOC_DAPM_PRE_REG), + /* HeadsetL/R */ + SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_hsol_control), + SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_hsor_control), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -744,6 +775,12 @@ static const struct snd_soc_dapm_route intercon[] = { {"PredriveR Mux", "DACR1", "ARXR1_APGA"}, {"PredriveR Mux", "DACR2", "ARXR2_APGA"}, {"PredriveR Mux", "DACL2", "ARXL2_APGA"}, + /* HeadsetL */ + {"HeadsetL Mux", "DACL1", "ARXL1_APGA"}, + {"HeadsetL Mux", "DACL2", "ARXL2_APGA"}, + /* HeadsetR */ + {"HeadsetR Mux", "DACR1", "ARXR1_APGA"}, + {"HeadsetR Mux", "DACR2", "ARXR2_APGA"}, /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, @@ -751,6 +788,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"EARPIECE", NULL, "Earpiece Mux"}, {"PREDRIVEL", NULL, "PredriveL Mux"}, {"PREDRIVER", NULL, "PredriveR Mux"}, + {"HSOL", NULL, "HeadsetL Mux"}, + {"HSOR", NULL, "HeadsetR Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, From 5152d8c28b95e421b91483ca0df76726e6e6c41e Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:50 +0200 Subject: [PATCH 272/367] ASoC: TWL4030: DAPM mapping of the Carkit outputs Adds DAPM muxing, routing for the Carkit outputs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 86ff5a9ffa7f..08c33e9b96ce 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -253,6 +253,30 @@ static const struct soc_enum twl4030_hsor_enum = static const struct snd_kcontrol_new twl4030_dapm_hsor_control = SOC_DAPM_ENUM("Route", twl4030_hsor_enum); +/* Carkit Left */ +static const char *twl4030_carkitl_texts[] = + {"Off", "DACL1", "DACL2"}; + +static const struct soc_enum twl4030_carkitl_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PRECKL_CTL, 1, + ARRAY_SIZE(twl4030_carkitl_texts), + twl4030_carkitl_texts); + +static const struct snd_kcontrol_new twl4030_dapm_carkitl_control = +SOC_DAPM_ENUM("Route", twl4030_carkitl_enum); + +/* Carkit Right */ +static const char *twl4030_carkitr_texts[] = + {"Off", "DACR1", "DACR2"}; + +static const struct soc_enum twl4030_carkitr_enum = + SOC_ENUM_SINGLE(TWL4030_REG_PRECKR_CTL, 1, + ARRAY_SIZE(twl4030_carkitr_texts), + twl4030_carkitr_texts); + +static const struct snd_kcontrol_new twl4030_dapm_carkitr_control = +SOC_DAPM_ENUM("Route", twl4030_carkitr_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -751,6 +775,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { &twl4030_dapm_hsol_control), SND_SOC_DAPM_MUX("HeadsetR Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_hsor_control), + /* CarkitL/R */ + SND_SOC_DAPM_MUX("CarkitL Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_carkitl_control), + SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, + &twl4030_dapm_carkitr_control), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -781,6 +810,12 @@ static const struct snd_soc_dapm_route intercon[] = { /* HeadsetR */ {"HeadsetR Mux", "DACR1", "ARXR1_APGA"}, {"HeadsetR Mux", "DACR2", "ARXR2_APGA"}, + /* CarkitL */ + {"CarkitL Mux", "DACL1", "ARXL1_APGA"}, + {"CarkitL Mux", "DACL2", "ARXL2_APGA"}, + /* CarkitR */ + {"CarkitR Mux", "DACR1", "ARXR1_APGA"}, + {"CarkitR Mux", "DACR2", "ARXR2_APGA"}, /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, @@ -790,6 +825,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"PREDRIVER", NULL, "PredriveR Mux"}, {"HSOL", NULL, "HeadsetL Mux"}, {"HSOR", NULL, "HeadsetR Mux"}, + {"CARKITL", NULL, "CarkitL Mux"}, + {"CARKITR", NULL, "CarkitR Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, From df339804bbfc118eaca066b95488a2dbacc2e258 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:51 +0200 Subject: [PATCH 273/367] ASoC: TWL4030: DAPM mapping of the Handsfree outputs Adds DAPM muxing, routing for the Handsfree outputs. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 08c33e9b96ce..d0612a4ca456 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -277,6 +277,30 @@ static const struct soc_enum twl4030_carkitr_enum = static const struct snd_kcontrol_new twl4030_dapm_carkitr_control = SOC_DAPM_ENUM("Route", twl4030_carkitr_enum); +/* Handsfree Left */ +static const char *twl4030_handsfreel_texts[] = + {"Voice", "DACL1", "DACL2", "DACR2"}; + +static const struct soc_enum twl4030_handsfreel_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, + ARRAY_SIZE(twl4030_handsfreel_texts), + twl4030_handsfreel_texts); + +static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = +SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); + +/* Handsfree Right */ +static const char *twl4030_handsfreer_texts[] = + {"Voice", "DACR1", "DACR2", "DACL2"}; + +static const struct soc_enum twl4030_handsfreer_enum = + SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, + ARRAY_SIZE(twl4030_handsfreer_texts), + twl4030_handsfreer_texts); + +static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = +SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); + static int outmixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -737,6 +761,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("PREDRIVER"), SND_SOC_DAPM_OUTPUT("HSOL"), SND_SOC_DAPM_OUTPUT("HSOR"), + SND_SOC_DAPM_OUTPUT("HFL"), + SND_SOC_DAPM_OUTPUT("HFR"), /* DACs */ SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", @@ -780,6 +806,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { &twl4030_dapm_carkitl_control), SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_carkitr_control), + /* HandsfreeL/R */ + SND_SOC_DAPM_MUX("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, + &twl4030_dapm_handsfreel_control), + SND_SOC_DAPM_MUX("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, + &twl4030_dapm_handsfreer_control), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), @@ -816,6 +847,14 @@ static const struct snd_soc_dapm_route intercon[] = { /* CarkitR */ {"CarkitR Mux", "DACR1", "ARXR1_APGA"}, {"CarkitR Mux", "DACR2", "ARXR2_APGA"}, + /* HandsfreeL */ + {"HandsfreeL Mux", "DACL1", "ARXL1_APGA"}, + {"HandsfreeL Mux", "DACL2", "ARXL2_APGA"}, + {"HandsfreeL Mux", "DACR2", "ARXR2_APGA"}, + /* HandsfreeR */ + {"HandsfreeR Mux", "DACR1", "ARXR1_APGA"}, + {"HandsfreeR Mux", "DACR2", "ARXR2_APGA"}, + {"HandsfreeR Mux", "DACL2", "ARXL2_APGA"}, /* outputs */ {"OUTL", NULL, "ARXL2_APGA"}, @@ -827,6 +866,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"HSOR", NULL, "HeadsetR Mux"}, {"CARKITL", NULL, "CarkitL Mux"}, {"CARKITR", NULL, "CarkitR Mux"}, + {"HFL", NULL, "HandsfreeL Mux"}, + {"HFR", NULL, "HandsfreeR Mux"}, /* inputs */ {"ADCL", NULL, "INL"}, From ca4513fe06c483bf0111c990059d42f97288605d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 9 Dec 2008 12:35:52 +0200 Subject: [PATCH 274/367] ASoC: TWL4030: Do not alter the Headset output volume on power-up/down There is a separate gain control for the Headset output already. Do not reset the gain to 0 dB at power up. In power-down, there is no need to set the Headset output gain to power-down mode, since if the CODECPDZ is in powered off this setting has no effect. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index d0612a4ca456..358aa2b1aae2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -887,7 +887,7 @@ static int twl4030_add_widgets(struct snd_soc_codec *codec) static void twl4030_power_up(struct snd_soc_codec *codec) { - u8 anamicl, regmisc1, byte, popn, hsgain; + u8 anamicl, regmisc1, byte, popn; int i = 0; /* set CODECPDZ to turn on codec */ @@ -925,10 +925,6 @@ static void twl4030_power_up(struct snd_soc_codec *codec) popn |= TWL4030_VMID_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - /* enable output stage and gain setting */ - hsgain = TWL4030_HSR_GAIN_0DB | TWL4030_HSL_GAIN_0DB; - twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain); - /* enable anti-pop ramp */ popn |= TWL4030_RAMP_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); @@ -936,17 +932,13 @@ static void twl4030_power_up(struct snd_soc_codec *codec) static void twl4030_power_down(struct snd_soc_codec *codec) { - u8 popn, hsgain; + u8 popn; /* disable anti-pop ramp */ popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); popn &= ~TWL4030_RAMP_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); - /* disable output stage and gain setting */ - hsgain = TWL4030_HSR_GAIN_PWR_DOWN | TWL4030_HSL_GAIN_PWR_DOWN; - twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain); - /* disable bias out */ popn &= ~TWL4030_VMID_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn); From c5af3a2e192d333997d1e191f3eba7fd2f869681 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 28 Nov 2008 13:29:45 +0000 Subject: [PATCH 275/367] ASoC: Add card registration API ASoC v2 allows cards, codecs and platforms to instantiate separately, with the overall ASoC device only being instantiated once all the required components have registered. As part of backporting Liam's work introduce an initial version of the card registration functions. At present these do nothing active and are internal only, they will be exposed to machine drivers after further backporting. Adding this now allows the datastructures used for dynamic card instantiation to be built up gradually. Signed-off-by: Mark Brown --- include/sound/soc.h | 5 ++++ sound/soc/soc-core.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 79d855d2bddd..4a578b5d855c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -333,6 +333,11 @@ struct snd_soc_dai_link { /* SoC card */ struct snd_soc_card { char *name; + struct device *dev; + + struct list_head list; + + int instantiated; int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2f2a8d93bbf0..44fbd71ce80f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -43,6 +43,12 @@ static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); static struct dentry *debugfs_root; #endif +static DEFINE_MUTEX(client_mutex); +static LIST_HEAD(card_list); + +static int snd_soc_register_card(struct snd_soc_card *card); +static int snd_soc_unregister_card(struct snd_soc_card *card); + /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -784,6 +790,14 @@ static int soc_probe(struct platform_device *pdev) /* Bodge while we push things out of socdev */ card->socdev = socdev; + /* Bodge while we unpick instantiation */ + card->dev = &pdev->dev; + ret = snd_soc_register_card(card); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register card\n"); + return ret; + } + if (card->probe) { ret = card->probe(pdev); if (ret < 0) @@ -863,6 +877,8 @@ static int soc_remove(struct platform_device *pdev) if (card->remove) card->remove(pdev); + snd_soc_unregister_card(card); + return 0; } @@ -1957,6 +1973,52 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); +/** + * snd_soc_register_card - Register a card with the ASoC core + * + * @param card Card to register + * + * Note that currently this is an internal only function: it will be + * exposed to machine drivers after further backporting of ASoC v2 + * registration APIs. + */ +static int snd_soc_register_card(struct snd_soc_card *card) +{ + if (!card->name || !card->dev) + return -EINVAL; + + INIT_LIST_HEAD(&card->list); + card->instantiated = 0; + + mutex_lock(&client_mutex); + list_add(&card->list, &card_list); + mutex_unlock(&client_mutex); + + dev_dbg(card->dev, "Registered card '%s'\n", card->name); + + return 0; +} + +/** + * snd_soc_unregister_card - Unregister a card with the ASoC core + * + * @param card Card to unregister + * + * Note that currently this is an internal only function: it will be + * exposed to machine drivers after further backporting of ASoC v2 + * registration APIs. + */ +static int snd_soc_unregister_card(struct snd_soc_card *card) +{ + mutex_lock(&client_mutex); + list_del(&card->list); + mutex_unlock(&client_mutex); + + dev_dbg(card->dev, "Unregistered card '%s'\n", card->name); + + return 0; +} + static int __devinit snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS From 9115171a6b79b6b4d5c6697f123556b6efc37f1f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Nov 2008 23:31:24 +0000 Subject: [PATCH 276/367] ASoC: Add DAI registration API Add API calls to register and unregister DAIs with the core. Currently these APIs are ineffective. Since multiple DAIs for a given device are a common case bulk variants are provided. Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 8 ++++ sound/soc/soc-core.c | 83 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index e2d5f76838c6..24247f763608 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -100,6 +100,12 @@ struct snd_soc_dai_ops; struct snd_soc_dai; struct snd_ac97_bus_ops; +/* Digital Audio Interface registration */ +int snd_soc_register_dai(struct snd_soc_dai *dai); +void snd_soc_unregister_dai(struct snd_soc_dai *dai); +int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count); +void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count); + /* Digital Audio Interface clocking API.*/ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir); @@ -186,6 +192,8 @@ struct snd_soc_dai { unsigned int id; int ac97_control; + struct device *dev; + /* DAI callbacks */ int (*probe)(struct platform_device *pdev, struct snd_soc_dai *dai); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 44fbd71ce80f..03460b068f1e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -45,6 +45,7 @@ static struct dentry *debugfs_root; static DEFINE_MUTEX(client_mutex); static LIST_HEAD(card_list); +static LIST_HEAD(dai_list); static int snd_soc_register_card(struct snd_soc_card *card); static int snd_soc_unregister_card(struct snd_soc_card *card); @@ -2019,6 +2020,88 @@ static int snd_soc_unregister_card(struct snd_soc_card *card) return 0; } +/** + * snd_soc_register_dai - Register a DAI with the ASoC core + * + * @param dai DAI to register + */ +int snd_soc_register_dai(struct snd_soc_dai *dai) +{ + if (!dai->name) + return -EINVAL; + + /* The device should become mandatory over time */ + if (!dai->dev) + printk(KERN_WARNING "No device for DAI %s\n", dai->name); + + INIT_LIST_HEAD(&dai->list); + + mutex_lock(&client_mutex); + list_add(&dai->list, &dai_list); + mutex_unlock(&client_mutex); + + pr_debug("Registered DAI '%s'\n", dai->name); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_register_dai); + +/** + * snd_soc_unregister_dai - Unregister a DAI from the ASoC core + * + * @param dai DAI to unregister + */ +void snd_soc_unregister_dai(struct snd_soc_dai *dai) +{ + mutex_lock(&client_mutex); + list_del(&dai->list); + mutex_unlock(&client_mutex); + + pr_debug("Unregistered DAI '%s'\n", dai->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_dai); + +/** + * snd_soc_register_dais - Register multiple DAIs with the ASoC core + * + * @param dai Array of DAIs to register + * @param count Number of DAIs + */ +int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = snd_soc_register_dai(&dai[i]); + if (ret != 0) + goto err; + } + + return 0; + +err: + for (i--; i >= 0; i--) + snd_soc_unregister_dai(&dai[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_register_dais); + +/** + * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core + * + * @param dai Array of DAIs to unregister + * @param count Number of DAIs + */ +void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count) +{ + int i; + + for (i = 0; i < count; i++) + snd_soc_unregister_dai(&dai[i]); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); + static int __devinit snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS From 3f4b783cfdebb559814690572041a17bc9744cf3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 19:26:35 +0000 Subject: [PATCH 277/367] ASoC: Register platform DAIs Register all platform DAIs with the core. In line with current behaviour this is done at module probe time rather than when the devices are probed (since currently that only happens as the entire ASoC card is registered except for those drivers that currently implement some kind of hotplug). Since the core currently ignores DAI registration this has no practical effect. Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 11 +++++++++++ sound/soc/au1x/psc-ac97.c | 3 ++- sound/soc/au1x/psc-i2s.c | 3 ++- sound/soc/blackfin/bf5xx-ac97.c | 12 ++++++++++++ sound/soc/blackfin/bf5xx-i2s.c | 12 ++++++++++++ sound/soc/davinci/davinci-i2s.c | 12 ++++++++++++ sound/soc/fsl/fsl_ssi.c | 10 ++++++++++ sound/soc/omap/omap-mcbsp.c | 13 +++++++++++++ sound/soc/pxa/pxa-ssp.c | 12 ++++++++++++ sound/soc/pxa/pxa2xx-ac97.c | 12 ++++++++++++ sound/soc/pxa/pxa2xx-i2s.c | 13 ++++++++++++- sound/soc/s3c24xx/s3c2412-i2s.c | 13 +++++++++++++ sound/soc/s3c24xx/s3c2443-ac97.c | 13 +++++++++++++ sound/soc/s3c24xx/s3c24xx-i2s.c | 12 ++++++++++++ sound/soc/sh/hac.c | 12 ++++++++++++ sound/soc/sh/ssi.c | 12 ++++++++++++ 16 files changed, 172 insertions(+), 3 deletions(-) diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index d9b874c5bf37..c9f02edd7308 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -772,6 +772,17 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { }; EXPORT_SYMBOL_GPL(atmel_ssc_dai); +static int __devinit atmel_ssc_modinit(void) +{ + return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); +} +module_init(snd_soc_init); + +static void __exit snd_soc_exit(void) +{ + snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); +} + /* Module information */ MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); MODULE_DESCRIPTION("ATMEL SSC ASoC Interface"); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index a1e824d29cf9..f0e30aec7f23 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -371,11 +371,12 @@ EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai); static int __init au1xpsc_ac97_init(void) { au1xpsc_ac97_workdata = NULL; - return 0; + return snd_soc_register_dai(&au1xpsc_ac97_dai); } static void __exit au1xpsc_ac97_exit(void) { + snd_soc_unregister_dai(&au1xpsc_ac97_dai); } module_init(au1xpsc_ac97_init); diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 16f97462ea15..f916de4400ed 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -396,11 +396,12 @@ EXPORT_SYMBOL(au1xpsc_i2s_dai); static int __init au1xpsc_i2s_init(void) { au1xpsc_i2s_workdata = NULL; - return 0; + return snd_soc_register_dai(&au1xpsc_i2s_dai); } static void __exit au1xpsc_i2s_exit(void) { + snd_soc_unregister_dai(&au1xpsc_i2s_dai); } module_init(au1xpsc_i2s_init); diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index c602ce109d52..ad3efeeb6d44 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -431,6 +431,18 @@ struct snd_soc_dai bfin_ac97_dai = { }; EXPORT_SYMBOL_GPL(bfin_ac97_dai); +static int __devinit bfin_ac97_init(void) +{ + return snd_soc_register_dai(&bfin_ac97_dai); +} +module_init(bfin_ac97_init); + +static void __exit bfin_ac97_exit(void) +{ + snd_soc_unregister_dai(&bfin_ac97_dai); +} +module_exit(bfin_ac97_exit); + MODULE_AUTHOR("Roy Huang"); MODULE_DESCRIPTION("AC97 driver for ADI Blackfin"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 9f8ce87cc6c6..0d58d2b6db6a 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -313,6 +313,18 @@ struct snd_soc_dai bf5xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); +static int __devinit bfin_i2s_init(void) +{ + return snd_soc_register_dai(&bfin_i2s_dai); +} +module_init(bfin_i2s_init); + +static void __exit bfin_i2s_exit(void) +{ + snd_soc_unregister_dai(&bfin_i2s_dai); +} +module_exit(bfin_i2s_exit); + /* Module information */ MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("I2S driver for ADI Blackfin"); diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 8b99efbc64c6..d89fc2f009ab 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -481,6 +481,18 @@ struct snd_soc_dai davinci_i2s_dai = { }; EXPORT_SYMBOL_GPL(davinci_i2s_dai); +static int __devinit davinci_i2s_init(void) +{ + return snd_soc_register_dai(&davinci_i2s_dai); +} +module_init(davinci_i2s_init); + +static void __exit davinci_i2s_exit(void) +{ + snd_soc_unregister_dai(&davinci_i2s_dai); +} +module_exit(davinci_i2s_exit); + MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 52c290bb47bf..c6d6eb71dc1d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -673,6 +673,14 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) fsl_ssi_dai->private_data = ssi_private; fsl_ssi_dai->name = ssi_private->name; fsl_ssi_dai->id = ssi_info->id; + fsl_ssi_dai->dev = ssi_info->dev; + + ret = snd_soc_register_dai(fsl_ssi_dai); + if (ret != 0) { + dev_err(ssi_info->dev, "failed to register DAI: %d\n", ret); + kfree(fsl_ssi_dai); + return NULL; + } return fsl_ssi_dai; } @@ -690,6 +698,8 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) device_remove_file(ssi_private->dev, &ssi_private->dev_attr); + snd_soc_unregister_dai(&ssi_private->cpu_dai); + kfree(ssi_private); } EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index e8f1314762d7..41cab2034163 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -499,6 +499,19 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); +static int __devinit omap_mcbsp_init(void) +{ + return snd_soc_register_dais(omap_mcbsp_dai, + ARRAY_SIZE(omap_mcbsp_dai)); +} +module_init(omap_mcbsp_init); + +static void __exit omap_mcbsp_exit(void) +{ + snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); +} +module_exit(omap_mcbsp_exit); + MODULE_AUTHOR("Jarkko Nikula "); MODULE_DESCRIPTION("OMAP I2S SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 73fa10defcca..3587f2fae5f1 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -913,6 +913,18 @@ struct snd_soc_dai pxa_ssp_dai[] = { }; EXPORT_SYMBOL_GPL(pxa_ssp_dai); +static int __devinit pxa_ssp_init(void) +{ + return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); +} +module_init(pxa_ssp_init); + +static void __exit pxa_ssp_exit(void) +{ + snd_soc_unregister_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); +} +module_exit(pxa_ssp_exit); + /* Module information */ MODULE_AUTHOR("Mark Brown "); MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 8eed80d5675d..f6249d5b492e 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -228,6 +228,18 @@ struct snd_soc_dai pxa_ac97_dai[] = { EXPORT_SYMBOL_GPL(pxa_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); +static int __devinit pxa_ac97_init(void) +{ + return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); +} +module_init(pxa_ac97_init); + +static void __exit pxa_ac97_exit(void) +{ + snd_soc_unregister_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); +} +module_exit(pxa_ac97_exit); + MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 314973ace6dc..517991fb1099 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -364,12 +364,23 @@ EXPORT_SYMBOL_GPL(pxa_i2s_dai); static int pxa2xx_i2s_probe(struct platform_device *dev) { + int ret; + clk_i2s = clk_get(&dev->dev, "I2SCLK"); - return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0; + if (IS_ERR(clk_i2s)) + return PTR_ERR(clk_i2s); + + pxa_i2s_dai.dev = &dev->dev; + ret = snd_soc_register_dai(&pxa_i2s_dai); + if (ret != 0) + clk_put(clk_i2s); + + return ret; } static int __devexit pxa2xx_i2s_remove(struct platform_device *dev) { + snd_soc_unregister_dai(&pxa_i2s_dai); clk_put(clk_i2s); clk_i2s = ERR_PTR(-ENOENT); return 0; diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 75f87c3c74d0..2cf050791562 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -736,6 +736,19 @@ struct snd_soc_dai s3c2412_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); +static int __devinit s3c2412_i2s_init(void) +{ + return snd_soc_register_dai(&s3c2412_i2s_dai); +} +module_init(s3c2412_i2s_init); + +static void __exit s3c2412_i2s_exit(void) +{ + snd_soc_unregister_dai(&s3c2412_i2s_dai); +} +module_exit(s3c2412_i2s_exit); + + /* Module information */ MODULE_AUTHOR("Ben Dooks, "); MODULE_DESCRIPTION("S3C2412 I2S SoC Interface"); diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index f0bc9b7e0840..7360c6d913bd 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -396,6 +396,19 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); +static int __devinit s3c2443_ac97_init(void) +{ + return snd_soc_register_dai(&s3c2443_ac97_dai); +} +module_init(s3c2443_ac97_init); + +static void __exit s3c2443_ac97_exit(void) +{ + snd_soc_unregister_dai(&s3c2443_ac97_dai); +} +module_exit(s3c2443_ac97_exit); + + MODULE_AUTHOR("Graeme Gregory"); MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 45fe8f7c88ab..897b1ac92cef 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -482,6 +482,18 @@ struct snd_soc_dai s3c24xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); +static int __devinit s3c24xx_i2s_init(void) +{ + return snd_soc_register_dai(&s3c24xx_i2s_dai); +} +module_init(s3c24xx_i2s_init); + +static void __exit s3c24xx_i2s_exit(void) +{ + snd_soc_unregister_dai(&s3c24xx_i2s_dai); +} +module_exit(s3c24xx_i2s_exit); + /* Module information */ MODULE_AUTHOR("Ben Dooks, "); MODULE_DESCRIPTION("s3c24xx I2S SoC Interface"); diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index c435913c60eb..9169bad1acfb 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -314,6 +314,18 @@ struct snd_soc_dai sh4_hac_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_hac_dai); +static int __devinit sh4_hac_init(void) +{ + return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); +} +module_init(sh4_hac_init); + +static void __exit sh4_hac_exit(void) +{ + snd_soc_unregister_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); +} +module_exit(sh4_hac_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver"); MODULE_AUTHOR("Manuel Lauss "); diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index fed544a3deff..9093588d4d07 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -392,6 +392,18 @@ struct snd_soc_dai sh4_ssi_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_ssi_dai); +static int __devinit sh4_ssi_init(void) +{ + return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); +} +module_init(sh4_ssi_init); + +static void __exit sh4_ssi_exit(void) +{ + snd_soc_unregister_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); +} +module_exit(sh4_ssi_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver"); MODULE_AUTHOR("Manuel Lauss "); From 12a48a8c0087ba39d926cf1d63938ccbdb9752c3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 19:40:30 +0000 Subject: [PATCH 278/367] ASoC: Add platform registration API ASoC v2 allows platform drivers to instantiate independantly of the overall ASoC card. This API allows drivers to notify the core when they are registered. Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4a578b5d855c..ce3661d07c24 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -149,6 +149,7 @@ struct snd_soc_ops; struct snd_soc_dai_mode; struct snd_soc_pcm_runtime; struct snd_soc_dai; +struct snd_soc_platform; struct snd_soc_codec; struct soc_enum; struct snd_soc_ac97_ops; @@ -158,6 +159,9 @@ typedef int (*hw_read_t)(void *,char* ,int); extern struct snd_ac97_bus_ops soc_ac97_ops; +int snd_soc_register_platform(struct snd_soc_platform *platform); +void snd_soc_unregister_platform(struct snd_soc_platform *platform); + /* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid); @@ -296,6 +300,7 @@ struct snd_soc_codec_device { /* SoC platform interface */ struct snd_soc_platform { char *name; + struct list_head list; int (*probe)(struct platform_device *pdev); int (*remove)(struct platform_device *pdev); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 03460b068f1e..ffae370b45df 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -46,6 +46,7 @@ static struct dentry *debugfs_root; static DEFINE_MUTEX(client_mutex); static LIST_HEAD(card_list); static LIST_HEAD(dai_list); +static LIST_HEAD(platform_list); static int snd_soc_register_card(struct snd_soc_card *card); static int snd_soc_unregister_card(struct snd_soc_card *card); @@ -2102,6 +2103,43 @@ void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count) } EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); +/** + * snd_soc_register_platform - Register a platform with the ASoC core + * + * @param platform platform to register + */ +int snd_soc_register_platform(struct snd_soc_platform *platform) +{ + if (!platform->name) + return -EINVAL; + + INIT_LIST_HEAD(&platform->list); + + mutex_lock(&client_mutex); + list_add(&platform->list, &platform_list); + mutex_unlock(&client_mutex); + + pr_debug("Registered platform '%s'\n", platform->name); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_register_platform); + +/** + * snd_soc_unregister_platform - Unregister a platform from the ASoC core + * + * @param platform platform to unregister + */ +void snd_soc_unregister_platform(struct snd_soc_platform *platform) +{ + mutex_lock(&client_mutex); + list_del(&platform->list); + mutex_unlock(&client_mutex); + + pr_debug("Unregistered platform '%s'\n", platform->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); + static int __devinit snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS From 958e792c7c8f06a9e666adb0ed94fff2cf90156f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 3 Dec 2008 19:58:17 +0000 Subject: [PATCH 279/367] ASoC: Register platform drivers This is done at modprobe time, mirroring current behaviour, except for mpc5200_psc_i2s where we do registration at the same time as we register with soc-of-simple. Since the core currently ignores registration this has no practical impact. Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm.c | 12 ++++++++++++ sound/soc/au1x/dbdma2.c | 3 ++- sound/soc/blackfin/bf5xx-ac97-pcm.c | 12 ++++++++++++ sound/soc/blackfin/bf5xx-i2s-pcm.c | 12 ++++++++++++ sound/soc/davinci/davinci-pcm.c | 12 ++++++++++++ sound/soc/fsl/fsl_dma.c | 12 ++++++++++++ sound/soc/fsl/mpc5200_psc_i2s.c | 4 ++++ sound/soc/omap/omap-pcm.c | 12 ++++++++++++ sound/soc/pxa/pxa2xx-pcm.c | 12 ++++++++++++ sound/soc/s3c24xx/s3c24xx-pcm.c | 12 ++++++++++++ sound/soc/sh/dma-sh7760.c | 12 ++++++++++++ 11 files changed, 114 insertions(+), 1 deletion(-) diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 8507aa1cd811..d6bcb4e6fda0 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -477,6 +477,18 @@ struct snd_soc_platform atmel_soc_platform = { }; EXPORT_SYMBOL_GPL(atmel_soc_platform); +static int __devinit atmel_pcm_modinit(void) +{ + return snd_soc_register_platform(&atmel_soc_platform); +} +module_init(atmel_pcm_modinit); + +static void __exit atmel_pcm_exit(void) +{ + snd_soc_unregister_platform(&atmel_soc_platform); +} +module_exit(atmel_pcm_modexit); + MODULE_AUTHOR("Sedji Gaouaou "); MODULE_DESCRIPTION("Atmel PCM module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 1466d9328800..74c823d60f91 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -406,11 +406,12 @@ static int __init au1xpsc_audio_dbdma_init(void) { au1xpsc_audio_pcmdma[PCM_TX] = NULL; au1xpsc_audio_pcmdma[PCM_RX] = NULL; - return 0; + return snd_soc_register_platform(&au1xpsc_soc_platform); } static void __exit au1xpsc_audio_dbdma_exit(void) { + snd_soc_unregister_platform(&au1xpsc_soc_platform); } module_init(au1xpsc_audio_dbdma_init); diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index d3d51bcb4569..5b27e0d9d0ec 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -451,6 +451,18 @@ struct snd_soc_platform bf5xx_ac97_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform); +static int __devinit bfin_ac97_init(void) +{ + return snd_soc_register_platform(&bf5xx_ac97_soc_platform); +} +module_init(bfin_ac97_init); + +static void __exit bfin_ac97_exit(void) +{ + snd_soc_unregister_platform(&bf5xx_ac97_soc_platform); +} +module_exit(bfin_ac97_exit); + MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 61fccf925192..c58b12a44870 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -283,6 +283,18 @@ struct snd_soc_platform bf5xx_i2s_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform); +static int __devinit bfin_i2s_init(void) +{ + return snd_soc_register_platform(&bf5xx_i2s_soc_platform); +} +module_init(bfin_i2s_init); + +static void __exit bfin_i2s_exit(void) +{ + snd_soc_unregister_platform(&bf5xx_i2s_soc_platform); +} +module_exit(bfin_i2s_exit); + MODULE_AUTHOR("Cliff Cai"); MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 76feaa657375..f1b6e02d24ed 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -384,6 +384,18 @@ struct snd_soc_platform davinci_soc_platform = { }; EXPORT_SYMBOL_GPL(davinci_soc_platform); +static int __devinit davinci_soc_platform_init(void) +{ + return snd_soc_register_platform(&davinci_soc_platform); +} +module_init(davinci_soc_platform_init); + +static void __exit davinci_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&davinci_soc_platform); +} +module_exit(davinci_soc_platform_exit); + MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index bf92331b4768..646c807163ab 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -853,6 +853,18 @@ int fsl_dma_configure(struct fsl_dma_info *dma_info) } EXPORT_SYMBOL_GPL(fsl_dma_configure); +static int __devinit fsl_soc_platform_init(void) +{ + return snd_soc_register_platform(&fsl_soc_platform); +} +module_init(fsl_soc_platform_init); + +static void __exit fsl_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&fsl_soc_platform); +} +module_exit(fsl_soc_platform_exit); + MODULE_AUTHOR("Timur Tabi "); MODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 9ad8f9a2d8e9..9eb1ce185bd0 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -828,6 +828,8 @@ static int __devinit psc_i2s_of_probe(struct of_device *op, if (rc) dev_info(psc_i2s->dev, "error creating sysfs files\n"); + snd_soc_register_platform(&psc_i2s_pcm_soc_platform); + /* Tell the ASoC OF helpers about it */ of_snd_soc_register_platform(&psc_i2s_pcm_soc_platform, op->node, &psc_i2s->dai); @@ -841,6 +843,8 @@ static int __devexit psc_i2s_of_remove(struct of_device *op) dev_dbg(&op->dev, "psc_i2s_remove()\n"); + snd_soc_unregister_platform(&psc_i2s_pcm_soc_platform); + bcom_gen_bd_rx_release(psc_i2s->capture.bcom_task); bcom_gen_bd_tx_release(psc_i2s->playback.bcom_task); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index e9084fdd2082..9940de296316 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -354,6 +354,18 @@ struct snd_soc_platform omap_soc_platform = { }; EXPORT_SYMBOL_GPL(omap_soc_platform); +static int __devinit omap_soc_platform_init(void) +{ + return snd_soc_register_platform(&omap_soc_platform); +} +module_init(omap_soc_platform_init); + +static void __exit omap_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&omap_soc_platform); +} +module_exit(omap_soc_platform_exit); + MODULE_AUTHOR("Jarkko Nikula "); MODULE_DESCRIPTION("OMAP PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 0f6b7bb2d44b..4fa1578f5d47 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -118,6 +118,18 @@ struct snd_soc_platform pxa2xx_soc_platform = { }; EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); +static int __devinit pxa2xx_soc_platform_init(void) +{ + return snd_soc_register_platform(&pxa2xx_soc_platform); +} +module_init(pxa2xx_soc_platform_init); + +static void __exit pxa2xx_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&pxa2xx_soc_platform); +} +module_exit(pxa2xx_soc_platform_exit); + MODULE_AUTHOR("Nicolas Pitre"); MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index e13e614bada9..ea5a9caec13e 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -465,6 +465,18 @@ struct snd_soc_platform s3c24xx_soc_platform = { }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); +static int __devinit s3c24xx_soc_platform_init(void) +{ + return snd_soc_register_platform(&s3c24xx_soc_platform); +} +module_init(s3c24xx_soc_platform_init); + +static void __exit s3c24xx_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&s3c24xx_soc_platform); +} +module_exit(s3c24xx_soc_platform_exit); + MODULE_AUTHOR("Ben Dooks, "); MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 9faa12622d09..39ffca0933a2 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -348,6 +348,18 @@ struct snd_soc_platform sh7760_soc_platform = { }; EXPORT_SYMBOL_GPL(sh7760_soc_platform); +static int __devinit sh7760_soc_platform_init(void) +{ + return snd_soc_register_platform(&sh7760_soc_platform); +} +module_init(sh7760_soc_platform_init); + +static void __exit sh7760_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&sh7760_soc_platform); +} +module_exit(sh7760_soc_platform_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver"); MODULE_AUTHOR("Manuel Lauss "); From 64089b84abfe2f26a864ebd968429302dcb071de Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 8 Dec 2008 19:17:58 +0000 Subject: [PATCH 280/367] ASoC: Register non-AC97 codec DAIs Currently this is done at module probe time since ASoC ties in codec device probe to the instantiation of the entire ASoC device. Subsequent patches will refactor the codec drivers to handle probing separately. Note that the core does not yet use this information. AC97 is special since the codec is controlled over the AC97 link but we want to give the machine driver a chance to set up the system before trying to instantiate since it may need to do configuration before the AC97 link will operate Signed-off-by: Mark Brown --- sound/soc/codecs/ad73311.c | 12 ++++++++++++ sound/soc/codecs/ak4535.c | 12 ++++++++++++ sound/soc/codecs/cs4270.c | 12 ++++++++++++ sound/soc/codecs/pcm3008.c | 12 ++++++++++++ sound/soc/codecs/ssm2602.c | 12 ++++++++++++ sound/soc/codecs/tlv320aic23.c | 12 ++++++++++++ sound/soc/codecs/tlv320aic26.c | 15 ++++++++++++--- sound/soc/codecs/tlv320aic3x.c | 12 ++++++++++++ sound/soc/codecs/twl4030.c | 14 +++++++++++++- sound/soc/codecs/uda134x.c | 12 ++++++++++++ sound/soc/codecs/uda1380.c | 12 ++++++++++++ sound/soc/codecs/wm8510.c | 12 ++++++++++++ sound/soc/codecs/wm8580.c | 12 ++++++++++++ sound/soc/codecs/wm8728.c | 12 ++++++++++++ sound/soc/codecs/wm8731.c | 12 ++++++++++++ sound/soc/codecs/wm8750.c | 12 ++++++++++++ sound/soc/codecs/wm8753.c | 12 ++++++++++++ sound/soc/codecs/wm8900.c | 12 ++++++++++++ sound/soc/codecs/wm8903.c | 12 ++++++++++++ sound/soc/codecs/wm8971.c | 12 ++++++++++++ sound/soc/codecs/wm8990.c | 12 ++++++++++++ 21 files changed, 253 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 500f9f3363d1..e32f55034e64 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -98,6 +98,18 @@ struct snd_soc_codec_device soc_codec_dev_ad73311 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311); +static int __devinit ad73311_init(void) +{ + return snd_soc_register_dai(&ad73311_dai); +} +module_init(ad73311_init); + +static void __exit ad73311_exit(void) +{ + snd_soc_unregister_dai(&ad73311_dai); +} +module_exit(ad73311_exit); + MODULE_DESCRIPTION("ASoC ad73311 driver"); MODULE_AUTHOR("Cliff Cai "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 23062c952e85..94148fba9119 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -688,6 +688,18 @@ struct snd_soc_codec_device soc_codec_dev_ak4535 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); +static int __devinit ak4535_modinit(void) +{ + return snd_soc_register_dai(&ak4535_dai); +} +module_init(ak4535_modinit); + +static void __exit ak4535_exit(void) +{ + snd_soc_unregister_dai(&ak4535_dai); +} +module_exit(ak4535_exit); + MODULE_DESCRIPTION("Soc AK4535 driver"); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 4667a07b566c..73aaf249d782 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -774,6 +774,18 @@ struct snd_soc_codec_device soc_codec_device_cs4270 = { }; EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); +static int __devinit cs4270_init(void) +{ + return snd_soc_register_dai(&cs4270_dai); +} +module_init(cs4270_init); + +static void __exit cs4270_exit(void) +{ + snd_soc_unregister_dai(&cs4270_dai); +} +module_exit(cs4270_exit); + MODULE_AUTHOR("Timur Tabi "); MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index a5862555b444..f333e88ee255 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -195,6 +195,18 @@ struct snd_soc_codec_device soc_codec_dev_pcm3008 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008); +static int __devinit pcm3008_init(void) +{ + return snd_soc_register_dai(&pcm3008_dai); +} +module_init(pcm3008_init); + +static void __exit pcm3008_exit(void) +{ + snd_soc_unregister_dai(&pcm3008_dai); +} +module_exit(pcm3008_exit); + MODULE_DESCRIPTION("Soc PCM3008 driver"); MODULE_AUTHOR("Hugo Villeneuve"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 973844973fe1..77fdcb4b9a1b 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -793,6 +793,18 @@ struct snd_soc_codec_device soc_codec_dev_ssm2602 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); +static int __devinit ssm2602_modinit(void) +{ + return snd_soc_register_dai(&ssm2602_dai); +} +module_init(ssm2602_modinit); + +static void __exit ssm2602_exit(void) +{ + snd_soc_unregister_dai(&ssm2602_dai); +} +module_exit(ssm2602_exit); + MODULE_DESCRIPTION("ASoC ssm2602 driver"); MODULE_AUTHOR("Cliff Cai"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index d209bec02a69..eac449b92bd5 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -847,6 +847,18 @@ struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); +static int __devinit tlv320aic23_modinit(void) +{ + return snd_soc_register_dai(&tlv320aic23_dai); +} +module_init(tlv320aic23_modinit); + +static void __exit tlv320aic23_exit(void) +{ + snd_soc_unregister_dai(&tlv320aic23_dai); +} +module_exit(tlv320aic23_exit); + MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); MODULE_AUTHOR("Arun KS "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index e33fb7e00d1e..29f2f1a017fd 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c @@ -426,7 +426,7 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set); static int aic26_spi_probe(struct spi_device *spi) { struct aic26 *aic26; - int rc, i, reg; + int ret, i, reg; dev_dbg(&spi->dev, "probing tlv320aic26 spi device\n"); @@ -456,6 +456,14 @@ static int aic26_spi_probe(struct spi_device *spi) aic26->codec.reg_cache_size = AIC26_NUM_REGS; aic26->codec.reg_cache = aic26->reg_cache; + aic26_dai.dev = &spi->dev; + ret = snd_soc_register_dai(&aic26_dai); + if (ret != 0) { + dev_err(&spi->dev, "Failed to register DAI: %d\n", ret); + kfree(aic26); + return ret; + } + /* Reset the codec to power on defaults */ aic26_reg_write(&aic26->codec, AIC26_REG_RESET, 0xBB00); @@ -474,8 +482,8 @@ static int aic26_spi_probe(struct spi_device *spi) /* Register the sysfs files for debugging */ /* Create SysFS files */ - rc = device_create_file(&spi->dev, &dev_attr_keyclick); - if (rc) + ret = device_create_file(&spi->dev, &dev_attr_keyclick); + if (ret) dev_info(&spi->dev, "error creating sysfs files\n"); #if defined(CONFIG_SND_SOC_OF_SIMPLE) @@ -492,6 +500,7 @@ static int aic26_spi_remove(struct spi_device *spi) { struct aic26 *aic26 = dev_get_drvdata(&spi->dev); + snd_soc_unregister_dai(&aic26_dai); kfree(aic26); return 0; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6a058298a3c3..ccd575961869 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1411,6 +1411,18 @@ struct snd_soc_codec_device soc_codec_dev_aic3x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); +static int __devinit aic3x_modinit(void) +{ + return snd_soc_register_dai(&aic3x_dai); +} +module_init(aic3x_modinit); + +static void __exit aic3x_exit(void) +{ + snd_soc_unregister_dai(&aic3x_dai); +} +module_exit(aic3x_exit); + MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver"); MODULE_AUTHOR("Vladimir Barinov"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 358aa2b1aae2..373daa486cea 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -358,7 +358,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, .put = snd_soc_put_volsw_r2_twl4030, \ .private_value = (unsigned long)&(struct soc_mixer_control) \ {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ - .max = xmax, .invert = xinvert} } + .rshift = xshift, .max = xmax, .invert = xinvert} } #define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \ SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \ xinvert, tlv_array) @@ -1275,6 +1275,18 @@ struct snd_soc_codec_device soc_codec_dev_twl4030 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); +static int __devinit twl4030_init(void) +{ + return snd_soc_register_dai(&twl4030_dai); +} +module_init(twl4030_init); + +static void __exit twl4030_exit(void) +{ + snd_soc_unregister_dai(&twl4030_dai); +} +module_exit(twl4030_exit); + MODULE_DESCRIPTION("ASoC TWL4030 codec driver"); MODULE_AUTHOR("Steve Sakoman"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 58de749185e6..8e035b5d733f 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -651,6 +651,18 @@ struct snd_soc_codec_device soc_codec_dev_uda134x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); +static int __devinit uda134x_init(void) +{ + return snd_soc_register_dai(&uda134x_dai); +} +module_init(uda134x_init); + +static void __exit uda134x_exit(void) +{ + snd_soc_unregister_dai(&uda134x_dai); +} +module_exit(uda134x_exit); + MODULE_DESCRIPTION("UDA134X ALSA soc codec driver"); MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 42491650593f..55a99b6a68a1 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -841,6 +841,18 @@ struct snd_soc_codec_device soc_codec_dev_uda1380 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); +static int __devinit uda1380_modinit(void) +{ + return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); +} +module_init(uda1380_modinit); + +static void __exit uda1380_exit(void) +{ + snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); +} +module_exit(uda1380_exit); + MODULE_AUTHOR("Giorgio Padrin"); MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 126c70f749d1..a2af04bb4e9f 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -889,6 +889,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8510 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); +static int __devinit wm8510_modinit(void) +{ + return snd_soc_register_dai(&wm8510_dai); +} +module_init(wm8510_modinit); + +static void __exit wm8510_exit(void) +{ + snd_soc_unregister_dai(&wm8510_dai); +} +module_exit(wm8510_exit); + MODULE_DESCRIPTION("ASoC WM8510 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 572a31de3219..391ec2978aed 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1042,6 +1042,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); +static int __devinit wm8580_modinit(void) +{ + return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); +} +module_init(wm8580_modinit); + +static void __exit wm8580_exit(void) +{ + snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); +} +module_exit(wm8580_exit); + MODULE_DESCRIPTION("ASoC WM8580 driver"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 28f12c6a6ac8..d905e25b1a93 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -568,6 +568,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8728 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); +static int __devinit wm8728_modinit(void) +{ + return snd_soc_register_dai(&wm8728_dai); +} +module_init(wm8728_modinit); + +static void __exit wm8728_exit(void) +{ + snd_soc_unregister_dai(&wm8728_dai); +} +module_exit(wm8728_exit); + MODULE_DESCRIPTION("ASoC WM8728 driver"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 403dea13b5d9..7b455a60d719 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -793,6 +793,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); +static int __devinit wm8731_modinit(void) +{ + return snd_soc_register_dai(&wm8731_dai); +} +module_init(wm8731_modinit); + +static void __exit wm8731_exit(void) +{ + snd_soc_unregister_dai(&wm8731_dai); +} +module_exit(wm8731_exit); + MODULE_DESCRIPTION("ASoC WM8731 driver"); MODULE_AUTHOR("Richard Purdie"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 979446f5c983..84a6307de907 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -1085,6 +1085,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8750 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); +static int __devinit wm8750_modinit(void) +{ + return snd_soc_register_dai(&wm8750_dai); +} +module_init(wm8750_modinit); + +static void __exit wm8750_exit(void) +{ + snd_soc_unregister_dai(&wm8750_dai); +} +module_exit(wm8750_exit); + MODULE_DESCRIPTION("ASoC WM8750 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 96c0453fffb3..1caca30d0812 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1874,6 +1874,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8753 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); +static int __devinit wm8753_modinit(void) +{ + return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); +} +module_init(wm8753_modinit); + +static void __exit wm8753_exit(void) +{ + snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); +} +module_exit(wm8753_exit); + MODULE_DESCRIPTION("ASoC WM8753 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 29cd83991c5b..02bb1c999ba1 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1530,6 +1530,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8900 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); +static int __devinit wm8900_modinit(void) +{ + return snd_soc_register_dai(&wm8900_dai); +} +module_init(wm8900_modinit); + +static void __exit wm8900_exit(void) +{ + snd_soc_unregister_dai(&wm8900_dai); +} +module_exit(wm8900_exit); + MODULE_DESCRIPTION("ASoC WM8900 driver"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 3c83b7973074..5d8fe7e1571e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1809,6 +1809,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8903 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); +static int __devinit wm8903_modinit(void) +{ + return snd_soc_register_dai(&wm8903_dai); +} +module_init(wm8903_modinit); + +static void __exit wm8903_exit(void) +{ + snd_soc_unregister_dai(&wm8903_dai); +} +module_exit(wm8903_exit); + MODULE_DESCRIPTION("ASoC WM8903 driver"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 53e6937e9ba1..2979fc4f44f1 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -935,6 +935,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8971 = { EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); +static int __devinit wm8971_modinit(void) +{ + return snd_soc_register_dai(&wm8971_dai); +} +module_init(wm8971_modinit); + +static void __exit wm8971_exit(void) +{ + snd_soc_unregister_dai(&wm8971_dai); +} +module_exit(wm8971_exit); + MODULE_DESCRIPTION("ASoC WM8971 driver"); MODULE_AUTHOR("Lab126"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 5c5128b6b453..53e71aafe6c6 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1643,6 +1643,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8990 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); +static int __devinit wm8990_modinit(void) +{ + return snd_soc_register_dai(&wm8990_dai); +} +module_init(wm8990_modinit); + +static void __exit wm8990_exit(void) +{ + snd_soc_unregister_dai(&wm8990_dai); +} +module_exit(wm8990_exit); + MODULE_DESCRIPTION("ASoC WM8990 driver"); MODULE_AUTHOR("Liam Girdwood"); MODULE_LICENSE("GPL"); From 435c5e2588893e3f7aba0bd4de67991bf00b3c9d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 4 Dec 2008 15:32:53 +0000 Subject: [PATCH 281/367] ASoC: Initial framework for dynamic card instantiation Use the lists of platforms, platform DAIs and cards to check to see that everything has registered. Since relationships are still specified by direct references to the structures in the drivers and the drivers all register everything at modprobe there should be no practical effect yet. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 95 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ffae370b45df..717db0e6499b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -780,30 +780,54 @@ static int soc_resume(struct platform_device *pdev) #define soc_resume NULL #endif -/* probes a new socdev */ -static int soc_probe(struct platform_device *pdev) +static void snd_soc_instantiate_card(struct snd_soc_card *card) { - int ret = 0, i; - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_card *card = socdev->card; - struct snd_soc_platform *platform = card->platform; - struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + struct platform_device *pdev = container_of(card->dev, + struct platform_device, + dev); + struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev; + struct snd_soc_platform *platform; + struct snd_soc_dai *dai; + int i, found, ret; - /* Bodge while we push things out of socdev */ - card->socdev = socdev; + if (card->instantiated) + return; - /* Bodge while we unpick instantiation */ - card->dev = &pdev->dev; - ret = snd_soc_register_card(card); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to register card\n"); - return ret; + found = 0; + list_for_each_entry(platform, &platform_list, list) + if (card->platform == platform) { + found = 1; + break; + } + if (!found) { + dev_dbg(card->dev, "Platform %s not registered\n", + card->platform->name); + return; } + for (i = 0; i < card->num_links; i++) { + found = 0; + list_for_each_entry(dai, &dai_list, list) + if (card->dai_link[i].cpu_dai == dai) { + found = 1; + break; + } + if (!found) { + dev_dbg(card->dev, "DAI %s not registered\n", + card->dai_link[i].cpu_dai->name); + return; + } + } + + /* Note that we do not current check for codec components */ + + dev_dbg(card->dev, "All components present, instantiating\n"); + + /* Found everything, bring it up */ if (card->probe) { ret = card->probe(pdev); if (ret < 0) - return ret; + return; } for (i = 0; i < card->num_links; i++) { @@ -834,7 +858,9 @@ static int soc_probe(struct platform_device *pdev) INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); #endif - return 0; + card->instantiated = 1; + + return; platform_err: if (codec_dev->remove) @@ -849,8 +875,38 @@ cpu_dai_err: if (card->remove) card->remove(pdev); +} - return ret; +/* + * Attempt to initialise any uninitalised cards. Must be called with + * client_mutex. + */ +static void snd_soc_instantiate_cards(void) +{ + struct snd_soc_card *card; + list_for_each_entry(card, &card_list, list) + snd_soc_instantiate_card(card); +} + +/* probes a new socdev */ +static int soc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_card *card = socdev->card; + + /* Bodge while we push things out of socdev */ + card->socdev = socdev; + + /* Bodge while we unpick instantiation */ + card->dev = &pdev->dev; + ret = snd_soc_register_card(card); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to register card\n"); + return ret; + } + + return 0; } /* removes a socdev */ @@ -1994,6 +2050,7 @@ static int snd_soc_register_card(struct snd_soc_card *card) mutex_lock(&client_mutex); list_add(&card->list, &card_list); + snd_soc_instantiate_cards(); mutex_unlock(&client_mutex); dev_dbg(card->dev, "Registered card '%s'\n", card->name); @@ -2039,6 +2096,7 @@ int snd_soc_register_dai(struct snd_soc_dai *dai) mutex_lock(&client_mutex); list_add(&dai->list, &dai_list); + snd_soc_instantiate_cards(); mutex_unlock(&client_mutex); pr_debug("Registered DAI '%s'\n", dai->name); @@ -2117,6 +2175,7 @@ int snd_soc_register_platform(struct snd_soc_platform *platform) mutex_lock(&client_mutex); list_add(&platform->list, &platform_list); + snd_soc_instantiate_cards(); mutex_unlock(&client_mutex); pr_debug("Registered platform '%s'\n", platform->name); From 6b05eda6383d89bffc21da654d148733e7839540 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 8 Dec 2008 19:26:48 +0000 Subject: [PATCH 282/367] ASoC: Wait for non-AC97 codec DAIs before instantiating This will allow codec drivers to be refactored to allow them to be registered out of line with the ASoC device registration. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 717db0e6499b..76a89eb65baf 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -788,7 +788,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev; struct snd_soc_platform *platform; struct snd_soc_dai *dai; - int i, found, ret; + int i, found, ret, ac97; if (card->instantiated) return; @@ -805,6 +805,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) return; } + ac97 = 0; for (i = 0; i < card->num_links; i++) { found = 0; list_for_each_entry(dai, &dai_list, list) @@ -817,8 +818,32 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) card->dai_link[i].cpu_dai->name); return; } + + if (card->dai_link[i].cpu_dai->ac97_control) + ac97 = 1; } + /* If we have AC97 in the system then don't wait for the + * codec. This will need revisiting if we have to handle + * systems with mixed AC97 and non-AC97 parts. Only check for + * DAIs currently; we can't do this per link since some AC97 + * codecs have non-AC97 DAIs. + */ + if (!ac97) + for (i = 0; i < card->num_links; i++) { + found = 0; + list_for_each_entry(dai, &dai_list, list) + if (card->dai_link[i].codec_dai == dai) { + found = 1; + break; + } + if (!found) { + dev_dbg(card->dev, "DAI %s not registered\n", + card->dai_link[i].codec_dai->name); + return; + } + } + /* Note that we do not current check for codec components */ dev_dbg(card->dev, "All components present, instantiating\n"); From f0752331b89ce79063f765545dd7dd5f49d9a713 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Dec 2008 12:51:56 +0000 Subject: [PATCH 283/367] ASoC: Convert WM8900 to allow registration by machine code This makes use of the support for delayed DAI registration to allow the WM8900 I2C device to be registered by general platform/architecture code rather than as part of the ASoC device probe. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8900.c | 97 ++++++++------------------------------- 1 file changed, 20 insertions(+), 77 deletions(-) diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 02bb1c999ba1..34e58af0c65a 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1382,32 +1382,21 @@ priv_err: return ret; } -static struct snd_soc_device *wm8900_socdev; +static struct i2c_client *wm8900_client; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ static int wm8900_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct snd_soc_device *socdev = wm8900_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; - - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = wm8900_init(socdev); - if (ret < 0) - dev_err(&i2c->dev, "failed to initialise WM8900\n"); - return ret; + wm8900_client = i2c; + wm8900_dai.dev = &i2c->dev; + return snd_soc_register_dai(&wm8900_dai); } static int wm8900_i2c_remove(struct i2c_client *client) { - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); + snd_soc_unregister_dai(&wm8900_dai); + wm8900_dai.dev = NULL; + wm8900_client = NULL; return 0; } @@ -1427,57 +1416,17 @@ static struct i2c_driver wm8900_i2c_driver = { .id_table = wm8900_i2c_id, }; -static int wm8900_add_i2c_device(struct platform_device *pdev, - const struct wm8900_setup_data *setup) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - int ret; - - ret = i2c_add_driver(&wm8900_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "wm8900", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; - -err_driver: - i2c_del_driver(&wm8900_i2c_driver); - return -ENODEV; -} -#endif - static int wm8900_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8900_setup_data *setup; struct snd_soc_codec *codec; int ret = 0; - dev_info(&pdev->dev, "WM8900 Audio Codec\n"); + if (!wm8900_client) { + dev_err(&pdev->dev, "I2C client not yet instantiated\n"); + return -ENODEV; + } - setup = socdev->codec_data; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; @@ -1490,15 +1439,13 @@ static int wm8900_probe(struct platform_device *pdev) codec->set_bias_level = wm8900_set_bias_level; - wm8900_socdev = socdev; -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; - ret = wm8900_add_i2c_device(pdev, setup); - } -#else -#error Non-I2C interfaces not yet supported -#endif + codec->hw_write = (hw_write_t)i2c_master_send; + codec->control_data = wm8900_client; + + ret = wm8900_init(socdev); + if (ret != 0) + kfree(codec); + return ret; } @@ -1513,10 +1460,6 @@ static int wm8900_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); - i2c_del_driver(&wm8900_i2c_driver); -#endif kfree(codec); return 0; @@ -1532,13 +1475,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); static int __devinit wm8900_modinit(void) { - return snd_soc_register_dai(&wm8900_dai); + return i2c_add_driver(&wm8900_i2c_driver); } module_init(wm8900_modinit); static void __exit wm8900_exit(void) { - snd_soc_unregister_dai(&wm8900_dai); + i2c_del_driver(&wm8900_i2c_driver); } module_exit(wm8900_exit); From 471716f7ea646487b7b5c7b3efc68a023b05a933 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Dec 2008 14:47:07 +0000 Subject: [PATCH 284/367] ASoC: Fix typos in Atmel module registration I wish I had boards which work with unmodified kernels :/ Signed-off-by: Mark Brown --- sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index d6bcb4e6fda0..027eb13f9dd0 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -483,7 +483,7 @@ static int __devinit atmel_pcm_modinit(void) } module_init(atmel_pcm_modinit); -static void __exit atmel_pcm_exit(void) +static void __exit atmel_pcm_modexit(void) { snd_soc_unregister_platform(&atmel_soc_platform); } diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index c9f02edd7308..87904b6ab8c2 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -776,12 +776,13 @@ static int __devinit atmel_ssc_modinit(void) { return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); } -module_init(snd_soc_init); +module_init(atmel_ssc_modinit); -static void __exit snd_soc_exit(void) +static void __exit atmel_ssc_modexit(void) { snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); } +module_exit(atmel_ssc_modexit); /* Module information */ MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com"); From 24e07db8cceb7dfe2d4005e4450a27f4bcda6499 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 07:40:24 +0100 Subject: [PATCH 285/367] ALSA: ASoC - Fix module init entry for twl4030.c Fixed the function name of module init entry for twl4030.c, which conflicted with the existing hardware init function: sound/soc/codecs/twl4030.c:1278: error: conflicting types for 'twl4030_init' sound/soc/codecs/twl4030.c:1187: error: previous definition of 'twl4030_init' was here Also fixed the section type of init function. Signed-off-by: Takashi Iwai --- sound/soc/codecs/twl4030.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 373daa486cea..71ab5342bea5 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -1275,11 +1275,11 @@ struct snd_soc_codec_device soc_codec_dev_twl4030 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030); -static int __devinit twl4030_init(void) +static int __init twl4030_modinit(void) { return snd_soc_register_dai(&twl4030_dai); } -module_init(twl4030_init); +module_init(twl4030_modinit); static void __exit twl4030_exit(void) { From c9b3a40ff2b3dea9914e36965a17c802650bb603 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 07:47:22 +0100 Subject: [PATCH 286/367] ALSA: ASoC - Fix wrong section types The module init entries should be __init instead of __devinit. Signed-off-by: Takashi Iwai --- sound/soc/atmel/atmel-pcm.c | 2 +- sound/soc/atmel/atmel_ssc_dai.c | 2 +- sound/soc/blackfin/bf5xx-ac97-pcm.c | 2 +- sound/soc/blackfin/bf5xx-ac97.c | 2 +- sound/soc/blackfin/bf5xx-i2s-pcm.c | 2 +- sound/soc/blackfin/bf5xx-i2s.c | 2 +- sound/soc/codecs/ad73311.c | 2 +- sound/soc/codecs/ak4535.c | 2 +- sound/soc/codecs/cs4270.c | 2 +- sound/soc/codecs/pcm3008.c | 2 +- sound/soc/codecs/ssm2602.c | 2 +- sound/soc/codecs/tlv320aic23.c | 2 +- sound/soc/codecs/tlv320aic3x.c | 2 +- sound/soc/codecs/uda134x.c | 2 +- sound/soc/codecs/uda1380.c | 2 +- sound/soc/codecs/wm8510.c | 2 +- sound/soc/codecs/wm8580.c | 2 +- sound/soc/codecs/wm8728.c | 2 +- sound/soc/codecs/wm8731.c | 2 +- sound/soc/codecs/wm8750.c | 2 +- sound/soc/codecs/wm8753.c | 2 +- sound/soc/codecs/wm8900.c | 2 +- sound/soc/codecs/wm8903.c | 2 +- sound/soc/codecs/wm8971.c | 2 +- sound/soc/codecs/wm8990.c | 2 +- sound/soc/davinci/davinci-i2s.c | 2 +- sound/soc/davinci/davinci-pcm.c | 2 +- sound/soc/fsl/fsl_dma.c | 2 +- sound/soc/omap/omap-mcbsp.c | 2 +- sound/soc/omap/omap-pcm.c | 2 +- sound/soc/pxa/pxa-ssp.c | 2 +- sound/soc/pxa/pxa2xx-ac97.c | 2 +- sound/soc/pxa/pxa2xx-pcm.c | 2 +- sound/soc/s3c24xx/s3c2412-i2s.c | 2 +- sound/soc/s3c24xx/s3c2443-ac97.c | 2 +- sound/soc/s3c24xx/s3c24xx-i2s.c | 2 +- sound/soc/s3c24xx/s3c24xx-pcm.c | 2 +- sound/soc/sh/dma-sh7760.c | 2 +- sound/soc/sh/hac.c | 2 +- sound/soc/sh/ssi.c | 2 +- sound/soc/soc-core.c | 2 +- 41 files changed, 41 insertions(+), 41 deletions(-) diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 027eb13f9dd0..1fac5efd285b 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c @@ -477,7 +477,7 @@ struct snd_soc_platform atmel_soc_platform = { }; EXPORT_SYMBOL_GPL(atmel_soc_platform); -static int __devinit atmel_pcm_modinit(void) +static int __init atmel_pcm_modinit(void) { return snd_soc_register_platform(&atmel_soc_platform); } diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 87904b6ab8c2..c5d67900d666 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -772,7 +772,7 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = { }; EXPORT_SYMBOL_GPL(atmel_ssc_dai); -static int __devinit atmel_ssc_modinit(void) +static int __init atmel_ssc_modinit(void) { return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai)); } diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 5b27e0d9d0ec..8067cfafa3a7 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -451,7 +451,7 @@ struct snd_soc_platform bf5xx_ac97_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform); -static int __devinit bfin_ac97_init(void) +static int __init bfin_ac97_init(void) { return snd_soc_register_platform(&bf5xx_ac97_soc_platform); } diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index ad3efeeb6d44..3be2be60576d 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -431,7 +431,7 @@ struct snd_soc_dai bfin_ac97_dai = { }; EXPORT_SYMBOL_GPL(bfin_ac97_dai); -static int __devinit bfin_ac97_init(void) +static int __init bfin_ac97_init(void) { return snd_soc_register_dai(&bfin_ac97_dai); } diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index c58b12a44870..53d290b3ea47 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -283,7 +283,7 @@ struct snd_soc_platform bf5xx_i2s_soc_platform = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform); -static int __devinit bfin_i2s_init(void) +static int __init bfin_i2s_init(void) { return snd_soc_register_platform(&bf5xx_i2s_soc_platform); } diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 0d58d2b6db6a..c17b131f6626 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -313,7 +313,7 @@ struct snd_soc_dai bf5xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); -static int __devinit bfin_i2s_init(void) +static int __init bfin_i2s_init(void) { return snd_soc_register_dai(&bfin_i2s_dai); } diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index e32f55034e64..b09289a1e55a 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -98,7 +98,7 @@ struct snd_soc_codec_device soc_codec_dev_ad73311 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311); -static int __devinit ad73311_init(void) +static int __init ad73311_init(void) { return snd_soc_register_dai(&ad73311_dai); } diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 94148fba9119..81300d8d42ca 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -688,7 +688,7 @@ struct snd_soc_codec_device soc_codec_dev_ak4535 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535); -static int __devinit ak4535_modinit(void) +static int __init ak4535_modinit(void) { return snd_soc_register_dai(&ak4535_dai); } diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 73aaf249d782..f1aa0c34421c 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -774,7 +774,7 @@ struct snd_soc_codec_device soc_codec_device_cs4270 = { }; EXPORT_SYMBOL_GPL(soc_codec_device_cs4270); -static int __devinit cs4270_init(void) +static int __init cs4270_init(void) { return snd_soc_register_dai(&cs4270_dai); } diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index f333e88ee255..9a3e67e5319c 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -195,7 +195,7 @@ struct snd_soc_codec_device soc_codec_dev_pcm3008 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_pcm3008); -static int __devinit pcm3008_init(void) +static int __init pcm3008_init(void) { return snd_soc_register_dai(&pcm3008_dai); } diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 77fdcb4b9a1b..2325aefea411 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -793,7 +793,7 @@ struct snd_soc_codec_device soc_codec_dev_ssm2602 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_ssm2602); -static int __devinit ssm2602_modinit(void) +static int __init ssm2602_modinit(void) { return snd_soc_register_dai(&ssm2602_dai); } diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index eac449b92bd5..39f5b981d25a 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -847,7 +847,7 @@ struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); -static int __devinit tlv320aic23_modinit(void) +static int __init tlv320aic23_modinit(void) { return snd_soc_register_dai(&tlv320aic23_dai); } diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index ccd575961869..8da9e5d2e2fb 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1411,7 +1411,7 @@ struct snd_soc_codec_device soc_codec_dev_aic3x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); -static int __devinit aic3x_modinit(void) +static int __init aic3x_modinit(void) { return snd_soc_register_dai(&aic3x_dai); } diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 8e035b5d733f..a2c5064a774b 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -651,7 +651,7 @@ struct snd_soc_codec_device soc_codec_dev_uda134x = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda134x); -static int __devinit uda134x_init(void) +static int __init uda134x_init(void) { return snd_soc_register_dai(&uda134x_dai); } diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 55a99b6a68a1..e6bf0844fbf3 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -841,7 +841,7 @@ struct snd_soc_codec_device soc_codec_dev_uda1380 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380); -static int __devinit uda1380_modinit(void) +static int __init uda1380_modinit(void) { return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai)); } diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index a2af04bb4e9f..40f8238df717 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -889,7 +889,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8510 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); -static int __devinit wm8510_modinit(void) +static int __init wm8510_modinit(void) { return snd_soc_register_dai(&wm8510_dai); } diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 391ec2978aed..d004e5845298 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1042,7 +1042,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); -static int __devinit wm8580_modinit(void) +static int __init wm8580_modinit(void) { return snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai)); } diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index d905e25b1a93..80b11983e137 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -568,7 +568,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8728 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8728); -static int __devinit wm8728_modinit(void) +static int __init wm8728_modinit(void) { return snd_soc_register_dai(&wm8728_dai); } diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 7b455a60d719..c444b9f2701e 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -793,7 +793,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); -static int __devinit wm8731_modinit(void) +static int __init wm8731_modinit(void) { return snd_soc_register_dai(&wm8731_dai); } diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 84a6307de907..5997fa68e0d5 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -1085,7 +1085,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8750 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750); -static int __devinit wm8750_modinit(void) +static int __init wm8750_modinit(void) { return snd_soc_register_dai(&wm8750_dai); } diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 1caca30d0812..6c21b50c9375 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1874,7 +1874,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8753 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); -static int __devinit wm8753_modinit(void) +static int __init wm8753_modinit(void) { return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); } diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 34e58af0c65a..ebf58fba1beb 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1473,7 +1473,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8900 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900); -static int __devinit wm8900_modinit(void) +static int __init wm8900_modinit(void) { return i2c_add_driver(&wm8900_i2c_driver); } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 5d8fe7e1571e..0b5bea37e3dc 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1809,7 +1809,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8903 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); -static int __devinit wm8903_modinit(void) +static int __init wm8903_modinit(void) { return snd_soc_register_dai(&wm8903_dai); } diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 2979fc4f44f1..88ead7f8dd98 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -935,7 +935,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8971 = { EXPORT_SYMBOL_GPL(soc_codec_dev_wm8971); -static int __devinit wm8971_modinit(void) +static int __init wm8971_modinit(void) { return snd_soc_register_dai(&wm8971_dai); } diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 53e71aafe6c6..5b5afc144478 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1643,7 +1643,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8990 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); -static int __devinit wm8990_modinit(void) +static int __init wm8990_modinit(void) { return snd_soc_register_dai(&wm8990_dai); } diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d89fc2f009ab..81ff5c37ab56 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -481,7 +481,7 @@ struct snd_soc_dai davinci_i2s_dai = { }; EXPORT_SYMBOL_GPL(davinci_i2s_dai); -static int __devinit davinci_i2s_init(void) +static int __init davinci_i2s_init(void) { return snd_soc_register_dai(&davinci_i2s_dai); } diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index f1b6e02d24ed..bc83e1cbd176 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -384,7 +384,7 @@ struct snd_soc_platform davinci_soc_platform = { }; EXPORT_SYMBOL_GPL(davinci_soc_platform); -static int __devinit davinci_soc_platform_init(void) +static int __init davinci_soc_platform_init(void) { return snd_soc_register_platform(&davinci_soc_platform); } diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 646c807163ab..64993eda5679 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -853,7 +853,7 @@ int fsl_dma_configure(struct fsl_dma_info *dma_info) } EXPORT_SYMBOL_GPL(fsl_dma_configure); -static int __devinit fsl_soc_platform_init(void) +static int __init fsl_soc_platform_init(void) { return snd_soc_register_platform(&fsl_soc_platform); } diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 41cab2034163..39cc57ce4bfd 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -499,7 +499,7 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); -static int __devinit omap_mcbsp_init(void) +static int __init omap_mcbsp_init(void) { return snd_soc_register_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 9940de296316..ce580a97cbd5 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -354,7 +354,7 @@ struct snd_soc_platform omap_soc_platform = { }; EXPORT_SYMBOL_GPL(omap_soc_platform); -static int __devinit omap_soc_platform_init(void) +static int __init omap_soc_platform_init(void) { return snd_soc_register_platform(&omap_soc_platform); } diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 3587f2fae5f1..73cb6b4c2f2d 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -913,7 +913,7 @@ struct snd_soc_dai pxa_ssp_dai[] = { }; EXPORT_SYMBOL_GPL(pxa_ssp_dai); -static int __devinit pxa_ssp_init(void) +static int __init pxa_ssp_init(void) { return snd_soc_register_dais(pxa_ssp_dai, ARRAY_SIZE(pxa_ssp_dai)); } diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index f6249d5b492e..780db6757ad2 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -228,7 +228,7 @@ struct snd_soc_dai pxa_ac97_dai[] = { EXPORT_SYMBOL_GPL(pxa_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); -static int __devinit pxa_ac97_init(void) +static int __init pxa_ac97_init(void) { return snd_soc_register_dais(pxa_ac97_dai, ARRAY_SIZE(pxa_ac97_dai)); } diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 4fa1578f5d47..c670d08e7c9e 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -118,7 +118,7 @@ struct snd_soc_platform pxa2xx_soc_platform = { }; EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); -static int __devinit pxa2xx_soc_platform_init(void) +static int __init pxa2xx_soc_platform_init(void) { return snd_soc_register_platform(&pxa2xx_soc_platform); } diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c index 2cf050791562..f3fc0aba0aaf 100644 --- a/sound/soc/s3c24xx/s3c2412-i2s.c +++ b/sound/soc/s3c24xx/s3c2412-i2s.c @@ -736,7 +736,7 @@ struct snd_soc_dai s3c2412_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c2412_i2s_dai); -static int __devinit s3c2412_i2s_init(void) +static int __init s3c2412_i2s_init(void) { return snd_soc_register_dai(&s3c2412_i2s_dai); } diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 7360c6d913bd..723779a3058d 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -396,7 +396,7 @@ struct snd_soc_dai s3c2443_ac97_dai[] = { EXPORT_SYMBOL_GPL(s3c2443_ac97_dai); EXPORT_SYMBOL_GPL(soc_ac97_ops); -static int __devinit s3c2443_ac97_init(void) +static int __init s3c2443_ac97_init(void) { return snd_soc_register_dai(&s3c2443_ac97_dai); } diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 897b1ac92cef..6f4d439b57aa 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c @@ -482,7 +482,7 @@ struct snd_soc_dai s3c24xx_i2s_dai = { }; EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai); -static int __devinit s3c24xx_i2s_init(void) +static int __init s3c24xx_i2s_init(void) { return snd_soc_register_dai(&s3c24xx_i2s_dai); } diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index ea5a9caec13e..7c64d31d067e 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c @@ -465,7 +465,7 @@ struct snd_soc_platform s3c24xx_soc_platform = { }; EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); -static int __devinit s3c24xx_soc_platform_init(void) +static int __init s3c24xx_soc_platform_init(void) { return snd_soc_register_platform(&s3c24xx_soc_platform); } diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index 39ffca0933a2..0dad3a0bb920 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -348,7 +348,7 @@ struct snd_soc_platform sh7760_soc_platform = { }; EXPORT_SYMBOL_GPL(sh7760_soc_platform); -static int __devinit sh7760_soc_platform_init(void) +static int __init sh7760_soc_platform_init(void) { return snd_soc_register_platform(&sh7760_soc_platform); } diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 9169bad1acfb..eab31838badf 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c @@ -314,7 +314,7 @@ struct snd_soc_dai sh4_hac_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_hac_dai); -static int __devinit sh4_hac_init(void) +static int __init sh4_hac_init(void) { return snd_soc_register_dais(sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai)); } diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index 9093588d4d07..d1e5390fddeb 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -392,7 +392,7 @@ struct snd_soc_dai sh4_ssi_dai[] = { }; EXPORT_SYMBOL_GPL(sh4_ssi_dai); -static int __devinit sh4_ssi_init(void) +static int __init sh4_ssi_init(void) { return snd_soc_register_dais(sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 76a89eb65baf..4d2db7cfaf4c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2224,7 +2224,7 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform) } EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); -static int __devinit snd_soc_init(void) +static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS debugfs_root = debugfs_create_dir("asoc", NULL); From acc421656b97f09b55acb0938ad5378eefa5aacc Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 9 Dec 2008 23:26:05 +0100 Subject: [PATCH 287/367] ALSA: sound: Make static Sparse asked whether these could be static. Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai --- sound/usb/usx2y/usb_stream.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index ff23cc1ce3b9..70b96355ca4c 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -276,7 +276,8 @@ static void subs_set_complete(struct urb **urbs, void (*complete)(struct urb *)) } } -int usb_stream_prepare_playback(struct usb_stream_kernel *sk, struct urb *inurb) +static int usb_stream_prepare_playback(struct usb_stream_kernel *sk, + struct urb *inurb) { struct usb_stream *s = sk->s; struct urb *io; From f73f2a6a23e34de9cca9672f727694e5af00e6c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 07:59:33 +0100 Subject: [PATCH 288/367] ALSA: ASoC - Fix symbol conflicts in omac-mcbsp.c Add snd_ prefix to avoid the conflict of symbols in omac-mcbsp.c: sound/soc/omap/omap-mcbsp.c:503: error: static declaration of 'omap_mcbsp_init' follows non-static declaration arch/arm/plat-omap/include/mach/mcbsp.h:373: error: previous declaration of 'omap_mcbsp_init' was here Signed-off-by: Takashi Iwai --- sound/soc/omap/omap-mcbsp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 39cc57ce4bfd..7b86373007ca 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -499,18 +499,18 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); -static int __init omap_mcbsp_init(void) +static int __init snd_omap_mcbsp_init(void) { return snd_soc_register_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); } -module_init(omap_mcbsp_init); +module_init(snd_omap_mcbsp_init); -static void __exit omap_mcbsp_exit(void) +static void __exit snd_omap_mcbsp_exit(void) { snd_soc_unregister_dais(omap_mcbsp_dai, ARRAY_SIZE(omap_mcbsp_dai)); } -module_exit(omap_mcbsp_exit); +module_exit(snd_omap_mcbsp_exit); MODULE_AUTHOR("Jarkko Nikula "); MODULE_DESCRIPTION("OMAP I2S SoC Interface"); From 44411e07c2ce1a755a756e10b592cd3ba02f99b3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 08:27:19 +0100 Subject: [PATCH 289/367] ALSA: ca0106 - Check return value of pci_enable_device() in resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return value of pci_enable_device() must be checked even in resume callback: sound/pci/ca0106/ca0106_main.c:1779: warning: ignoring return value of ‘pci_enable_device’, declared with attribute warn_unused_result Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index cea8a7cdb1d5..c13aa41a35b4 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1776,7 +1776,12 @@ static int snd_ca0106_resume(struct pci_dev *pci) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); - pci_enable_device(pci); + + if (pci_enable_device(pci) < 0) { + snd_card_disconnect(card); + return -EIO; + } + pci_set_master(pci); ca0106_init_chip(chip); From d2afbe78a2922929ad44882d3583d938b9949a30 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 09:28:15 +0100 Subject: [PATCH 290/367] ALSA: hda - Update documentation Minor typo-fixes and improvements on HD-Audio.txt. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 159 ++++++++++++++------------ 1 file changed, 83 insertions(+), 76 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index e758f24017bf..ca8187de52d8 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -9,22 +9,25 @@ GENERAL HD-audio is the new standard on-board audio component on modern PCs after AC97. Although Linux has been supporting HD-audio since long time ago, there are often problems with new machines. A part of the -problem is broken BIOS, and rest is the driver implementation. This -document explains the trouble-shooting and debugging methods for the -HD-audio hardware. +problem is broken BIOS, and the rest is the driver implementation. +This document explains the brief trouble-shooting and debugging +methods for the HD-audio hardware. The HD-audio component consists of two parts: the controller chip and the codec chips on the HD-audio bus. Linux provides a single driver -for all controllers, snd-hda-intel. Since the HD-audio controllers -are supposed to be compatible, the single snd-hda-driver should work -in most cases. But, not surprisingly, there are known bugs and issues -specific to each controller type. The snd-hda-intel driver has a -bunch of workarounds for these as described below. +for all controllers, snd-hda-intel. Although the driver name contains +a word of a well-known harware vendor, it's not specific to it but for +all controller chips by other companies. Since the HD-audio +controllers are supposed to be compatible, the single snd-hda-driver +should work in most cases. But, not surprisingly, there are known +bugs and issues specific to each controller type. The snd-hda-intel +driver has a bunch of workarounds for these as described below. A controller may have multiple codecs. Usually you have one audio -codec and optionally one modem codec. In some cases, there can be -multiple audio codecs, e.g. for analog and digital outputs, but the -driver might not work properly. +codec and optionally one modem codec. In theory, there might be +multiple audio codecs, e.g. for analog and digital outputs, and the +driver might not work properly because of conflict of mixer elements. +This should be fixed in future if such hardware really exists. The snd-hda-intel driver has several different codec parsers depending on the codec. It has a generic parser as a fallback, but this @@ -48,15 +51,16 @@ DMA-Position Problem The most common problem of the controller is the inaccurate DMA pointer reporting. The DMA pointer for playback and capture can be read in two ways, either via a LPIB register or via a position-buffer -map. As default the driver tries to reads from the io-mapped -position-buffer, and falls back to LPIB if it appears unupdated. -However, this detection isn't perfect on some devices. In such a -case, you can change the default method via `position_fix` option. +map. As default the driver tries to read from the io-mapped +position-buffer, and falls back to LPIB if the position-buffer appears +dead. However, this detection isn't perfect on some devices. In such +a case, you can change the default method via `position_fix` option. `position_fix=1` means to use LPIB method explicitly. `position_fix=2` means to use the position-buffer. 0 is the default -value, the automatic check. If you get a problem of repeated sounds, -this option might help. +value, the automatic check and fallback to LPIB as described in the +above. If you get a problem of repeated sounds, this option might +help. In addition to that, every controller is known to be broken regarding the wake-up timing. It wakes up a few samples before actually @@ -67,9 +71,9 @@ via `bdl_pos_adj` option. When `bdl_pos_adj` is a negative value (as default), it's assigned to an appropriate value depending on the controller chip. For Intel -chip, it'd be 1 while it'd be 32 for others. Usually this works. +chips, it'd be 1 while it'd be 32 for others. Usually this works. Only in case it doesn't work and you get warning messages, you should -change to other values. +change this parameter to other values. Codec-Probing Problem @@ -77,13 +81,13 @@ Codec-Probing Problem A less often but a more severe problem is the codec probing. When BIOS reports the available codec slots wrongly, the driver gets confused and tries to access the non-existing codec slot. This often -results in the total screw-up, and destruct the further communication -with the codec chips. The symptom appears usually as the error -message like: +results in the total screw-up, and destructs the further communication +with the codec chips. The symptom appears usually as error messages +like: ------------------------------------------------------------------------ - hda_intel: azx_get_response timeout, switching to polling mode: \ + hda_intel: azx_get_response timeout, switching to polling mode: last cmd=0x12345678 - hda_intel: azx_get_response timeout, switching to single_cmd mode: \ + hda_intel: azx_get_response timeout, switching to single_cmd mode: last cmd=0x12345678 ------------------------------------------------------------------------ @@ -98,9 +102,9 @@ accessing a non-existing codec slot. Thus, if the second error message appears, try to narrow the probed codec slots via `probe_mask` option. It's a bitmask, and each bit -corresponding to the codec slot. For example, to probe only the -first slot, pass `probe_mask=1`. For the first and the third slots, -pass `probe_mask=5` (where 5 = 1 | 4), and so on. +corresponds to the codec slot. For example, to probe only the first +slot, pass `probe_mask=1`. For the first and the third slots, pass +`probe_mask=5` (where 5 = 1 | 4), and so on. Since 2.6.29 kernel, the driver has a more robust probing method, so this error might happen rarely, though. @@ -119,10 +123,10 @@ HD-AUDIO CODEC Model Option ~~~~~~~~~~~~ -The most common problems with the HD-audio driver is the unsupported -codec features or the mismatched device configuration. Most of -codec-specific code has several preset models, either to override the -BIOS setup or to provide more comprehensive features. +The most common problem regarding the HD-audio driver is the +unsupported codec features or the mismatched device configuration. +Most of codec-specific code has several preset models, either to +override the BIOS setup or to provide more comprehensive features. The driver checks PCI SSID and looks through the static configuration table until any matching entry is found. If you have a new machine, @@ -130,44 +134,44 @@ you may see a message like below: ------------------------------------------------------------------------ hda_codec: Unknown model for ALC880, trying auto-probe from BIOS... ------------------------------------------------------------------------ -Even if you such a message, DON'T PANIC. Take a deep breath (and keep -your towel). First of all, it's an informational message, no warning, -no error. This means that the PCI SSID of your device isn't listed in -the known preset model list. But, this doesn't mean that the driver -is broken. Many codec-driver provides the automatic configuration -based on the BIOS setup. +Even if you see such a message, DON'T PANIC. Take a deep breath and +keep your towel. First of all, it's an informational message, no +warning, no error. This means that the PCI SSID of your device isn't +listed in the known preset model (white-)list. But, this doesn't mean +that the driver is broken. Many codec-drivers provide the automatic +configuration mechanism based on the BIOS setup. The HD-audio codec has usually "pin" widgets, and BIOS sets the default configuration of each pin, which indicates the location, the connection type, the jack color, etc. The HD-audio driver can guess the right connection judging from these default configuration values. -However -- some codec support codes, such as patch_analog.c, don't +However -- some codec-support codes, such as patch_analog.c, don't support the automatic probing (yet as of 2.6.28). And, BIOS is often, yes, pretty often broken. It sets up wrong values and screws up the driver. -The preset model is provided basically to override such a situation. -When the matching preset model is found in the list, the driver +The preset model is provided basically to overcome such a situation. +When the matching preset model is found in the white-list, the driver assumes the static configuration of that preset and builds the mixer -and PCM based on the static information. Thus, if you have a newer -machine with a slightly different PCI SSID from the existing one, you -may have a good chance to re-use the same model. You can pass the -`model` option to specify the preset model instead of PCI SSID -look-up. +elements and PCM streams based on the static information. Thus, if +you have a newer machine with a slightly different PCI SSID from the +existing one, you may have a good chance to re-use the same model. +You can pass the `model` option to specify the preset model instead of +PCI SSID look-up. What `model` option values are available depends on the codec chip. Check your codec chip from the codec proc file (see "Codec Proc-File" section below). It will show the vendor/product name of your codec -chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt file. -In the section of HD-audio driver, you can find a list of codecs and -`model` options belonging to each codec. For example, for Realtek +chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt +file, the section of HD-audio driver. You can find a list of codecs +and `model` options belonging to each codec. For example, for Realtek ALC262 codec chip, pass `model=ultra` for devices that are compatible with Samsung Q1 Ultra. -Thus, the first thing you can do for any brand-new, unsupported -HD-audio hardware is to check HD-audio codec and several different -`model` option values. If you have a luck, some of them might suit -with your device well. +Thus, the first thing you can do for any brand-new, unsupported and +non-working HD-audio hardware is to check HD-audio codec and several +different `model` option values. If you have a luck, some of them +might suit with your device well. Some codecs such as ALC880 have a special model option `model=test`. This configures the driver to provide as many mixer controls as @@ -188,12 +192,14 @@ One of the most frequent (and obvious) bugs with HD-audio is the silent output from either or both of a built-in speaker and a headphone jack. In general, you should try a headphone output at first. A speaker output often requires more additional controls like -the amplifier. Thus a headphone output has a slightly better chance. +the external amplifier bits. Thus a headphone output has a slightly +better chance. Before making a bug report, double-check whether the mixer is set up correctly. The recent version of snd-hda-intel driver provides mostly -"Master" volume control as well as "Front" volume. In addition, there -are individual "Headphone" and "Speaker" controls. +"Master" volume control as well as "Front" volume (where Front +indicates the front-channels). In addition, there can be individual +"Headphone" and "Speaker" controls. Ditto for the speaker output. There can be "External Amplifier" switch on some codecs. Turn on this if present. @@ -214,7 +220,7 @@ following: external amplifier. This can be set usually via EAPD verb or a certain GPIO. If the codec pin supports EAPD, you have a better chance via SET_EAPD_BTL verb (0x70c). On others, GPIO pin (mostly - it's either GPIO0 or GPIO1) can turn on/off EAPD. + it's either GPIO0 or GPIO1) may turn on/off EAPD. - Some Realtek codecs require special vendor-specific coefficients to turn on the amplifier. See patch_realtek.c. - IDT codecs may have extra power-enable/disable controls on each @@ -227,29 +233,29 @@ following: Capture Problems ~~~~~~~~~~~~~~~~ -The capture problems are often missing setups of mixers. Thus, before -submitting a bug report, make sure that you set up the mixer -correctly. For example, both "Capture Volume" and "Capture Switch" -have to be set properly in addition to the right "Capture Source" or -"Input Source" selection. Some devices have "Mic Boost" volume or -switch. +The capture problems are often because of missing setups of mixers. +Thus, before submitting a bug report, make sure that you set up the +mixer correctly. For example, both "Capture Volume" and "Capture +Switch" have to be set properly in addition to the right "Capture +Source" or "Input Source" selection. Some devices have "Mic Boost" +volume or switch. When the PCM device is opened via "default" PCM (without pulse-audio plugin), you'll likely have "Digital Capture Volume" control as well. This is provided for the extra gain/attenuation of the signal in software, especially for the inputs without the hardware volume control such as digital microphones. Unless really needed, this -should be set to exactly 50%, corresponding to 0dB. When you use "hw" -PCM, i.e., a raw access PCM, this control will have no influence, -though. +should be set to exactly 50%, corresponding to 0dB -- neither extra +gain nor attenuation. When you use "hw" PCM, i.e., a raw access PCM, +this control will have no influence, though. It's known that some codecs / devices have fairly bad analog circuits, and the recorded sound contains a certain DC-offset. This is no bug of the driver. -Most of modern laptops have no analog CD-input connection. Thus, the +Most of modern laptops have no analog CD-input connection. Thus, the recording from CD input won't work in many cases although the driver -provides it as the capture source. +provides it as the capture source. Use CDDA instead. The automatic switching of the built-in and external mic per plugging is implemented on some codec models but not on every model. Partly @@ -264,7 +270,7 @@ to fight again the evil, try debugging via hitting the raw HD-audio codec verbs to the device. Some tools are available: hda-emu and hda-analyzer. The detailed description is found in the sections below. You'd need to enable hwdep for using these tools. See "Kernel -Configuration". +Configuration" section. OTHER ISSUES @@ -284,15 +290,16 @@ sure to want it. Don't forget to turn on the appropriate `CONFIG_SND_HDA_CODEC_*` options. Note that each of them corresponds to the codec chip, not the controller chip. Thus, even if lspci shows the Nvidia controller, -you may choose the option for other vendors. If you are unsure, just -choose all yes. +you may need to choose the option for other vendors. If you are +unsure, just select all yes. `CONFIG_SND_HDA_HWDEP` is a useful option for debugging the driver. When this is enabled, the driver creates hardware-dependent devices (one per each codec), and you have a raw access to the device via -hda-verb program. For example, `hwC0D2` will be created for the card -0 codec slot #2. For debug tools such as hda-verb and hda-analyzer, -the hwdep device has to be enabled. Thus, turn this on always. +these device files. For example, `hwC0D2` will be created for the +codec slot #2 of the first card (#0). For debug-tools such as +hda-verb and hda-analyzer, the hwdep device has to be enabled. +Thus, it'd be better to turn this on always. `CONFIG_SND_HDA_RECONFIG` is a new option, and this depends on the hwdep option above. When enabled, you'll have some sysfs files under @@ -436,7 +443,7 @@ details. hda-verb ~~~~~~~~ hda-verb is a tiny program that allows you to access the HD-audio -codec directly. It executes a HD-audio codec verb directly. +codec directly. You can execute a raw HD-audio codec verb with this. This program accesses the hwdep device, thus you need to enable the kernel config `CONFIG_SND_HDA_HWDEP=y` beforehand. @@ -486,7 +493,7 @@ hda-analyzer ~~~~~~~~~~~~ hda-analyzer provides a graphical interface to access the raw HD-audio control, based on pyGTK2 binding. It's a more powerful version of -hda-verb. The program gives you a easy-to-use GUI stuff for showing +hda-verb. The program gives you an easy-to-use GUI stuff for showing the widget information and adjusting the amp values, as well as the proc-compatible output. @@ -498,7 +505,7 @@ alsa-project.org: hda-emu ~~~~~~~ -hda-emu is a HD-audio emulator. The main purpose of this program is +hda-emu is an HD-audio emulator. The main purpose of this program is to debug an HD-audio codec without the real hardware. Thus, it doesn't emulate the behavior with the real audio I/O, but it just dumps the codec register changes and the ALSA-driver internal changes From 11d518e07d700eeb5bcec36bfd5f501e405230dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 10:37:33 +0100 Subject: [PATCH 291/367] ALSA: hda - Add quirk for HP6730B laptop Added model=laptop for HP 6730B laptop with AD1984A codec. Reference: Novell bnc#457909 https://bugzilla.novell.com/show_bug.cgi?id=457909 Signed-off-by: Takashi Iwai Cc: stable@kernel.org --- sound/pci/hda/patch_analog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index c1918a1a6df9..26247cfe749d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -3901,6 +3901,7 @@ static const char *ad1884a_models[AD1884A_MODELS] = { static struct snd_pci_quirk ad1884a_cfg_tbl[] = { SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE), SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE), + SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP), SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP), SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), From 1e297a19252a6792c4479b300020f7f63eeb56ef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 11:08:33 +0000 Subject: [PATCH 292/367] ASoC: Work around warnings from some build environments BUG() should be marked as not returning but for at least some configurations (including some widely deployed compilers) that's either not happening or being forgotten by the compiler. Add some extra return statements to the affected paths. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 0b5bea37e3dc..b1f5cf77a876 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -392,6 +392,7 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, break; default: BUG(); + return -EINVAL; /* Spurious warning from some compilers */ } switch (w->shift) { @@ -403,6 +404,7 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, break; default: BUG(); + return -EINVAL; /* Spurious warning from some compilers */ } if (event & SND_SOC_DAPM_PRE_PMU) { From 6a1bee4a9cae13aa73abd8f724bada213a38eb63 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 10 Dec 2008 12:51:46 +0200 Subject: [PATCH 293/367] ASoC: TWL4030: Add missing Carkit output SND_SOC_DAPM_OUTPUT definition for carkitL/R was missing. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 71ab5342bea5..13d5a12ac293 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -761,6 +761,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("PREDRIVER"), SND_SOC_DAPM_OUTPUT("HSOL"), SND_SOC_DAPM_OUTPUT("HSOR"), + SND_SOC_DAPM_OUTPUT("CARKITL"), + SND_SOC_DAPM_OUTPUT("CARKITR"), SND_SOC_DAPM_OUTPUT("HFL"), SND_SOC_DAPM_OUTPUT("HFR"), From d4a73131a56e906b8f65e20934516adcad68b524 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 10 Dec 2008 12:51:47 +0200 Subject: [PATCH 294/367] ASoC: TWL4030: Small cleanup The mux switch related texts fits to on line, no need to wrap them. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 13d5a12ac293..b321928152d1 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -192,8 +192,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* Earpiece */ static const char *twl4030_earpiece_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR1"}; + {"Off", "DACL1", "DACL2", "Invalid", "DACR1"}; static const struct soc_enum twl4030_earpiece_enum = SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, @@ -205,8 +204,7 @@ SOC_DAPM_ENUM("Route", twl4030_earpiece_enum); /* PreDrive Left */ static const char *twl4030_predrivel_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR2"}; + {"Off", "DACL1", "DACL2", "Invalid", "DACR2"}; static const struct soc_enum twl4030_predrivel_enum = SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, @@ -218,8 +216,7 @@ SOC_DAPM_ENUM("Route", twl4030_predrivel_enum); /* PreDrive Right */ static const char *twl4030_predriver_texts[] = - {"Off", "DACR1", "DACR2", "Invalid", - "DACL2"}; + {"Off", "DACR1", "DACR2", "Invalid", "DACL2"}; static const struct soc_enum twl4030_predriver_enum = SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, From 1e5fa31f96d558e53fe80e943305104bf4339711 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 10 Dec 2008 12:51:48 +0200 Subject: [PATCH 295/367] ASoC: TWL4030: Change the name for the DACs To avoid confusion the names for the DACs changed: DACL1 -> DAC Left1 ... Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b321928152d1..13773028f6f1 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -764,13 +764,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HFR"), /* DACs */ - SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", + SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback", TWL4030_REG_AVDAC_CTL, 0, 0), - SND_SOC_DAPM_DAC("DACL1", "Left Front Playback", + SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback", TWL4030_REG_AVDAC_CTL, 1, 0), - SND_SOC_DAPM_DAC("DACR2", "Right Rear Playback", + SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback", TWL4030_REG_AVDAC_CTL, 2, 0), - SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", + SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback", TWL4030_REG_AVDAC_CTL, 3, 0), /* Analog PGAs */ @@ -816,10 +816,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { }; static const struct snd_soc_dapm_route intercon[] = { - {"ARXL1_APGA", NULL, "DACL1"}, - {"ARXR1_APGA", NULL, "DACR1"}, - {"ARXL2_APGA", NULL, "DACL2"}, - {"ARXR2_APGA", NULL, "DACR2"}, + {"ARXL1_APGA", NULL, "DAC Left1"}, + {"ARXR1_APGA", NULL, "DAC Right1"}, + {"ARXL2_APGA", NULL, "DAC Left2"}, + {"ARXR2_APGA", NULL, "DAC Right2"}, /* Internal playback routings */ /* Earpiece */ From cdc693643271b2e6a693cf8f6afb258cce01f058 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 13:55:49 +0000 Subject: [PATCH 296/367] ALSA: Add support for mechanical jack insertion Some systems support both mechanical and electrical jack detection, allowing them to report that a jack is physically present but does not have any functioning connections. Add a new jack type for these, allowing user space to report faulty connections. Thanks to Guillem Jover for the suggestion. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- include/linux/input.h | 1 + include/sound/jack.h | 1 + sound/core/jack.c | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/include/linux/input.h b/include/linux/input.h index 7323d2ff5151..abd223b0f586 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -645,6 +645,7 @@ struct input_absinfo { #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ #define SW_LINEOUT_INSERT 0x06 /* set = inserted */ +#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) diff --git a/include/sound/jack.h b/include/sound/jack.h index 7cb25f4b50bb..2e0315cdd0d6 100644 --- a/include/sound/jack.h +++ b/include/sound/jack.h @@ -36,6 +36,7 @@ enum snd_jack_types { SND_JACK_MICROPHONE = 0x0002, SND_JACK_HEADSET = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE, SND_JACK_LINEOUT = 0x0004, + SND_JACK_MECHANICAL = 0x0008, /* If detected separately */ }; struct snd_jack { diff --git a/sound/core/jack.c b/sound/core/jack.c index c4bb9bad3133..6ebd5f12bc50 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -108,6 +108,9 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, if (type & SND_JACK_MICROPHONE) input_set_capability(jack->input_dev, EV_SW, SW_MICROPHONE_INSERT); + if (type & SND_JACK_MECHANICAL) + input_set_capability(jack->input_dev, EV_SW, + SW_JACK_PHYSICAL_INSERT); err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); if (err < 0) @@ -159,6 +162,9 @@ void snd_jack_report(struct snd_jack *jack, int status) if (jack->type & SND_JACK_MICROPHONE) input_report_switch(jack->input_dev, SW_MICROPHONE_INSERT, status & SND_JACK_MICROPHONE); + if (jack->type & SND_JACK_MECHANICAL) + input_report_switch(jack->input_dev, SW_JACK_PHYSICAL_INSERT, + status & SND_JACK_MECHANICAL); input_sync(jack->input_dev); } From 0d0cf00a7fc63cee9a4c4a3b8612879b4f7f42ba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 14:32:45 +0000 Subject: [PATCH 297/367] ASoC: Add codec registration API Another part of the backporting of Liam's ASoC v2 work. Using this is more complicated than the other registration types since currently the codec is instantiated during the probe of the ASoC device so we can't currently readily wait for the codec to register. Signed-off-by: Mark Brown --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index ce3661d07c24..f86e455d3828 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -161,6 +161,8 @@ extern struct snd_ac97_bus_ops soc_ac97_ops; int snd_soc_register_platform(struct snd_soc_platform *platform); void snd_soc_unregister_platform(struct snd_soc_platform *platform); +int snd_soc_register_codec(struct snd_soc_codec *codec); +void snd_soc_unregister_codec(struct snd_soc_codec *codec); /* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); @@ -247,6 +249,9 @@ struct snd_soc_codec { char *name; struct module *owner; struct mutex mutex; + struct device *dev; + + struct list_head list; /* callbacks */ int (*set_bias_level)(struct snd_soc_codec *, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4d2db7cfaf4c..b098c0b4c584 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -47,6 +47,7 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(card_list); static LIST_HEAD(dai_list); static LIST_HEAD(platform_list); +static LIST_HEAD(codec_list); static int snd_soc_register_card(struct snd_soc_card *card); static int snd_soc_unregister_card(struct snd_soc_card *card); @@ -2224,6 +2225,48 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform) } EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); +/** + * snd_soc_register_codec - Register a codec with the ASoC core + * + * @param codec codec to register + */ +int snd_soc_register_codec(struct snd_soc_codec *codec) +{ + if (!codec->name) + return -EINVAL; + + /* The device should become mandatory over time */ + if (!codec->dev) + printk(KERN_WARNING "No device for codec %s\n", codec->name); + + INIT_LIST_HEAD(&codec->list); + + mutex_lock(&client_mutex); + list_add(&codec->list, &codec_list); + snd_soc_instantiate_cards(); + mutex_unlock(&client_mutex); + + pr_debug("Registered codec '%s'\n", codec->name); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_register_codec); + +/** + * snd_soc_unregister_codec - Unregister a codec from the ASoC core + * + * @param codec codec to unregister + */ +void snd_soc_unregister_codec(struct snd_soc_codec *codec) +{ + mutex_lock(&client_mutex); + list_del(&codec->list); + mutex_unlock(&client_mutex); + + pr_debug("Unregistered codec '%s'\n", codec->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS From 0bed7b292d68f82316bfb8cd521e16c867689efe Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 5 Nov 2008 17:29:53 -0500 Subject: [PATCH 298/367] ALSA: cs5535audio: stick AD1888 bitshift values into a header file We'd like to use the High Pass Filter and V_REFOUT bitshift values elsewhere, so stick them into a ac97_codec.h. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- include/sound/ac97_codec.h | 2 ++ sound/pci/ac97/ac97_patch.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 9c309daf492b..251fc1cd5002 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -281,10 +281,12 @@ /* specific - Analog Devices */ #define AC97_AD_TEST 0x5a /* test register */ #define AC97_AD_TEST2 0x5c /* undocumented test register 2 */ +#define AC97_AD_HPFD_SHIFT 12 /* High Pass Filter Disable */ #define AC97_AD_CODEC_CFG 0x70 /* codec configuration */ #define AC97_AD_JACK_SPDIF 0x72 /* Jack Sense & S/PDIF */ #define AC97_AD_SERIAL_CFG 0x74 /* Serial Configuration */ #define AC97_AD_MISC 0x76 /* Misc Control Bits */ +#define AC97_AD_VREFD_SHIFT 2 /* V_REFOUT Disable (AD1888) */ /* specific - Cirrus Logic */ #define AC97_CSR_ACMODE 0x5e /* AC Mode Register */ diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 6e831aff1bd0..7ad25f439b50 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2054,8 +2054,9 @@ static const struct snd_kcontrol_new snd_ac97_ad1888_controls[] = { .get = snd_ac97_ad1888_lohpsel_get, .put = snd_ac97_ad1888_lohpsel_put }, - AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1), - AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1), + AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1), + AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, + AC97_AD_HPFD_SHIFT, 1, 1), AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, From b035ce0f26812292d067fbe2fc9e9d88d5dfcdb4 Mon Sep 17 00:00:00 2001 From: Jaya Kumar Date: Wed, 5 Nov 2008 17:30:08 -0500 Subject: [PATCH 299/367] ALSA: cs5535audio: turn off PCM properly if closing the audio device As per , we need to properly turn off the PCM if we're closing the device in order to save power. This also causes the MIC led to turn off properly. Signed-off-by: Jaya Kumar Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio.c | 3 ++- sound/pci/cs5535audio/cs5535audio.h | 1 + sound/pci/cs5535audio/cs5535audio_pcm.c | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 1d8b16052535..6c886edd06db 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -159,7 +159,8 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) return err; memset(&ac97, 0, sizeof(ac97)); - ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM; + ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM + | AC97_SCAP_POWER_SAVE; ac97.private_data = cs5535au; ac97.pci = cs5535au->pci; diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 66bae7664193..57e9c65e6854 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -78,6 +78,7 @@ struct cs5535audio_dma { unsigned int buf_addr, buf_bytes; unsigned int period_bytes, periods; u32 saved_prd; + int pcm_open_flag; }; struct cs5535audio { diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index cdcda87116c3..6aa0c19390d7 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -260,6 +260,9 @@ static int snd_cs5535audio_hw_params(struct snd_pcm_substream *substream, err = cs5535audio_build_dma_packets(cs5535au, dma, substream, params_periods(hw_params), params_period_bytes(hw_params)); + if (!err) + dma->pcm_open_flag = 1; + return err; } @@ -268,6 +271,15 @@ static int snd_cs5535audio_hw_free(struct snd_pcm_substream *substream) struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); struct cs5535audio_dma *dma = substream->runtime->private_data; + if (dma->pcm_open_flag) { + if (substream == cs5535au->playback_substream) + snd_ac97_update_power(cs5535au->ac97, + AC97_PCM_FRONT_DAC_RATE, 0); + else + snd_ac97_update_power(cs5535au->ac97, + AC97_PCM_LR_ADC_RATE, 0); + dma->pcm_open_flag = 0; + } cs5535audio_clear_dma_packets(cs5535au, dma, substream); return snd_pcm_lib_free_pages(substream); } From b6c52a2cdb58fca918eef9ada5ef3a6cd17a9240 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 5 Nov 2008 17:30:30 -0500 Subject: [PATCH 300/367] ALSA: cs5535audio: suspend/resume callbacks are only defined with CONFIG_PM snd_cs5535audio_suspend and snd_cs5535audio_resume are only defined when CONFIG_PM is set; make that clear in the header file. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 57e9c65e6854..1aa1e2bbdf74 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -94,8 +94,11 @@ struct cs5535audio { struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; }; +#ifdef CONFIG_PM int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); int snd_cs5535audio_resume(struct pci_dev *pci); +#endif + int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); #endif /* __SOUND_CS5535AUDIO_H */ From 57d4bf6d8e965404b82b105ae44ddf137bb7b8e6 Mon Sep 17 00:00:00 2001 From: Jaya Kumar Date: Thu, 6 Nov 2008 16:43:34 -0500 Subject: [PATCH 301/367] ALSA: cs5535audio: OLPC analog input support This is a 2nd cut at adding support for OLPC analog input. Signed-off-by: Jaya Kumar Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/Makefile | 4 + sound/pci/cs5535audio/cs5535audio.c | 7 ++ sound/pci/cs5535audio/cs5535audio.h | 9 ++ sound/pci/cs5535audio/cs5535audio_olpc.c | 113 +++++++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 sound/pci/cs5535audio/cs5535audio_olpc.c diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index bb3d57e6a3cb..3e41fd39780d 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -5,5 +5,9 @@ snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o +ifdef CONFIG_OLPC +snd-cs5535audio-objs += cs5535audio_olpc.o +endif + # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 6c886edd06db..50333bb9242c 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -171,6 +171,13 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk); + /* olpc_quirks is dummied out if not olpc */ + err = olpc_quirks(card, cs5535au->ac97); + if (err < 0) { + snd_printk(KERN_ERR "olpc quirks failed\n"); + return err; + } + return 0; } diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 1aa1e2bbdf74..adcb213eb276 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -92,6 +92,9 @@ struct cs5535audio { struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; +#ifdef CONFIG_OLPC + int ec_analog_input_mode; +#endif }; #ifdef CONFIG_PM @@ -99,6 +102,12 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); int snd_cs5535audio_resume(struct pci_dev *pci); #endif +#ifdef CONFIG_OLPC +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); +#else +#define olpc_quirks(arg, arg2) (0) +#endif + int __devinit 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 new file mode 100644 index 000000000000..4b72d8662ec9 --- /dev/null +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include +#include "cs5535audio.h" + +/* OLPC has an additional feature on top of regular AD1888 codec +features. This is support for an analog input mode. This is a +2 step process. First, to turn off the AD1888 codec bias voltage +and high pass filter. Second, to tell the embedded controller to +reroute from a capacitive trace to a direct trace using an analog +switch. The *_ec()s are what talk to that controller */ + +static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +#define AD1888_VREFOUT_EN_BIT (1 << 2) +#define AD1888_HPF_EN_BIT (1 << 12) +static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); + u16 reg1, reg2; + + /* if either AD1888 VRef Bias and High Pass Filter are enabled + or the EC is not in analog mode then flag as not in analog mode. + No EC command to read current analog state so we cache that. */ + reg1 = snd_ac97_read(cs5535au->ac97, AC97_AD_MISC); + reg2 = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); + + if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT) && + cs5535au->ec_analog_input_mode) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int err; + struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); + u8 value; + struct snd_ac97 *ac97 = cs5535au->ac97; + + /* value is 1 if analog input is desired */ + value = ucontrol->value.integer.value[0]; + + /* use ec mode as flag to determine if any change needed */ + if (cs5535au->ec_analog_input_mode == value) + return 0; + + /* sets High Z on VREF Bias if 1 */ + if (value) + err = snd_ac97_update_bits(ac97, AC97_AD_MISC, + AD1888_VREFOUT_EN_BIT, AD1888_VREFOUT_EN_BIT); + else + err = snd_ac97_update_bits(ac97, AC97_AD_MISC, + AD1888_VREFOUT_EN_BIT, 0); + if (err < 0) + snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err); + + /* turns off High Pass Filter if 1 */ + if (value) + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, + AD1888_HPF_EN_BIT, AD1888_HPF_EN_BIT); + else + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, + AD1888_HPF_EN_BIT, 0); + if (err < 0) + snd_printk(KERN_ERR "Error updating AD_TEST2 %d\n", err); + + if (value) + err = write_ec_command(0x01); /* activate MIC_AC_OFF */ + else + err = write_ec_command(0x02); /* deactivates MIC_AC_OFF */ + + if (err < 0) + snd_printk(KERN_ERR "Error talking to EC %d\n", err); + + cs5535au->ec_analog_input_mode = value; + + return 1; +} + +static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Input Switch", + .info = snd_cs5535audio_ctl_info, + .get = snd_cs5535audio_ctl_get, + .put = snd_cs5535audio_ctl_put, + .private_value = 0 +}; + +int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) +{ + /* setup callback for mixer control that does analog input mode */ + return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls, + ac97->private_data)); +} + From c8974be5465b87414fa542cf9cca1a1ba21b8d60 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Thu, 6 Nov 2008 16:43:53 -0500 Subject: [PATCH 302/367] ALSA: cs5535audio: Use OLPC/Geode basic infrastructure Use basic infrastructure code; geode_gpio* (rather than indexed i/o EC access), and do an OLPC machine check in olpc_quirk. [dilinger@debian.org: don't return failure in olpc_quirks if !OLPC] [dilinger@debian.org: drop the Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/cs5535audio_olpc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 4b72d8662ec9..9073fb353f0e 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -1,9 +1,10 @@ -#include #include #include #include #include #include + +#include #include "cs5535audio.h" /* OLPC has an additional feature on top of regular AD1888 codec @@ -81,13 +82,11 @@ static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, if (err < 0) snd_printk(KERN_ERR "Error updating AD_TEST2 %d\n", err); + /* B2 and newer writes directly to a GPIO pin */ if (value) - err = write_ec_command(0x01); /* activate MIC_AC_OFF */ + geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); else - err = write_ec_command(0x02); /* deactivates MIC_AC_OFF */ - - if (err < 0) - snd_printk(KERN_ERR "Error talking to EC %d\n", err); + geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); cs5535au->ec_analog_input_mode = value; @@ -106,6 +105,9 @@ static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { + if (!machine_is_olpc()) + return 0; + /* setup callback for mixer control that does analog input mode */ return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls, ac97->private_data)); From 3556d18465c6e67c7a8f436428b95671add02f57 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:44:08 -0500 Subject: [PATCH 303/367] ALSA: cs5535audio: invert EAPD for OLPC (newer than B3) Fix an audible pop described in . Originally based upon fixes by Mitch Bradley and Chris Ball. Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/cs5535audio.c | 3 +++ sound/pci/cs5535audio/cs5535audio.h | 11 +++++++++-- sound/pci/cs5535audio/cs5535audio_olpc.c | 11 +++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 50333bb9242c..130f10a8d524 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -164,6 +164,9 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) ac97.private_data = cs5535au; ac97.pci = cs5535au->pci; + /* set any OLPC-specific scaps */ + olpc_prequirks(card, &ac97); + if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) { snd_printk(KERN_ERR "mixer failed\n"); return err; diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index adcb213eb276..93602cf2858a 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -103,9 +103,16 @@ int snd_cs5535audio_resume(struct pci_dev *pci); #endif #ifdef CONFIG_OLPC -int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); +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); #else -#define olpc_quirks(arg, arg2) (0) +static inline void olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97) { } +static inline int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) +{ + return 0; +} #endif int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 9073fb353f0e..ff7b68ba6179 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -103,6 +103,17 @@ static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = .private_value = 0 }; +void __devinit olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97) +{ + if (!machine_is_olpc()) + return; + + /* invert EAPD if on an OLPC B3 or higher */ + if (olpc_board_at_least(olpc_board_pre(0xb3))) + ac97->scaps |= AC97_SCAP_INV_EAPD; +} + int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { if (!machine_is_olpc()) From b91254e75c3ec4f371ce1849672a95a929d99861 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:46:31 -0500 Subject: [PATCH 304/367] ALSA: cs5535audio: drop ec_analog_input flag for OLPC stuff This is no longer necessary, as we're no longer doing indexed i/o commands. Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/cs5535audio.h | 3 --- sound/pci/cs5535audio/cs5535audio_olpc.c | 9 +-------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 93602cf2858a..31ecb33ffff9 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -92,9 +92,6 @@ struct cs5535audio { struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; -#ifdef CONFIG_OLPC - int ec_analog_input_mode; -#endif }; #ifdef CONFIG_PM diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index ff7b68ba6179..2bd6588b4353 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -38,8 +38,7 @@ static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, reg1 = snd_ac97_read(cs5535au->ac97, AC97_AD_MISC); reg2 = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); - if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT) && - cs5535au->ec_analog_input_mode) + if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT)) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; @@ -58,10 +57,6 @@ static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, /* value is 1 if analog input is desired */ value = ucontrol->value.integer.value[0]; - /* use ec mode as flag to determine if any change needed */ - if (cs5535au->ec_analog_input_mode == value) - return 0; - /* sets High Z on VREF Bias if 1 */ if (value) err = snd_ac97_update_bits(ac97, AC97_AD_MISC, @@ -88,8 +83,6 @@ static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, else geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); - cs5535au->ec_analog_input_mode = value; - return 1; } From 1e2232bc70b32f90109d678d1faccf6f50ebba80 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:47:05 -0500 Subject: [PATCH 305/367] ALSA: cs5535audio: decouple HPF from V_REFOUT in OLPC code We shouldn't be touching V_REFOUT when we toggle HPF/analog input, so just drop that code. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 25 ++++-------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 2bd6588b4353..f20e74182725 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -30,18 +30,11 @@ static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); - u16 reg1, reg2; + u8 val; - /* if either AD1888 VRef Bias and High Pass Filter are enabled - or the EC is not in analog mode then flag as not in analog mode. - No EC command to read current analog state so we cache that. */ - reg1 = snd_ac97_read(cs5535au->ac97, AC97_AD_MISC); - reg2 = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); - - if ((reg1 & AD1888_VREFOUT_EN_BIT) && (reg2 & AD1888_HPF_EN_BIT)) - ucontrol->value.integer.value[0] = 1; - else - ucontrol->value.integer.value[0] = 0; + val = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); + val >>= AC97_AD_HPFD_SHIFT; + ucontrol->value.integer.value[0] = val & 0x1; return 0; } @@ -57,16 +50,6 @@ static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, /* value is 1 if analog input is desired */ value = ucontrol->value.integer.value[0]; - /* sets High Z on VREF Bias if 1 */ - if (value) - err = snd_ac97_update_bits(ac97, AC97_AD_MISC, - AD1888_VREFOUT_EN_BIT, AD1888_VREFOUT_EN_BIT); - else - err = snd_ac97_update_bits(ac97, AC97_AD_MISC, - AD1888_VREFOUT_EN_BIT, 0); - if (err < 0) - snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err); - /* turns off High Pass Filter if 1 */ if (value) err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, From d6276b78028dfab944dd4a58124aefcc9aa580da Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:49:38 -0500 Subject: [PATCH 306/367] ALSA: cs5535audio: create function for setting OLPC's Analog Input mode Clean this stuff up a bit.. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio.h | 2 + sound/pci/cs5535audio/cs5535audio_olpc.c | 54 +++++++++++------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 31ecb33ffff9..22737fc9ed03 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -103,6 +103,7 @@ int snd_cs5535audio_resume(struct pci_dev *pci); 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 olpc_analog_input(struct snd_ac97 *ac97, int on); #else static inline void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) { } @@ -110,6 +111,7 @@ static inline int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { return 0; } +static inline void olpc_analog_input(struct snd_ac97 *ac97, int on) { } #endif int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index f20e74182725..597395e6e358 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -7,12 +7,29 @@ #include #include "cs5535audio.h" -/* OLPC has an additional feature on top of regular AD1888 codec -features. This is support for an analog input mode. This is a -2 step process. First, to turn off the AD1888 codec bias voltage -and high pass filter. Second, to tell the embedded controller to -reroute from a capacitive trace to a direct trace using an analog -switch. The *_ec()s are what talk to that controller */ +/* + * OLPC has an additional feature on top of the regular AD1888 codec features. + * It has an Analog Input mode that is switched into (after disabling the + * High Pass Filter) via GPIO. It is supported on B2 and later models. + */ +void olpc_analog_input(struct snd_ac97 *ac97, int on) +{ + int err; + + /* update the High Pass Filter (via AC97_AD_TEST2) */ + err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, + 1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT); + if (err < 0) { + snd_printk(KERN_ERR "setting High Pass Filter - %d\n", err); + return; + } + + /* set Analog Input through GPIO */ + if (on) + geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); + else + geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); +} static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -24,8 +41,6 @@ static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, return 0; } -#define AD1888_VREFOUT_EN_BIT (1 << 2) -#define AD1888_HPF_EN_BIT (1 << 12) static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -42,30 +57,9 @@ static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - int err; struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); - u8 value; - struct snd_ac97 *ac97 = cs5535au->ac97; - - /* value is 1 if analog input is desired */ - value = ucontrol->value.integer.value[0]; - - /* turns off High Pass Filter if 1 */ - if (value) - err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, - AD1888_HPF_EN_BIT, AD1888_HPF_EN_BIT); - else - err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, - AD1888_HPF_EN_BIT, 0); - if (err < 0) - snd_printk(KERN_ERR "Error updating AD_TEST2 %d\n", err); - - /* B2 and newer writes directly to a GPIO pin */ - if (value) - geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); - else - geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); + olpc_analog_input(cs5535au->ac97, ucontrol->value.integer.value[0]); return 1; } From 466ae3055be8665525a5613456fcb387ffef4cb7 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:49:46 -0500 Subject: [PATCH 307/367] ALSA: cs5535audio: rename OLPC's analog input control && drop AD1888's HPF Previously, we had two separate controls; there's no need to have AD1888's HPF control, so drop it if we're on an OLPC machine. Also, as per Arjun's request, rename OLPC's Analog Input Switch control to "DC Mode Enable". Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 36 ++++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 597395e6e358..6c0c0dbeb218 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -31,8 +31,8 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on) geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); } -static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static int olpc_dc_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; @@ -41,35 +41,33 @@ static int snd_cs5535audio_ctl_info(struct snd_kcontrol *kcontrol, return 0; } -static int snd_cs5535audio_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int olpc_dc_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) { - struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); + struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); u8 val; val = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); val >>= AC97_AD_HPFD_SHIFT; - ucontrol->value.integer.value[0] = val & 0x1; + v->value.integer.value[0] = val & 0x1; return 0; } -static int snd_cs5535audio_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int olpc_dc_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) { - struct cs5535audio *cs5535au = snd_kcontrol_chip(kcontrol); + struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); - olpc_analog_input(cs5535au->ac97, ucontrol->value.integer.value[0]); + olpc_analog_input(cs5535au->ac97, v->value.integer.value[0]); return 1; } static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Input Switch", - .info = snd_cs5535audio_ctl_info, - .get = snd_cs5535audio_ctl_get, - .put = snd_cs5535audio_ctl_put, + .name = "DC Mode Enable", + .info = olpc_dc_info, + .get = olpc_dc_get, + .put = olpc_dc_put, .private_value = 0 }; @@ -86,10 +84,18 @@ void __devinit olpc_prequirks(struct snd_card *card, int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { + struct snd_ctl_elem_id elem; + if (!machine_is_olpc()) return 0; - /* setup callback for mixer control that does analog input mode */ + /* drop the original AD1888 HPF control */ + memset(&elem, 0, sizeof(elem)); + elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strncpy(elem.name, "High Pass Filter Enable", sizeof(elem.name)); + snd_ctl_remove_id(card, &elem); + + /* add the override for OLPC's HPF */ return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls, ac97->private_data)); } From 189d34e747e9540b70227f6682bd680868d90b10 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:49:55 -0500 Subject: [PATCH 308/367] ALSA: cs5535audio: check OLPC's Analog Input status vis GPIO Checking the HPF register is irrelevant; HPF is secondary to the AI mode. Instead, check for Analog Input mode via GPIO. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 6c0c0dbeb218..7f26cfbc8f52 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -43,13 +43,8 @@ static int olpc_dc_info(struct snd_kcontrol *kctl, static int olpc_dc_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) { - struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); - u8 val; - - val = snd_ac97_read(cs5535au->ac97, AC97_AD_TEST2); - val >>= AC97_AD_HPFD_SHIFT; - v->value.integer.value[0] = val & 0x1; - + v->value.integer.value[0] = geode_gpio_isset(OLPC_GPIO_MIC_AC, + GPIO_OUTPUT_VAL); return 0; } From e463ae1d13ffe4943bb31f47cc6f24415e55a59a Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Thu, 6 Nov 2008 16:50:09 -0500 Subject: [PATCH 309/367] ALSA: cs5535audio: enable OLPC's V_REFOUT bias when recording The OLPC has a privacy light hooked up in series with the microphone's V_Ref bias. We want to activate the bias while we are capturing audio. Signed-off-by: Chris Ball Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_pcm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 6aa0c19390d7..fa2a6b1b81a6 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -363,11 +363,27 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; + +#ifdef CONFIG_OLPC + /* Enable the V_ref bias only while recording. */ + err = snd_ac97_update_bits(cs5535au->ac97, AC97_AD_MISC, + 1 << AC97_AD_VREFD_SHIFT, 0); + if (err < 0) + snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err); +#endif return 0; } static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream) { + int err; + struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); + +#ifdef CONFIG_OLPC + /* Disable V_ref bias. */ + err = snd_ac97_update_bits(cs5535au->ac97, AC97_AD_MISC, + 1 << AC97_AD_VREFD_SHIFT, 1 << AC97_AD_VREFD_SHIFT); +#endif return 0; } From bf1e5278354856ac0260d338961560e720147681 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:03 -0500 Subject: [PATCH 310/367] ALSA: cs5535audio: rename V_REFOUT control to MIC Bias This drops the AD1888 V_REFOUT control, and replaces it with a MIC Bias Enable control. It also moves the MIC bias enabling into a separate function. Signed-off-by: Andres Salomon --- sound/pci/cs5535audio/cs5535audio.h | 16 ++++++ sound/pci/cs5535audio/cs5535audio_olpc.c | 73 ++++++++++++++++++++++-- sound/pci/cs5535audio/cs5535audio_pcm.c | 17 +----- 3 files changed, 87 insertions(+), 19 deletions(-) diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 22737fc9ed03..63190cd723c6 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -104,6 +104,19 @@ 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 olpc_analog_input(struct snd_ac97 *ac97, int on); +void olpc_mic_bias(struct snd_ac97 *ac97, int on); + +static inline void olpc_capture_open(struct snd_ac97 *ac97) +{ + /* enable MIC Bias for recording */ + olpc_mic_bias(ac97, 1); +} + +static inline void olpc_capture_close(struct snd_ac97 *ac97) +{ + /* disable the MIC Bias (so the recording LED turns off) */ + olpc_mic_bias(ac97, 0); +} #else static inline void olpc_prequirks(struct snd_card *card, struct snd_ac97_template *ac97) { } @@ -112,6 +125,9 @@ static inline int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) return 0; } static inline void olpc_analog_input(struct snd_ac97 *ac97, int on) { } +static inline void olpc_mic_bias(struct snd_ac97 *ac97, int on) { } +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); diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 7f26cfbc8f52..73811e0e8ac7 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -31,6 +31,20 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on) geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); } +/* + * OLPC XO-1's V_REFOUT is a mic bias enable. + */ +void olpc_mic_bias(struct snd_ac97 *ac97, int on) +{ + int err; + + on = on ? 0 : 1; + err = snd_ac97_update_bits(ac97, AC97_AD_MISC, + 1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT); + if (err < 0) + snd_printk(KERN_ERR "setting MIC Bias - %d\n", err); +} + static int olpc_dc_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -56,7 +70,36 @@ static int olpc_dc_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) return 1; } -static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = +static int olpc_mic_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int olpc_mic_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) +{ + struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); + struct snd_ac97 *ac97 = cs5535au->ac97; + int i; + + i = (snd_ac97_read(ac97, AC97_AD_MISC) >> AC97_AD_VREFD_SHIFT) & 0x1; + v->value.integer.value[0] = i ? 0 : 1; + return 0; +} + +static int olpc_mic_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) +{ + struct cs5535audio *cs5535au = snd_kcontrol_chip(kctl); + + olpc_mic_bias(cs5535au->ac97, v->value.integer.value[0]); + return 1; +} + +static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DC Mode Enable", @@ -64,6 +107,15 @@ static struct snd_kcontrol_new snd_cs5535audio_controls __devinitdata = .get = olpc_dc_get, .put = olpc_dc_put, .private_value = 0 +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIC Bias Enable", + .info = olpc_mic_info, + .get = olpc_mic_get, + .put = olpc_mic_put, + .private_value = 0, +}, }; void __devinit olpc_prequirks(struct snd_card *card, @@ -80,6 +132,7 @@ void __devinit olpc_prequirks(struct snd_card *card, int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { struct snd_ctl_elem_id elem; + int i, err; if (!machine_is_olpc()) return 0; @@ -90,8 +143,20 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) strncpy(elem.name, "High Pass Filter Enable", sizeof(elem.name)); snd_ctl_remove_id(card, &elem); - /* add the override for OLPC's HPF */ - return snd_ctl_add(card, snd_ctl_new1(&snd_cs5535audio_controls, - ac97->private_data)); + /* drop the original V_REFOUT control */ + memset(&elem, 0, sizeof(elem)); + elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strncpy(elem.name, "V_REFOUT Enable", sizeof(elem.name)); + snd_ctl_remove_id(card, &elem); + + /* add the OLPC-specific controls */ + for (i = 0; i < ARRAY_SIZE(olpc_cs5535audio_ctls); i++) { + err = snd_ctl_add(card, snd_ctl_new1(&olpc_cs5535audio_ctls[i], + ac97->private_data)); + if (err < 0) + return err; + } + + return 0; } diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index fa2a6b1b81a6..0f48a871f17b 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -363,27 +363,14 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; - -#ifdef CONFIG_OLPC - /* Enable the V_ref bias only while recording. */ - err = snd_ac97_update_bits(cs5535au->ac97, AC97_AD_MISC, - 1 << AC97_AD_VREFD_SHIFT, 0); - if (err < 0) - snd_printk(KERN_ERR "Error updating AD_MISC %d\n", err); -#endif + olpc_capture_open(cs5535au->ac97); return 0; } static int snd_cs5535audio_capture_close(struct snd_pcm_substream *substream) { - int err; struct cs5535audio *cs5535au = snd_pcm_substream_chip(substream); - -#ifdef CONFIG_OLPC - /* Disable V_ref bias. */ - err = snd_ac97_update_bits(cs5535au->ac97, AC97_AD_MISC, - 1 << AC97_AD_VREFD_SHIFT, 1 << AC97_AD_VREFD_SHIFT); -#endif + olpc_capture_close(cs5535au->ac97); return 0; } From 01da02419da827742acd5235467f493206e83574 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:11 -0500 Subject: [PATCH 311/367] ALSA: cs5535audio: for OLPC, default to Analog Input being off Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 63190cd723c6..777703717a70 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -108,12 +108,16 @@ void olpc_mic_bias(struct snd_ac97 *ac97, int on); static inline void olpc_capture_open(struct snd_ac97 *ac97) { + /* default to Analog Input off */ + olpc_analog_input(ac97, 0); /* enable MIC Bias for recording */ olpc_mic_bias(ac97, 1); } static inline void olpc_capture_close(struct snd_ac97 *ac97) { + /* disable Analog Input */ + olpc_analog_input(ac97, 0); /* disable the MIC Bias (so the recording LED turns off) */ olpc_mic_bias(ac97, 0); } From c8f0eeebc119c401202bc2794bec026d6cfd062e Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:19 -0500 Subject: [PATCH 312/367] ALSA: cs5535audio: turn off mic bias on OLPCs by default Always turn off mic bias; the MIC LED should never come on when the driver is first loaded. Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 73811e0e8ac7..45b24f718d62 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -157,6 +157,8 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) return err; } + /* turn off the mic by default */ + olpc_mic_bias(ac97, 0); return 0; } From b5ccc57b06b54058879ab3ea548625d9bf88c7fc Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:26 -0500 Subject: [PATCH 313/367] ALSA: cs5535audio: clean up OLPC code - add copyright info to _olpc.c - minor layout fixes - make Makefile more concise - silence a warning Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/Makefile | 5 +---- sound/pci/cs5535audio/cs5535audio.c | 1 - sound/pci/cs5535audio/cs5535audio_olpc.c | 15 ++++++++++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index 3e41fd39780d..ccc642269b9e 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -4,10 +4,7 @@ snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o - -ifdef CONFIG_OLPC -snd-cs5535audio-objs += cs5535audio_olpc.o -endif +snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 130f10a8d524..826e6dec2e97 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -174,7 +174,6 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk); - /* olpc_quirks is dummied out if not olpc */ err = olpc_quirks(card, cs5535au->ac97); if (err < 0) { snd_printk(KERN_ERR "olpc quirks failed\n"); diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 45b24f718d62..164f6bdab991 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -1,4 +1,14 @@ -#include +/* + * OLPC XO-1 additional sound features + * + * Copyright © 2006 Jaya Kumar + * Copyright © 2007-2008 Andres Salomon + * + * 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. + */ #include #include #include @@ -106,7 +116,7 @@ static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = { .info = olpc_dc_info, .get = olpc_dc_get, .put = olpc_dc_put, - .private_value = 0 + .private_value = 0, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -161,4 +171,3 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) olpc_mic_bias(ac97, 0); return 0; } - From 0fb497f5b6ff8da1e9e60afb39835f40d7f043ec Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 6 Nov 2008 16:53:34 -0500 Subject: [PATCH 314/367] ALSA: cs5535audio: ensure MIC Bias/Analog Input bail if not on an OLPC machine Signed-off-by: Andres Salomon Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/cs5535audio_olpc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 164f6bdab991..5c6814335cd7 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -26,6 +26,9 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on) { int err; + if (!machine_is_olpc()) + return; + /* update the High Pass Filter (via AC97_AD_TEST2) */ err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, 1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT); @@ -48,6 +51,9 @@ void olpc_mic_bias(struct snd_ac97 *ac97, int on) { int err; + if (!machine_is_olpc()) + return; + on = on ? 0 : 1; err = snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT); From f144b7f6679d9833bd3b94b91e452592b6d0e502 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Dec 2008 17:23:24 +0100 Subject: [PATCH 315/367] ALSA: cs5535 - Make OLPC-stuff depending on MGEODE_LX The GPIO stuff for OLPC in cs5535audio_olpc.c is implemented only for Geode-LX, and enabled only when CONFIG_MGEODE_LX=y. Without this config option, the driver gets build errors. This patch adds a workaround to make it dependent on CONFIG_MGEODE_LX. Ideally, the OLPC-GPIO stuff should be implemented in a way independent from CPU type selection... Signed-off-by: Takashi Iwai --- sound/pci/cs5535audio/Makefile | 2 ++ sound/pci/cs5535audio/cs5535audio.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index ccc642269b9e..fda7a94c992f 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -4,7 +4,9 @@ snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o +ifdef CONFIG_MGEODE_LX snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o +endif # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 777703717a70..7a298ac662e3 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -99,7 +99,7 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); int snd_cs5535audio_resume(struct pci_dev *pci); #endif -#ifdef CONFIG_OLPC +#if defined(CONFIG_OLPC) && defined(CONFIG_MGEODE_LX) 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); From 78e19a39d3985e2a06354493a70a200c0d432de5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 15:38:36 +0000 Subject: [PATCH 316/367] ASoC: Convert WM8900 to do more work at I2C probe time Redo the instantiation of the WM8900 to do most of the initialisation work when the I2C driver probes rather than when the ASoC device is instantiated, registering the codec with the ASoC core when done. Also move all dynamic allocations into a single kmalloc() to simplify error handling and rename the I2C driver to make output more sensible. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8900.c | 171 +++++++++++++++++++------------------- sound/soc/codecs/wm8900.h | 7 -- 2 files changed, 87 insertions(+), 91 deletions(-) diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index ebf58fba1beb..6767de10ded0 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -138,6 +138,10 @@ struct snd_soc_codec_device soc_codec_dev_wm8900; struct wm8900_priv { + struct snd_soc_codec codec; + + u16 reg_cache[WM8900_MAXREG]; + u32 fll_in; /* FLL input frequency */ u32 fll_out; /* FLL output frequency */ }; @@ -1282,16 +1286,28 @@ static int wm8900_resume(struct platform_device *pdev) return 0; } -/* - * initialise the WM8900 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8900_init(struct snd_soc_device *socdev) +static struct snd_soc_codec *wm8900_codec; + +static int wm8900_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; + struct wm8900_priv *wm8900; + struct snd_soc_codec *codec; unsigned int reg; - struct i2c_client *i2c_client = socdev->codec->control_data; + int ret; + + wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); + if (wm8900 == NULL) + return -ENOMEM; + + codec = &wm8900->codec; + codec->private_data = wm8900; + codec->reg_cache = &wm8900->reg_cache[0]; + codec->reg_cache_size = WM8900_MAXREG; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); codec->name = "WM8900"; codec->owner = THIS_MODULE; @@ -1299,33 +1315,28 @@ static int wm8900_init(struct snd_soc_device *socdev) codec->write = wm8900_write; codec->dai = &wm8900_dai; codec->num_dai = 1; - codec->reg_cache_size = WM8900_MAXREG; - codec->reg_cache = kmemdup(wm8900_reg_defaults, - sizeof(wm8900_reg_defaults), GFP_KERNEL); - - if (codec->reg_cache == NULL) - return -ENOMEM; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->control_data = i2c; + codec->set_bias_level = wm8900_set_bias_level; + codec->dev = &i2c->dev; reg = wm8900_read(codec, WM8900_REG_ID); if (reg != 0x8900) { - dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n", - reg); - return -ENODEV; - } - - codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); - if (codec->private_data == NULL) { - ret = -ENOMEM; - goto priv_err; + dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg); + ret = -ENODEV; + goto err; } /* Read back from the chip */ reg = wm8900_chip_read(codec, WM8900_REG_POWER1); reg = (reg >> 12) & 0xf; - dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg); + dev_info(&i2c->dev, "WM8900 revision %d\n", reg); wm8900_reset(codec); + /* Turn the chip on */ + wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Latch the volume update bits */ wm8900_write(codec, WM8900_REG_LINVOL, wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); @@ -1351,52 +1362,43 @@ static int wm8900_init(struct snd_soc_device *socdev) /* Set the DAC and mixer output bias */ wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); - /* Register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(&i2c_client->dev, "Failed to register new PCMs\n"); - goto pcm_err; - } - - /* Turn the chip on */ - codec->bias_level = SND_SOC_BIAS_OFF; - wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - - wm8900_add_controls(codec); - wm8900_add_widgets(codec); - - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&i2c_client->dev, "Failed to register card\n"); - goto card_err; - } - return ret; - -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); -priv_err: - kfree(codec->private_data); - return ret; -} - -static struct i2c_client *wm8900_client; - -static int wm8900_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - wm8900_client = i2c; wm8900_dai.dev = &i2c->dev; - return snd_soc_register_dai(&wm8900_dai); + + wm8900_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&wm8900_dai); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; + } + + return ret; + +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8900); + wm8900_codec = NULL; + return ret; } static int wm8900_i2c_remove(struct i2c_client *client) { snd_soc_unregister_dai(&wm8900_dai); + snd_soc_unregister_codec(wm8900_codec); + + wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF); + wm8900_dai.dev = NULL; - wm8900_client = NULL; + kfree(wm8900_codec->private_data); + wm8900_codec = NULL; + return 0; } @@ -1408,7 +1410,7 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); static struct i2c_driver wm8900_i2c_driver = { .driver = { - .name = "WM8900 I2C codec", + .name = "WM8900", .owner = THIS_MODULE, }, .probe = wm8900_i2c_probe, @@ -1422,45 +1424,46 @@ static int wm8900_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0; - if (!wm8900_client) { + if (!wm8900_codec) { dev_err(&pdev->dev, "I2C client not yet instantiated\n"); return -ENODEV; } - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - + codec = wm8900_codec; socdev->codec = codec; - codec->set_bias_level = wm8900_set_bias_level; + /* Register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register new PCMs\n"); + goto pcm_err; + } - codec->hw_write = (hw_write_t)i2c_master_send; - codec->control_data = wm8900_client; + wm8900_add_controls(codec); + wm8900_add_widgets(codec); - ret = wm8900_init(socdev); - if (ret != 0) - kfree(codec); + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register card\n"); + goto card_err; + } return ret; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: + return ret; } /* power down chip */ static int wm8900_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); - kfree(codec); return 0; } diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h index 2249a446ad37..fd15007d10c7 100644 --- a/sound/soc/codecs/wm8900.h +++ b/sound/soc/codecs/wm8900.h @@ -52,13 +52,6 @@ #define WM8900_DAC_CLKDIV_5_5 0x14 #define WM8900_DAC_CLKDIV_6 0x18 -#define WM8900_ - -struct wm8900_setup_data { - int i2c_bus; - unsigned short i2c_address; -}; - extern struct snd_soc_dai wm8900_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8900; From d58d5d5567ea9483346f57c83a94ce05992cd47c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 18:36:42 +0000 Subject: [PATCH 317/367] ASoC: Convert WM8903 driver to register at I2C probe time The driver now registers the codec and DAI when probed as an I2C device. Also convert the driver to use a single dynamic allocation to simplify error handling. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 242 ++++++++++++++++---------------------- sound/soc/codecs/wm8903.h | 5 - 2 files changed, 103 insertions(+), 144 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b1f5cf77a876..c80968fe326e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -33,19 +33,6 @@ #include "wm8903.h" -struct wm8903_priv { - int sysclk; - - /* Reference counts */ - int charge_pump_users; - int class_w_users; - int playback_active; - int capture_active; - - struct snd_pcm_substream *master_substream; - struct snd_pcm_substream *slave_substream; -}; - /* Register defaults at reset */ static u16 wm8903_reg_defaults[] = { 0x8903, /* R0 - SW Reset and ID */ @@ -223,6 +210,23 @@ static u16 wm8903_reg_defaults[] = { 0x0000, /* R172 - Analogue Output Bias 0 */ }; +struct wm8903_priv { + struct snd_soc_codec codec; + u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)]; + + int sysclk; + + /* Reference counts */ + int charge_pump_users; + int class_w_users; + int playback_active; + int capture_active; + + struct snd_pcm_substream *master_substream; + struct snd_pcm_substream *slave_substream; +}; + + static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { @@ -360,6 +364,8 @@ static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) static void wm8903_reset(struct snd_soc_codec *codec) { wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); + memcpy(codec->reg_cache, wm8903_reg_defaults, + sizeof(wm8903_reg_defaults)); } #define WM8903_OUTPUT_SHORT 0x8 @@ -1563,17 +1569,43 @@ static int wm8903_resume(struct platform_device *pdev) return 0; } -/* - * initialise the WM8903 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8903_init(struct snd_soc_device *socdev) +static struct snd_soc_codec *wm8903_codec; + +static int wm8903_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c = codec->control_data; - int ret = 0; + struct wm8903_priv *wm8903; + struct snd_soc_codec *codec; + int ret; u16 val; + wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); + if (wm8903 == NULL) + return -ENOMEM; + + codec = &wm8903->codec; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->dev = &i2c->dev; + codec->name = "WM8903"; + codec->owner = THIS_MODULE; + codec->read = wm8903_read; + codec->write = wm8903_write; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8903_set_bias_level; + codec->dai = &wm8903_dai; + codec->num_dai = 1; + codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache); + codec->reg_cache = &wm8903->reg_cache[0]; + codec->private_data = wm8903; + + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { dev_err(&i2c->dev, @@ -1581,36 +1613,12 @@ static int wm8903_init(struct snd_soc_device *socdev) return -ENODEV; } - codec->name = "WM8903"; - codec->owner = THIS_MODULE; - codec->read = wm8903_read; - codec->write = wm8903_write; - codec->bias_level = SND_SOC_BIAS_OFF; - codec->set_bias_level = wm8903_set_bias_level; - codec->dai = &wm8903_dai; - codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults); - codec->reg_cache = kmemdup(wm8903_reg_defaults, - sizeof(wm8903_reg_defaults), - GFP_KERNEL); - if (codec->reg_cache == NULL) { - dev_err(&i2c->dev, "Failed to allocate register cache\n"); - return -ENOMEM; - } - val = wm8903_read(codec, WM8903_REVISION_NUMBER); dev_info(&i2c->dev, "WM8903 revision %d\n", val & WM8903_CHIP_REV_MASK); wm8903_reset(codec); - /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(&i2c->dev, "failed to create pcms\n"); - goto pcm_err; - } - /* SYSCLK is required for pretty much anything */ wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); @@ -1648,47 +1656,45 @@ static int wm8903_init(struct snd_soc_device *socdev) val |= WM8903_DAC_MUTEMODE; wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); - wm8903_add_controls(codec); - wm8903_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&i2c->dev, "wm8903: failed to register card\n"); - goto card_err; + wm8903_dai.dev = &i2c->dev; + wm8903_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&wm8903_dai); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; } return ret; -card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -static struct snd_soc_device *wm8903_socdev; - -static int wm8903_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct snd_soc_device *socdev = wm8903_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; - - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = wm8903_init(socdev); - if (ret < 0) - dev_err(&i2c->dev, "Device initialisation failed\n"); - +err_codec: + snd_soc_unregister_codec(codec); +err: + wm8903_codec = NULL; + kfree(wm8903); return ret; } static int wm8903_i2c_remove(struct i2c_client *client) { struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); + + snd_soc_unregister_dai(&wm8903_dai); + snd_soc_unregister_codec(codec); + + wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); + + kfree(codec->private_data); + + wm8903_codec = NULL; + wm8903_dai.dev = NULL; + return 0; } @@ -1712,75 +1718,37 @@ static struct i2c_driver wm8903_i2c_driver = { static int wm8903_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8903_setup_data *setup; - struct snd_soc_codec *codec; - struct wm8903_priv *wm8903; - struct i2c_board_info board_info; - struct i2c_adapter *adapter; - struct i2c_client *i2c_client; int ret = 0; - setup = socdev->codec_data; - - if (!setup->i2c_address) { - dev_err(&pdev->dev, "No codec address provided\n"); - return -ENODEV; + if (!wm8903_codec) { + dev_err(&pdev->dev, "I2C device not yet probed\n"); + goto err; } - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; + socdev->codec = wm8903_codec; - wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); - if (wm8903 == NULL) { - ret = -ENOMEM; - goto err_codec; + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to create pcms\n"); + goto err; } - codec->private_data = wm8903; - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); + wm8903_add_controls(socdev->codec); + wm8903_add_widgets(socdev->codec); - wm8903_socdev = socdev; - - codec->hw_write = (hw_write_t)i2c_master_send; - ret = i2c_add_driver(&wm8903_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - goto err_priv; - } else { - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE); - board_info.addr = setup->i2c_address; - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "Can't get I2C bus %d\n", - setup->i2c_bus); - ret = -ENODEV; - goto err_adapter; - } - - i2c_client = i2c_new_device(adapter, &board_info); - i2c_put_adapter(adapter); - if (i2c_client == NULL) { - dev_err(&pdev->dev, - "I2C driver registration failed\n"); - ret = -ENODEV; - goto err_adapter; - } + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "wm8903: failed to register card\n"); + goto card_err; } return ret; -err_adapter: - i2c_del_driver(&wm8903_i2c_driver); -err_priv: - kfree(codec->private_data); -err_codec: - kfree(codec); +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +err: return ret; } @@ -1795,10 +1763,6 @@ static int wm8903_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); - i2c_unregister_device(socdev->codec->control_data); - i2c_del_driver(&wm8903_i2c_driver); - kfree(codec->private_data); - kfree(codec); return 0; } @@ -1813,13 +1777,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903); static int __init wm8903_modinit(void) { - return snd_soc_register_dai(&wm8903_dai); + return i2c_add_driver(&wm8903_i2c_driver); } module_init(wm8903_modinit); static void __exit wm8903_exit(void) { - snd_soc_unregister_dai(&wm8903_dai); + i2c_del_driver(&wm8903_i2c_driver); } module_exit(wm8903_exit); diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h index cec622f2f660..0ea27e2b9963 100644 --- a/sound/soc/codecs/wm8903.h +++ b/sound/soc/codecs/wm8903.h @@ -18,11 +18,6 @@ extern struct snd_soc_dai wm8903_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8903; -struct wm8903_setup_data { - int i2c_bus; - int i2c_address; -}; - #define WM8903_MCLK_DIV_2 1 #define WM8903_CLK_SYS 2 #define WM8903_BCLK 3 From 3b1228abc93f7ab0aa28c46341d6a0f7e2cade70 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Dec 2008 19:27:10 +0000 Subject: [PATCH 318/367] ASoC: Stop WM8903 SYSCLK when suspending This will save some additional power. Signed-off-by: Mark Brown --- sound/soc/codecs/wm8903.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c80968fe326e..bde74546db4a 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -997,6 +997,9 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { + wm8903_write(codec, WM8903_CLOCK_RATES_2, + WM8903_CLK_SYS_ENA); + wm8903_run_sequence(codec, 0); wm8903_sync_reg_cache(codec, codec->reg_cache); @@ -1027,6 +1030,9 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: wm8903_run_sequence(codec, 32); + reg = wm8903_read(codec, WM8903_CLOCK_RATES_2); + reg &= ~WM8903_CLK_SYS_ENA; + wm8903_write(codec, WM8903_CLOCK_RATES_2, reg); break; } @@ -1619,9 +1625,6 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, wm8903_reset(codec); - /* SYSCLK is required for pretty much anything */ - wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); - /* power on device */ wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); From 623b9f6738dee0394398564a74fdabbff00f506f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 07:44:18 +0100 Subject: [PATCH 319/367] ALSA: hda - Update HD-Audio.txt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed typos and added a section about codecgraph. Thanks to Vedran Miletić and Daniel T Chen for suggestions. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index ca8187de52d8..ee9117eee1aa 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -266,7 +266,7 @@ submit the improvement patch to the author. Direct Debugging ~~~~~~~~~~~~~~~~ If no model option gives you a better result, and you are a touch guy -to fight again the evil, try debugging via hitting the raw HD-audio +to fight against evil, try debugging via hitting the raw HD-audio codec verbs to the device. Some tools are available: hda-emu and hda-analyzer. The detailed description is found in the sections below. You'd need to enable hwdep for using these tools. See "Kernel @@ -389,7 +389,7 @@ power-down/up depending on the device. Some of them might be solvable, but some are hard, I'm afraid. Some distros such as openSUSE enables the power-saving feature automatically when the power cable is unplugged. Thus, if you hear noises, suspect first the -power-saving. See /sys/modules/snd_hda_intel/parameters/power_save to +power-saving. See /sys/module/snd_hda_intel/parameters/power_save to check the current value. If it's non-zero, the feature is turned on. @@ -503,6 +503,19 @@ alsa-project.org: - http://git.alsa-project.org/?p=alsa.git;a=tree;f=hda-analyzer +Codecgraph +~~~~~~~~~~ +Codecgraph is a utility program to generate a graph and visualizes the +codec-node connection of a codec chip. It's especially useful when +you analyze or debug a codec without a proper datasheet. The program +parses the given codec proc file and converts to SVG via graphiz +program. + +The tarball and GIT trees are found in the web page at: + +- http://helllabs.org/codecgraph/ + + hda-emu ~~~~~~~ hda-emu is an HD-audio emulator. The main purpose of this program is From 6de45d5d776d2a7e7a9adc8ea49d37fe1bd45fb2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 10:28:18 +0100 Subject: [PATCH 320/367] ALSA: ASoC - Fix DAI registration in s3c2443-ac97.c Fixed the registration of dais in s3c2443-ac97.c. sound/soc/s3c24xx/s3c2443-ac97.c: In function 's3c2443_ac97_init': sound/soc/s3c24xx/s3c2443-ac97.c:401: warning: passing argument 1 of 'snd_soc_register_dai' from incompatible pointer type sound/soc/s3c24xx/s3c2443-ac97.c: In function 's3c2443_ac97_exit': sound/soc/s3c24xx/s3c2443-ac97.c:407: warning: passing argument 1 of 'snd_soc_unregister_dai' from incompatible pointer type Signed-off-by: Takashi Iwai --- sound/soc/s3c24xx/s3c2443-ac97.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 723779a3058d..1bfce40bb2e4 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c @@ -398,13 +398,15 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops); static int __init s3c2443_ac97_init(void) { - return snd_soc_register_dai(&s3c2443_ac97_dai); + return snd_soc_register_dais(s3c2443_ac97_dai, + ARRAY_SIZE(s3c2443_ac97_dai)); } module_init(s3c2443_ac97_init); static void __exit s3c2443_ac97_exit(void) { - snd_soc_unregister_dai(&s3c2443_ac97_dai); + snd_soc_unregister_dais(s3c2443_ac97_dai, + ARRAY_SIZE(s3c2443_ac97_dai)); } module_exit(s3c2443_ac97_exit); From 5c0b9bec460c348d2ee5a800c288e5d0e8fcda66 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 11:47:17 +0100 Subject: [PATCH 321/367] ALSA: hda - Fix a compile warning when CONFIG_PM=n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed the compile warning regarding the unused function when built with CONFIG_PM=n: sound/pci/hda/hda_intel.c:1905: warning: ‘snd_hda_codecs_inuse’ defined but not used snd_hda_codecs_inuse() is used only in the resume callback. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 8aee322313ed..f2337e4eddda 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1900,6 +1900,12 @@ static void azx_power_notify(struct hda_bus *bus) else if (chip->running && power_save_controller) azx_stop_chip(chip); } +#endif /* CONFIG_SND_HDA_POWER_SAVE */ + +#ifdef CONFIG_PM +/* + * power management + */ static int snd_hda_codecs_inuse(struct hda_bus *bus) { @@ -1911,14 +1917,7 @@ static int snd_hda_codecs_inuse(struct hda_bus *bus) } return 0; } -#else /* !CONFIG_SND_HDA_POWER_SAVE */ -#define snd_hda_codecs_inuse(bus) 1 -#endif /* CONFIG_SND_HDA_POWER_SAVE */ -#ifdef CONFIG_PM -/* - * power management - */ static int azx_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); From 42a73df435a23e60d97d9d860f4e55dc9833e950 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 12:12:06 +0100 Subject: [PATCH 322/367] ALSA: sb8 - Fix a return code in the error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed a compile warning below: sound/isa/sb/sb8.c: In function ‘snd_sb8_probe’: sound/isa/sb/sb8.c:104: warning: ‘err’ may be used uninitialized in this function by setting the return value correctly. Signed-off-by: Takashi Iwai --- sound/isa/sb/sb8.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index 667eccc676a4..ea06877be4b1 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -140,8 +140,10 @@ static int __devinit snd_sb8_probe(struct device *pdev, unsigned int dev) break; } } - if (i >= ARRAY_SIZE(possible_ports)) + if (i >= ARRAY_SIZE(possible_ports)) { + err = -EINVAL; goto _err; + } } acard->chip = chip; From f8bbd06b17f16984328398cdecdf9302ef9bb0bf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 13:12:59 +0100 Subject: [PATCH 323/367] ALSA: hda - Fix another typo in HD-Audio.txt --- Documentation/sound/alsa/HD-Audio.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index ee9117eee1aa..2e4d031ea1fa 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -265,7 +265,7 @@ submit the improvement patch to the author. Direct Debugging ~~~~~~~~~~~~~~~~ -If no model option gives you a better result, and you are a touch guy +If no model option gives you a better result, and you are a tough guy to fight against evil, try debugging via hitting the raw HD-audio codec verbs to the device. Some tools are available: hda-emu and hda-analyzer. The detailed description is found in the sections From 132bb7c0efe82fc976b06d557f5d63536cb9fdaa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 11 Dec 2008 15:39:52 +0100 Subject: [PATCH 324/367] ALSA: hda - Add development tree URLs in HD-audio.txt Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 2e4d031ea1fa..642a2b012541 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -393,6 +393,28 @@ power-saving. See /sys/module/snd_hda_intel/parameters/power_save to check the current value. If it's non-zero, the feature is turned on. +Development Tree +~~~~~~~~~~~~~~~~ +The latest development codes for HD-audio are found on sound git tree: + +- git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git + +The master branch or for-next branches can be used as the main +development branches in general while the HD-audio specific patches +are committed in topic/hda branch. + +If you are using the latest Linus tree, it'd be better to pull the +above GIT tree onto it. If you are using the older kernels, an easy +way to try the latest ALSA code is to build from the snapshot +tarball. There are daily tarballs and the latest snapshot tarball. +All can be built just like normal alsa-driver release packages, that +is, installed via the usual spells: configure, make and make +install(-modules). See INSTALL in the package. The snapshot tarballs +are found at: + +- ftp://ftp.kernel.org/pub/linux/kernel/people/tiwai/snapshot/ + + Sending a Bug Report ~~~~~~~~~~~~~~~~~~~~ If any model or module options don't work for your device, it's time From 4544f8a22f38ba4560320fcfbe8c7e81562ddc6f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Dec 2008 16:11:38 +0000 Subject: [PATCH 325/367] ASoC: Fix variable name for Blackfin I2S DAI Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index c17b131f6626..d1d95d2393fe 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c @@ -315,13 +315,13 @@ EXPORT_SYMBOL_GPL(bf5xx_i2s_dai); static int __init bfin_i2s_init(void) { - return snd_soc_register_dai(&bfin_i2s_dai); + return snd_soc_register_dai(&bf5xx_i2s_dai); } module_init(bfin_i2s_init); static void __exit bfin_i2s_exit(void) { - snd_soc_unregister_dai(&bfin_i2s_dai); + snd_soc_unregister_dai(&bf5xx_i2s_dai); } module_exit(bfin_i2s_exit); From 49d92c7d5bbd158734bc34ed578a68b214a48583 Mon Sep 17 00:00:00 2001 From: "Stanley.Miao" Date: Thu, 11 Dec 2008 23:28:10 +0800 Subject: [PATCH 326/367] ASoC: TWL4030: hands-free start-up sequence. A special start-up sequence is required to reduce the pop-noise of Class D amplifier when enable hands-free on TWL4030. Signed-off-by: Stanley.Miao Signed-off-by: Mark Brown --- sound/soc/codecs/twl4030.c | 34 ++++++++++++++++++++++++++++++---- sound/soc/codecs/twl4030.h | 6 ++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 13773028f6f1..51848880504a 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -322,6 +322,30 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, return ret; } +static int handsfree_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value; + unsigned char hs_ctl; + + hs_ctl = twl4030_read_reg_cache(w->codec, e->reg); + + if (hs_ctl & TWL4030_HF_CTL_REF_EN) { + hs_ctl |= TWL4030_HF_CTL_RAMP_EN; + twl4030_write(w->codec, e->reg, hs_ctl); + hs_ctl |= TWL4030_HF_CTL_LOOP_EN; + twl4030_write(w->codec, e->reg, hs_ctl); + hs_ctl |= TWL4030_HF_CTL_HB_EN; + twl4030_write(w->codec, e->reg, hs_ctl); + } else { + hs_ctl &= ~(TWL4030_HF_CTL_RAMP_EN | TWL4030_HF_CTL_LOOP_EN + | TWL4030_HF_CTL_HB_EN); + twl4030_write(w->codec, e->reg, hs_ctl); + } + + return 0; +} + /* * Some of the gain controls in TWL (mostly those which are associated with * the outputs) are implemented in an interesting way: @@ -806,10 +830,12 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_MUX("CarkitR Mux", SND_SOC_NOPM, 0, 0, &twl4030_dapm_carkitr_control), /* HandsfreeL/R */ - SND_SOC_DAPM_MUX("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, - &twl4030_dapm_handsfreel_control), - SND_SOC_DAPM_MUX("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, - &twl4030_dapm_handsfreer_control), + SND_SOC_DAPM_MUX_E("HandsfreeL Mux", TWL4030_REG_HFL_CTL, 5, 0, + &twl4030_dapm_handsfreel_control, handsfree_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("HandsfreeR Mux", TWL4030_REG_HFR_CTL, 5, 0, + &twl4030_dapm_handsfreer_control, handsfree_event, + SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0), diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index a2065d417c2e..54615c76802b 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h @@ -191,6 +191,12 @@ #define TWL4030_RAMP_DELAY_2581MS 0x1C #define TWL4030_RAMP_EN 0x02 +/* HFL_CTL (0x29, 0x2A) Fields */ +#define TWL4030_HF_CTL_HB_EN 0x04 +#define TWL4030_HF_CTL_LOOP_EN 0x08 +#define TWL4030_HF_CTL_RAMP_EN 0x10 +#define TWL4030_HF_CTL_REF_EN 0x20 + /* APLL_CTL (0x3A) Fields */ #define TWL4030_APLL_EN 0x10 From 9cd28ab0051cc5232e3dffea6b318233445a3d5f Mon Sep 17 00:00:00 2001 From: Alexander Beregalov Date: Sat, 13 Dec 2008 16:25:27 +0300 Subject: [PATCH 327/367] ASoC: switch davinci DPRINTK to pr_debug() Signed-off-by: Alexander Beregalov Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-pcm.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index bc83e1cbd176..74abc9b4f1cc 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,13 +25,6 @@ #include "davinci-pcm.h" -#define DAVINCI_PCM_DEBUG 0 -#if DAVINCI_PCM_DEBUG -#define DPRINTK(x...) printk(KERN_DEBUG x) -#else -#define DPRINTK(x...) -#endif - static struct snd_pcm_hardware davinci_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -78,8 +72,8 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset; - DPRINTK("audio_set_dma_params_play channel = %d dma_ptr = %x " - "period_size=%x\n", lch, dma_pos, period_size); + pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " + "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size); data_type = prtd->params->data_type; count = period_size / data_type; @@ -112,7 +106,7 @@ static void davinci_pcm_dma_irq(int lch, u16 ch_status, void *data) struct snd_pcm_substream *substream = data; struct davinci_runtime_data *prtd = substream->runtime->private_data; - DPRINTK("lch=%d, status=0x%x\n", lch, ch_status); + pr_debug("davinci_pcm: lch=%d, status=0x%x\n", lch, ch_status); if (unlikely(ch_status != DMA_COMPLETE)) return; @@ -316,8 +310,8 @@ static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) buf->area = dma_alloc_writecombine(pcm->card->dev, size, &buf->addr, GFP_KERNEL); - DPRINTK("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, (void *) buf->addr, size); + pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, " + "size=%d\n", (void *) buf->area, (void *) buf->addr, size); if (!buf->area) return -ENOMEM; From 3d1ee379bd576c0830050c2d313e77b9f98a8013 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 15 Dec 2008 15:43:43 +0000 Subject: [PATCH 328/367] ALSA: Fix declaration of sound_class Include sound/core.h in sound_core.c so that sound_class is declared before it is defined, avoiding it looking like it should be static. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/sound_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/sound_core.c b/sound/sound_core.c index 10ba4218161b..2b302bbffe73 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef CONFIG_SOUND_OSS_CORE static int __init init_oss_soundcore(void); From 31117b78ee843622cbc4c7c17c97be417c766385 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Dec 2008 14:43:21 +0100 Subject: [PATCH 329/367] ALSA: hda - Add Nvidia vendor id string Added Nvidia (0x10de) to the vendor id list. Cleaned up the codec name strings accordingly. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/patch_nvhdmi.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d49d0b698687..f6832e160684 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -46,6 +46,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1002, "ATI" }, { 0x1057, "Motorola" }, { 0x1095, "Silicon Image" }, + { 0x10de, "Nvidia" }, { 0x10ec, "Realtek" }, { 0x1106, "VIA" }, { 0x111d, "IDT" }, diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 0cd53063e62e..0270fda0bda5 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -159,9 +159,9 @@ static int patch_nvhdmi(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { - { .id = 0x10de0002, .name = "NVIDIA MCP78 HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de0007, .name = "NVIDIA MCP7A HDMI", .patch = patch_nvhdmi }, - { .id = 0x10de0067, .name = "NVIDIA MCP67 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, + { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, {} /* terminator */ }; From f649a7145b8b67121e8be0b50f7861755f21aa3b Mon Sep 17 00:00:00 2001 From: Ben Stanley Date: Fri, 12 Dec 2008 09:47:13 +1100 Subject: [PATCH 330/367] ALSA: ca0106 Add comments to snd_ca0106_details struct Takashi wrote an email [1] explaining the fields of snd_ca0106_details, so I captured the information into the ca0106.h header file. [1] http://article.gmane.org/gmane.linux.alsa.devel/56783/match=takashi+gpio_type Signed-off-by: Ben Stanley Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 74175fc80c7f..3faccb6ecad9 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -664,10 +664,14 @@ struct snd_ca0106_pcm { struct snd_ca0106_details { u32 serial; char * name; - int ac97; - int gpio_type; - int i2c_adc; - int spi_dac; + int ac97; /* ac97 = 0 -> Select MIC, Line in, TAD in, AUX in. + ac97 = 1 -> Default to AC97 in. */ + int gpio_type; /* gpio_type = 1 -> shared mic-in/line-in + gpio_type = 2 -> shared side-out/line-in. */ + int i2c_adc; /* with i2c_adc=1, the driver adds some capture volume + controls, phone, mic, line-in and aux. */ + int spi_dac; /* spi_dac=1 adds the mute switch for each analog + output, front, rear, etc. */ }; // definition of the chip-specific record From bb1f24bf00a85f666b56a09b7cdbfd221af16c2c Mon Sep 17 00:00:00 2001 From: Ben Stanley Date: Mon, 15 Dec 2008 23:38:12 +1100 Subject: [PATCH 331/367] ALSA: ca0106 MSI K8N Diamond MB spi_dac 2->1 This patch removes an inconsistency that became apparent when I documented the fields of snd_ca0106_details. spi_dac is always used in a 'boolean' sense, so this cleanup should make no difference. [Actually, there is one place checking explicitly spi_dac == 1, so this will change the behavior. But, supposing it's rather a typo, I apply this clean-up patch -- tiwai] Signed-off-by: Ben Stanley Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 88fbf285d2b7..6ac19364631b 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -254,7 +254,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { .name = "MSI K8N Diamond MB", .gpio_type = 2, .i2c_adc = 1, - .spi_dac = 2 } , + .spi_dac = 1 } , /* Shuttle XPC SD31P which has an onboard Creative Labs * Sound Blaster Live! 24-bit EAX * high-definition 7.1 audio processor". From 74c611334ff131f2b87c7634314bde9e7fd98653 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 18 Dec 2008 09:11:33 +0100 Subject: [PATCH 332/367] ALSA: hda - Add Intel vendor id string Added Intel codec vendor id string (0x8086). Also fixed Intel-HDMI codec name strings, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + sound/pci/hda/patch_intelhdmi.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f6832e160684..8459d6ba2055 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -58,6 +58,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x1854, "LG" }, { 0x1aec, "Wolfson Microelectronics" }, { 0x434d, "C-Media" }, + { 0x8086, "Intel" }, { 0x8384, "SigmaTel" }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 290da562f29b..3564f4e4b74c 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -675,10 +675,10 @@ static int patch_intel_hdmi(struct hda_codec *codec) } static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { - { .id = 0x808629fb, .name = "INTEL G45 DEVCL", .patch = patch_intel_hdmi }, - { .id = 0x80862801, .name = "INTEL G45 DEVBLC", .patch = patch_intel_hdmi }, - { .id = 0x80862802, .name = "INTEL G45 DEVCTG", .patch = patch_intel_hdmi }, - { .id = 0x80862803, .name = "INTEL G45 DEVELK", .patch = patch_intel_hdmi }, + { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, + { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, + { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, + { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; From 3218c178b41b420cb7e0d120c7a137a3969242e5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 18 Dec 2008 09:17:56 +0100 Subject: [PATCH 333/367] ALSA: hda - Remove duplicated strings from codec name Remove codec vendor names from the codec name strings. The vendor name is already given from the vendor name table, so displayed doubly. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_atihdmi.c | 8 ++-- sound/pci/hda/patch_via.c | 72 +++++++++++++++++------------------ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index 5887b827bb32..233e4778bba9 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c @@ -187,10 +187,10 @@ static int patch_atihdmi(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_atihdmi[] = { - { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, - { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, - { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, - { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, + { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, + { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, + { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, + { .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_atihdmi }, { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_atihdmi }, {} /* terminator */ diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6e4d01d1d502..c761394cbe84 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -3249,73 +3249,73 @@ static int patch_vt1702(struct hda_codec *codec) * patch entries */ static struct hda_codec_preset snd_hda_preset_via[] = { - { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, - { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", + { .id = 0x11061708, .name = "VT1708", .patch = patch_vt1708}, + { .id = 0x11061709, .name = "VT1708", .patch = patch_vt1708}, + { .id = 0x1106170a, .name = "VT1708", .patch = patch_vt1708}, + { .id = 0x1106170b, .name = "VT1708", .patch = patch_vt1708}, + { .id = 0x1106e710, .name = "VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", + { .id = 0x1106e711, .name = "VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", + { .id = 0x1106e712, .name = "VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", + { .id = 0x1106e713, .name = "VT1709 10-Ch", .patch = patch_vt1709_10ch}, - { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", + { .id = 0x1106e714, .name = "VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", + { .id = 0x1106e715, .name = "VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", + { .id = 0x1106e716, .name = "VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", + { .id = 0x1106e717, .name = "VT1709 6-Ch", .patch = patch_vt1709_6ch}, - { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch", + { .id = 0x1106e720, .name = "VT1708B 8-Ch", .patch = patch_vt1708B_8ch}, - { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch", + { .id = 0x1106e721, .name = "VT1708B 8-Ch", .patch = patch_vt1708B_8ch}, - { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch", + { .id = 0x1106e722, .name = "VT1708B 8-Ch", .patch = patch_vt1708B_8ch}, - { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch", + { .id = 0x1106e723, .name = "VT1708B 8-Ch", .patch = patch_vt1708B_8ch}, - { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch", + { .id = 0x1106e724, .name = "VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, - { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch", + { .id = 0x1106e725, .name = "VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, - { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch", + { .id = 0x1106e726, .name = "VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, - { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", + { .id = 0x1106e727, .name = "VT1708B 4-Ch", .patch = patch_vt1708B_4ch}, - { .id = 0x11060397, .name = "VIA VT1708S", + { .id = 0x11060397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11061397, .name = "VIA VT1708S", + { .id = 0x11061397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11062397, .name = "VIA VT1708S", + { .id = 0x11062397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11063397, .name = "VIA VT1708S", + { .id = 0x11063397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11064397, .name = "VIA VT1708S", + { .id = 0x11064397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11065397, .name = "VIA VT1708S", + { .id = 0x11065397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11066397, .name = "VIA VT1708S", + { .id = 0x11066397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11067397, .name = "VIA VT1708S", + { .id = 0x11067397, .name = "VT1708S", .patch = patch_vt1708S}, - { .id = 0x11060398, .name = "VIA VT1702", + { .id = 0x11060398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11061398, .name = "VIA VT1702", + { .id = 0x11061398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11062398, .name = "VIA VT1702", + { .id = 0x11062398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11063398, .name = "VIA VT1702", + { .id = 0x11063398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11064398, .name = "VIA VT1702", + { .id = 0x11064398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11065398, .name = "VIA VT1702", + { .id = 0x11065398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11066398, .name = "VIA VT1702", + { .id = 0x11066398, .name = "VT1702", .patch = patch_vt1702}, - { .id = 0x11067398, .name = "VIA VT1702", + { .id = 0x11067398, .name = "VT1702", .patch = patch_vt1702}, {} /* terminator */ }; From 1f04128a3db7c0f0e8b5d25323eba70ac342f47f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 18 Dec 2008 12:17:55 +0100 Subject: [PATCH 334/367] ALSA: hda - Convert from takslet_hi_schedule() to tasklet_schedule() Replace all tasklet_hi_schedule() callers with the normal tasklet_schedule(). The former often causes troubles with RT-kernels, and has actually no merit. Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 4 ++-- sound/core/rtctimer.c | 2 +- sound/core/timer.c | 2 +- sound/drivers/vx/vx_core.c | 2 +- sound/drivers/vx/vx_pcm.c | 2 +- sound/pci/es1968.c | 2 +- sound/pci/maestro3.c | 2 +- sound/pci/mixart/mixart_core.c | 2 +- sound/pci/pcxhr/pcxhr.c | 2 +- sound/pci/pcxhr/pcxhr_core.c | 2 +- sound/pci/riptide/riptide.c | 2 +- sound/pci/rme9652/hdsp.c | 2 +- sound/pci/rme9652/hdspm.c | 2 +- sound/pcmcia/pdaudiocf/pdaudiocf_irq.c | 2 +- sound/usb/usbmidi.c | 2 +- 15 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 39672f68ce5d..002777ba336a 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -151,7 +151,7 @@ static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *subs if (!substream->opened) return; if (up) { - tasklet_hi_schedule(&substream->runtime->tasklet); + tasklet_schedule(&substream->runtime->tasklet); } else { tasklet_kill(&substream->runtime->tasklet); substream->ops->trigger(substream, 0); @@ -908,7 +908,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, } if (result > 0) { if (runtime->event) - tasklet_hi_schedule(&runtime->tasklet); + tasklet_schedule(&runtime->tasklet); else if (snd_rawmidi_ready(substream)) wake_up(&runtime->sleep); } diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c index 51e64e30dd3b..0851cd13e303 100644 --- a/sound/core/rtctimer.c +++ b/sound/core/rtctimer.c @@ -118,7 +118,7 @@ static void rtctimer_tasklet(unsigned long data) */ static void rtctimer_interrupt(void *private_data) { - tasklet_hi_schedule(private_data); + tasklet_schedule(private_data); } diff --git a/sound/core/timer.c b/sound/core/timer.c index c584408c9f17..796532081e81 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -743,7 +743,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) spin_unlock_irqrestore(&timer->lock, flags); if (use_tasklet) - tasklet_hi_schedule(&timer->task_queue); + tasklet_schedule(&timer->task_queue); } /* diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index 473b07f6ae85..14e3354be43a 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -548,7 +548,7 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev) (chip->chip_status & VX_STAT_IS_STALE)) return IRQ_NONE; if (! vx_test_and_ack(chip)) - tasklet_hi_schedule(&chip->tq); + tasklet_schedule(&chip->tq); return IRQ_HANDLED; } diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 27de574c08f7..6644d0034fba 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -823,7 +823,7 @@ static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd) * we trigger the pipe using tasklet, so that the interrupts are * issued surely after the trigger is completed. */ - tasklet_hi_schedule(&pipe->start_tq); + tasklet_schedule(&pipe->start_tq); chip->pcm_running++; pipe->running = 1; break; diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 20ee7599600b..e9c3794bbcb8 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -1953,7 +1953,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); if (event & ESM_HWVOL_IRQ) - tasklet_hi_schedule(&chip->hwvol_tq); /* we'll do this later */ + tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */ /* else ack 'em all, i imagine */ outb(0xFF, chip->io_port + 0x1A); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 9ff3f9e34404..59bbaf8f3e5b 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -1670,7 +1670,7 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) return IRQ_NONE; if (status & HV_INT_PENDING) - tasklet_hi_schedule(&chip->hwvol_tq); + tasklet_schedule(&chip->hwvol_tq); /* * ack an assp int if its running diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index b9a06c279397..d3350f383966 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -550,7 +550,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; mgr->msg_fifo_writeptr++; mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; - tasklet_hi_schedule(&mgr->msg_taskq); + tasklet_schedule(&mgr->msg_taskq); } spin_unlock(&mgr->msg_lock); break; diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 73de6e989b3d..8309d4487722 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -653,7 +653,7 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd) PCXHR_STREAM_STATUS_SCHEDULE_RUN; snd_pcm_trigger_done(s, subs); } - tasklet_hi_schedule(&chip->mgr->trigger_taskq); + tasklet_schedule(&chip->mgr->trigger_taskq); } else { stream = subs->runtime->private_data; snd_printdd("Only one Substream %c %d\n", diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 7143259cfe34..4a5481f9781f 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -1213,7 +1213,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID; mgr->src_it_dsp = reg; - tasklet_hi_schedule(&mgr->msg_taskq); + tasklet_schedule(&mgr->msg_taskq); } #ifdef CONFIG_SND_DEBUG_VERBOSE if (reg & PCXHR_FATAL_DSP_ERR) diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index e9f0706ed3e4..1d0eeb1f506c 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1754,7 +1754,7 @@ snd_riptide_interrupt(int irq, void *dev_id) if (IS_EOBIRQ(cif->hwport) || IS_EOSIRQ(cif->hwport) || IS_EOCIRQ(cif->hwport)) { chip->handled_irqs++; - tasklet_hi_schedule(&chip->riptide_tq); + tasklet_schedule(&chip->riptide_tq); } if (chip->rmidi && IS_MPUIRQ(cif->hwport)) { chip->handled_irqs++; diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 736246f98acc..f87ff0497116 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -3750,7 +3750,7 @@ static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id) } } if (hdsp->use_midi_tasklet && schedule) - tasklet_hi_schedule(&hdsp->midi_tasklet); + tasklet_schedule(&hdsp->midi_tasklet); return IRQ_HANDLED; } diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 98762f909d64..d7dd53675ccd 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3476,7 +3476,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) schedule = 1; } if (schedule) - tasklet_hi_schedule(&hdspm->midi_tasklet); + tasklet_schedule(&hdspm->midi_tasklet); return IRQ_HANDLED; } diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c index fa4b11398b1f..ea903c8e90dd 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c @@ -41,7 +41,7 @@ irqreturn_t pdacf_interrupt(int irq, void *dev) if (stat & PDAUDIOCF_IRQOVR) /* should never happen */ snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n"); if (chip->pcm_substream) - tasklet_hi_schedule(&chip->tq); + tasklet_schedule(&chip->tq); if (!(stat & PDAUDIOCF_IRQAKM)) stat |= PDAUDIOCF_IRQAKM; /* check rate */ } diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 5962e4b84423..6d9f9b135c62 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -880,7 +880,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, snd_rawmidi_transmit_ack(substream, 1); return; } - tasklet_hi_schedule(&port->ep->tasklet); + tasklet_schedule(&port->ep->tasklet); } } From 0b34a3d03e2fa615a786027b1ef4cbbd8c807f2c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Dec 2008 14:44:48 +0000 Subject: [PATCH 335/367] ASoC: Ease merge difficulties from new architectures Rather than listing lots of architectures per line in Kconfig and Makefile, causing merge conflicts all the time, have one per line in alphabetical order. Signed-off-by: Mark Brown --- sound/soc/Kconfig | 10 +++++----- sound/soc/Makefile | 12 ++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 615ebf0b76e7..ef025c66cc66 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -22,16 +22,16 @@ if SND_SOC config SND_SOC_AC97_BUS bool -# All the supported Soc's +# All the supported SoCs source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" +source "sound/soc/blackfin/Kconfig" +source "sound/soc/davinci/Kconfig" +source "sound/soc/fsl/Kconfig" +source "sound/soc/omap/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/s3c24xx/Kconfig" source "sound/soc/sh/Kconfig" -source "sound/soc/fsl/Kconfig" -source "sound/soc/davinci/Kconfig" -source "sound/soc/omap/Kconfig" -source "sound/soc/blackfin/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 4d475c3ceb91..86a9b1f5b0f3 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,5 +1,13 @@ snd-soc-core-objs := soc-core.o soc-dapm.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o -obj-$(CONFIG_SND_SOC) += codecs/ atmel/ pxa/ s3c24xx/ sh/ fsl/ davinci/ -obj-$(CONFIG_SND_SOC) += omap/ au1x/ blackfin/ +obj-$(CONFIG_SND_SOC) += codecs/ +obj-$(CONFIG_SND_SOC) += atmel/ +obj-$(CONFIG_SND_SOC) += au1x/ +obj-$(CONFIG_SND_SOC) += blackfin/ +obj-$(CONFIG_SND_SOC) += davinci/ +obj-$(CONFIG_SND_SOC) += fsl/ +obj-$(CONFIG_SND_SOC) += omap/ +obj-$(CONFIG_SND_SOC) += pxa/ +obj-$(CONFIG_SND_SOC) += s3c24xx/ +obj-$(CONFIG_SND_SOC) += sh/ From b8b33cb5608a3bb1b072548dc89159ef614096ab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 18 Dec 2008 11:19:30 +0000 Subject: [PATCH 336/367] ASoC: Complain if we fail to create DAPM controls This should never happen and it's helpful to identify the specific control that failed when it does happen. Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 61d7d85aa578..8863eddbac02 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1320,8 +1320,12 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, for (i = 0; i < num; i++) { ret = snd_soc_dapm_new_control(codec, widget); - if (ret < 0) + if (ret < 0) { + printk(KERN_ERR + "ASoC: Failed to create DAPM control %s: %d\n", + widget->name, ret); return ret; + } widget++; } return 0; From 40aa4a30d0fd075fb934de4ee8163056827052ab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 16 Dec 2008 10:15:12 +0000 Subject: [PATCH 337/367] ASoC: Add WM8350 AudioPlus codec driver The WM8350 is an integrated audio and power management subsystem which provides a single-chip solution for portable audio and multimedia systems. The integrated audio CODEC provides all the necessary functions for high-quality stereo recording and playback. Programmable on-chip amplifiers allow for the direct connection of headphones and microphones with a minimum of external components. A programmable low-noise bias voltage is available to feed one or more electret microphones. Additional audio features include programmable high-pass filter in the ADC input path. This driver was originally written by Liam Girdwood with further updates from me. Signed-off-by: Mark Brown --- include/linux/mfd/wm8350/audio.h | 38 +- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wm8350.c | 1583 ++++++++++++++++++++++++++++++ sound/soc/codecs/wm8350.h | 20 + 5 files changed, 1643 insertions(+), 4 deletions(-) create mode 100644 sound/soc/codecs/wm8350.c create mode 100644 sound/soc/codecs/wm8350.h diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h index 217bb22ebb8e..af95a1d2f3a1 100644 --- a/include/linux/mfd/wm8350/audio.h +++ b/include/linux/mfd/wm8350/audio.h @@ -1,7 +1,7 @@ /* * audio.h -- Audio Driver for Wolfson WM8350 PMIC * - * Copyright 2007 Wolfson Microelectronics PLC + * Copyright 2007, 2008 Wolfson Microelectronics PLC * * 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 @@ -70,9 +70,9 @@ #define WM8350_CODEC_ISEL_0_5 3 /* x0.5 */ #define WM8350_VMID_OFF 0 -#define WM8350_VMID_500K 1 -#define WM8350_VMID_100K 2 -#define WM8350_VMID_10K 3 +#define WM8350_VMID_300K 1 +#define WM8350_VMID_50K 2 +#define WM8350_VMID_5K 3 /* * R40 (0x28) - Clock Control 1 @@ -591,8 +591,38 @@ #define WM8350_IRQ_CODEC_MICSCD 41 #define WM8350_IRQ_CODEC_MICD 42 +/* + * WM8350 Platform data. + * + * This must be initialised per platform for best audio performance. + * Please see WM8350 datasheet for information. + */ +struct wm8350_audio_platform_data { + int vmid_discharge_msecs; /* VMID --> OFF discharge time */ + int drain_msecs; /* OFF drain time */ + int cap_discharge_msecs; /* Cap ON (from OFF) discharge time */ + int vmid_charge_msecs; /* vmid power up time */ + u32 vmid_s_curve:2; /* vmid enable s curve speed */ + u32 dis_out4:2; /* out4 discharge speed */ + u32 dis_out3:2; /* out3 discharge speed */ + u32 dis_out2:2; /* out2 discharge speed */ + u32 dis_out1:2; /* out1 discharge speed */ + u32 vroi_out4:1; /* out4 tie off */ + u32 vroi_out3:1; /* out3 tie off */ + u32 vroi_out2:1; /* out2 tie off */ + u32 vroi_out1:1; /* out1 tie off */ + u32 vroi_enable:1; /* enable tie off */ + u32 codec_current_on:2; /* current level ON */ + u32 codec_current_standby:2; /* current level STANDBY */ + u32 codec_current_charge:2; /* codec current @ vmid charge */ +}; + +struct snd_soc_codec; + struct wm8350_codec { struct platform_device *pdev; + struct snd_soc_codec *codec; + struct wm8350_audio_platform_data *platform_data; }; #endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bf68052d6924..c41289b5f586 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -13,6 +13,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TWL4030 if TWL4030_CORE select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C + select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8510 if (I2C || SPI_MASTER) select SND_SOC_WM8580 if I2C select SND_SOC_WM8728 if (I2C || SPI_MASTER) @@ -100,6 +101,9 @@ config SND_SOC_UDA134X config SND_SOC_UDA1380 tristate +config SND_SOC_WM8350 + tristate + config SND_SOC_WM8510 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 9a20fddd09c7..c4ddc9aa2bbd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -12,6 +12,7 @@ snd-soc-tlv320aic3x-objs := tlv320aic3x.o snd-soc-twl4030-objs := twl4030.o snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o +snd-soc-wm8350-objs := wm8350.o snd-soc-wm8510-objs := wm8510.o snd-soc-wm8580-objs := wm8580.o snd-soc-wm8728-objs := wm8728.o @@ -39,6 +40,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o +obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c new file mode 100644 index 000000000000..4bbfb5a5894b --- /dev/null +++ b/sound/soc/codecs/wm8350.c @@ -0,0 +1,1583 @@ +/* + * wm8350.c -- WM8350 ALSA SoC audio driver + * + * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC. + * + * Author: Liam Girdwood + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm8350.h" + +#define WM8350_OUTn_0dB 0x39 + +#define WM8350_RAMP_NONE 0 +#define WM8350_RAMP_UP 1 +#define WM8350_RAMP_DOWN 2 + +/* We only include the analogue supplies here; the digital supplies + * need to be available well before this driver can be probed. + */ +static const char *supply_names[] = { + "AVDD", + "HPVDD", +}; + +struct wm8350_output { + u16 active; + u16 left_vol; + u16 right_vol; + u16 ramp; + u16 mute; +}; + +struct wm8350_data { + struct snd_soc_codec codec; + struct wm8350_output out1; + struct wm8350_output out2; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; +}; + +static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct wm8350 *wm8350 = codec->control_data; + return wm8350->reg_cache[reg]; +} + +static unsigned int wm8350_codec_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + struct wm8350 *wm8350 = codec->control_data; + return wm8350_reg_read(wm8350, reg); +} + +static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct wm8350 *wm8350 = codec->control_data; + return wm8350_reg_write(wm8350, reg, value); +} + +/* + * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown. + */ +static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec) +{ + struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_output *out1 = &wm8350_data->out1; + struct wm8350 *wm8350 = codec->control_data; + int left_complete = 0, right_complete = 0; + u16 reg, val; + + /* left channel */ + reg = wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME); + val = (reg & WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; + + if (out1->ramp == WM8350_RAMP_UP) { + /* ramp step up */ + if (val < out1->left_vol) { + val++; + reg &= ~WM8350_OUT1L_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, + reg | (val << WM8350_OUT1L_VOL_SHIFT)); + } else + left_complete = 1; + } else if (out1->ramp == WM8350_RAMP_DOWN) { + /* ramp step down */ + if (val > 0) { + val--; + reg &= ~WM8350_OUT1L_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, + reg | (val << WM8350_OUT1L_VOL_SHIFT)); + } else + left_complete = 1; + } else + return 1; + + /* right channel */ + reg = wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME); + val = (reg & WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; + if (out1->ramp == WM8350_RAMP_UP) { + /* ramp step up */ + if (val < out1->right_vol) { + val++; + reg &= ~WM8350_OUT1R_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, + reg | (val << WM8350_OUT1R_VOL_SHIFT)); + } else + right_complete = 1; + } else if (out1->ramp == WM8350_RAMP_DOWN) { + /* ramp step down */ + if (val > 0) { + val--; + reg &= ~WM8350_OUT1R_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, + reg | (val << WM8350_OUT1R_VOL_SHIFT)); + } else + right_complete = 1; + } + + /* only hit the update bit if either volume has changed this step */ + if (!left_complete || !right_complete) + wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, WM8350_OUT1_VU); + + return left_complete & right_complete; +} + +/* + * Ramp OUT2 PGA volume to minimise pops at stream startup and shutdown. + */ +static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec) +{ + struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_output *out2 = &wm8350_data->out2; + struct wm8350 *wm8350 = codec->control_data; + int left_complete = 0, right_complete = 0; + u16 reg, val; + + /* left channel */ + reg = wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME); + val = (reg & WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; + if (out2->ramp == WM8350_RAMP_UP) { + /* ramp step up */ + if (val < out2->left_vol) { + val++; + reg &= ~WM8350_OUT2L_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, + reg | (val << WM8350_OUT1L_VOL_SHIFT)); + } else + left_complete = 1; + } else if (out2->ramp == WM8350_RAMP_DOWN) { + /* ramp step down */ + if (val > 0) { + val--; + reg &= ~WM8350_OUT2L_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, + reg | (val << WM8350_OUT1L_VOL_SHIFT)); + } else + left_complete = 1; + } else + return 1; + + /* right channel */ + reg = wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME); + val = (reg & WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; + if (out2->ramp == WM8350_RAMP_UP) { + /* ramp step up */ + if (val < out2->right_vol) { + val++; + reg &= ~WM8350_OUT2R_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, + reg | (val << WM8350_OUT1R_VOL_SHIFT)); + } else + right_complete = 1; + } else if (out2->ramp == WM8350_RAMP_DOWN) { + /* ramp step down */ + if (val > 0) { + val--; + reg &= ~WM8350_OUT2R_VOL_MASK; + wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, + reg | (val << WM8350_OUT1R_VOL_SHIFT)); + } else + right_complete = 1; + } + + /* only hit the update bit if either volume has changed this step */ + if (!left_complete || !right_complete) + wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, WM8350_OUT2_VU); + + return left_complete & right_complete; +} + +/* + * This work ramps both output PGAs at stream start/stop time to + * minimise pop associated with DAPM power switching. + * It's best to enable Zero Cross when ramping occurs to minimise any + * zipper noises. + */ +static void wm8350_pga_work(struct work_struct *work) +{ + struct snd_soc_codec *codec = + container_of(work, struct snd_soc_codec, delayed_work.work); + struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_output *out1 = &wm8350_data->out1, + *out2 = &wm8350_data->out2; + int i, out1_complete, out2_complete; + + /* do we need to ramp at all ? */ + if (out1->ramp == WM8350_RAMP_NONE && out2->ramp == WM8350_RAMP_NONE) + return; + + /* PGA volumes have 6 bits of resolution to ramp */ + for (i = 0; i <= 63; i++) { + out1_complete = 1, out2_complete = 1; + if (out1->ramp != WM8350_RAMP_NONE) + out1_complete = wm8350_out1_ramp_step(codec); + if (out2->ramp != WM8350_RAMP_NONE) + out2_complete = wm8350_out2_ramp_step(codec); + + /* ramp finished ? */ + if (out1_complete && out2_complete) + break; + + /* we need to delay longer on the up ramp */ + if (out1->ramp == WM8350_RAMP_UP || + out2->ramp == WM8350_RAMP_UP) { + /* delay is longer over 0dB as increases are larger */ + if (i >= WM8350_OUTn_0dB) + schedule_timeout_interruptible(msecs_to_jiffies + (2)); + else + schedule_timeout_interruptible(msecs_to_jiffies + (1)); + } else + udelay(50); /* doesn't matter if we delay longer */ + } + + out1->ramp = WM8350_RAMP_NONE; + out2->ramp = WM8350_RAMP_NONE; +} + +/* + * WM8350 Controls + */ + +static int pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_output *out; + + switch (w->shift) { + case 0: + case 1: + out = &wm8350_data->out1; + break; + case 2: + case 3: + out = &wm8350_data->out2; + break; + + default: + BUG(); + return -1; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + out->ramp = WM8350_RAMP_UP; + out->active = 1; + + if (!delayed_work_pending(&codec->delayed_work)) + schedule_delayed_work(&codec->delayed_work, + msecs_to_jiffies(1)); + break; + + case SND_SOC_DAPM_PRE_PMD: + out->ramp = WM8350_RAMP_DOWN; + out->active = 0; + + if (!delayed_work_pending(&codec->delayed_work)) + schedule_delayed_work(&codec->delayed_work, + msecs_to_jiffies(1)); + break; + } + + return 0; +} + +static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8350_data *wm8350_priv = codec->private_data; + struct wm8350_output *out = NULL; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int ret; + unsigned int reg = mc->reg; + u16 val; + + /* For OUT1 and OUT2 we shadow the values and only actually write + * them out when active in order to ensure the amplifier comes on + * as quietly as possible. */ + switch (reg) { + case WM8350_LOUT1_VOLUME: + out = &wm8350_priv->out1; + break; + case WM8350_LOUT2_VOLUME: + out = &wm8350_priv->out2; + break; + default: + break; + } + + if (out) { + out->left_vol = ucontrol->value.integer.value[0]; + out->right_vol = ucontrol->value.integer.value[1]; + if (!out->active) + return 1; + } + + ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); + if (ret < 0) + return ret; + + /* now hit the volume update bits (always bit 8) */ + val = wm8350_codec_read(codec, reg); + wm8350_codec_write(codec, reg, val | WM8350_OUT1_VU); + return 1; +} + +static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8350_data *wm8350_priv = codec->private_data; + struct wm8350_output *out1 = &wm8350_priv->out1; + struct wm8350_output *out2 = &wm8350_priv->out2; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int reg = mc->reg; + + /* If these are cached registers use the cache */ + switch (reg) { + case WM8350_LOUT1_VOLUME: + ucontrol->value.integer.value[0] = out1->left_vol; + ucontrol->value.integer.value[1] = out1->right_vol; + return 0; + + case WM8350_LOUT2_VOLUME: + ucontrol->value.integer.value[0] = out2->left_vol; + ucontrol->value.integer.value[1] = out2->right_vol; + return 0; + + default: + break; + } + + return snd_soc_get_volsw_2r(kcontrol, ucontrol); +} + +/* double control with volume update */ +#define SOC_WM8350_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, \ + xinvert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_2r, \ + .get = wm8350_get_volsw_2r, .put = wm8350_put_volsw_2r_vu, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ + .rshift = xshift, .max = xmax, .invert = xinvert}, } + +static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; +static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" }; +static const char *wm8350_dacmutem[] = { "Normal", "Soft" }; +static const char *wm8350_dacmutes[] = { "Fast", "Slow" }; +static const char *wm8350_dacfilter[] = { "Normal", "Sloping" }; +static const char *wm8350_adcfilter[] = { "None", "High Pass" }; +static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" }; +static const char *wm8350_lr[] = { "Left", "Right" }; + +static const struct soc_enum wm8350_enum[] = { + SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 4, 4, wm8350_deemp), + SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol), + SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem), + SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes), + SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 12, 2, wm8350_dacfilter), + SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter), + SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp), + SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol), + SOC_ENUM_SINGLE(WM8350_INPUT_MIXER_VOLUME, 15, 2, wm8350_lr), +}; + +static DECLARE_TLV_DB_LINEAR(pre_amp_tlv, -1200, 3525); +static DECLARE_TLV_DB_LINEAR(out_pga_tlv, -5700, 600); +static DECLARE_TLV_DB_SCALE(dac_pcm_tlv, -7163, 36, 1); +static DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -12700, 50, 1); +static DECLARE_TLV_DB_SCALE(out_mix_tlv, -1500, 300, 1); + +static const unsigned int capture_sd_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 12, TLV_DB_SCALE_ITEM(-3600, 300, 1), + 13, 15, TLV_DB_SCALE_ITEM(0, 0, 0), +}; + +static const struct snd_kcontrol_new wm8350_snd_controls[] = { + SOC_ENUM("Playback Deemphasis", wm8350_enum[0]), + SOC_ENUM("Playback DAC Inversion", wm8350_enum[1]), + SOC_WM8350_DOUBLE_R_TLV("Playback PCM Volume", + WM8350_DAC_DIGITAL_VOLUME_L, + WM8350_DAC_DIGITAL_VOLUME_R, + 0, 255, 0, dac_pcm_tlv), + SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]), + SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]), + SOC_ENUM("Playback PCM Filter", wm8350_enum[4]), + SOC_ENUM("Capture PCM Filter", wm8350_enum[5]), + SOC_ENUM("Capture PCM HP Filter", wm8350_enum[6]), + SOC_ENUM("Capture ADC Inversion", wm8350_enum[7]), + SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume", + WM8350_ADC_DIGITAL_VOLUME_L, + WM8350_ADC_DIGITAL_VOLUME_R, + 0, 255, 0, adc_pcm_tlv), + SOC_DOUBLE_TLV("Capture Sidetone Volume", + WM8350_ADC_DIVIDER, + 8, 4, 15, 1, capture_sd_tlv), + SOC_WM8350_DOUBLE_R_TLV("Capture Volume", + WM8350_LEFT_INPUT_VOLUME, + WM8350_RIGHT_INPUT_VOLUME, + 2, 63, 0, pre_amp_tlv), + SOC_DOUBLE_R("Capture ZC Switch", + WM8350_LEFT_INPUT_VOLUME, + WM8350_RIGHT_INPUT_VOLUME, 13, 1, 0), + SOC_SINGLE_TLV("Left Input Left Sidetone Volume", + WM8350_OUTPUT_LEFT_MIXER_VOLUME, 1, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Left Input Right Sidetone Volume", + WM8350_OUTPUT_LEFT_MIXER_VOLUME, + 5, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Left Input Bypass Volume", + WM8350_OUTPUT_LEFT_MIXER_VOLUME, + 9, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Right Input Left Sidetone Volume", + WM8350_OUTPUT_RIGHT_MIXER_VOLUME, + 1, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Right Input Right Sidetone Volume", + WM8350_OUTPUT_RIGHT_MIXER_VOLUME, + 5, 7, 0, out_mix_tlv), + SOC_SINGLE_TLV("Right Input Bypass Volume", + WM8350_OUTPUT_RIGHT_MIXER_VOLUME, + 13, 7, 0, out_mix_tlv), + SOC_SINGLE("Left Input Mixer +20dB Switch", + WM8350_INPUT_MIXER_VOLUME_L, 0, 1, 0), + SOC_SINGLE("Right Input Mixer +20dB Switch", + WM8350_INPUT_MIXER_VOLUME_R, 0, 1, 0), + SOC_SINGLE_TLV("Out4 Capture Volume", + WM8350_INPUT_MIXER_VOLUME, + 1, 7, 0, out_mix_tlv), + SOC_WM8350_DOUBLE_R_TLV("Out1 Playback Volume", + WM8350_LOUT1_VOLUME, + WM8350_ROUT1_VOLUME, + 2, 63, 0, out_pga_tlv), + SOC_DOUBLE_R("Out1 Playback ZC Switch", + WM8350_LOUT1_VOLUME, + WM8350_ROUT1_VOLUME, 13, 1, 0), + SOC_WM8350_DOUBLE_R_TLV("Out2 Playback Volume", + WM8350_LOUT2_VOLUME, + WM8350_ROUT2_VOLUME, + 2, 63, 0, out_pga_tlv), + SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8350_LOUT2_VOLUME, + WM8350_ROUT2_VOLUME, 13, 1, 0), + SOC_SINGLE("Out2 Right Invert Switch", WM8350_ROUT2_VOLUME, 10, 1, 0), + SOC_SINGLE_TLV("Out2 Beep Volume", WM8350_BEEP_VOLUME, + 5, 7, 0, out_mix_tlv), + + SOC_DOUBLE_R("Out1 Playback Switch", + WM8350_LOUT1_VOLUME, + WM8350_ROUT1_VOLUME, + 14, 1, 1), + SOC_DOUBLE_R("Out2 Playback Switch", + WM8350_LOUT2_VOLUME, + WM8350_ROUT2_VOLUME, + 14, 1, 1), +}; + +/* + * DAPM Controls + */ + +/* Left Playback Mixer */ +static const struct snd_kcontrol_new wm8350_left_play_mixer_controls[] = { + SOC_DAPM_SINGLE("Playback Switch", + WM8350_LEFT_MIXER_CONTROL, 11, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", + WM8350_LEFT_MIXER_CONTROL, 2, 1, 0), + SOC_DAPM_SINGLE("Right Playback Switch", + WM8350_LEFT_MIXER_CONTROL, 12, 1, 0), + SOC_DAPM_SINGLE("Left Sidetone Switch", + WM8350_LEFT_MIXER_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("Right Sidetone Switch", + WM8350_LEFT_MIXER_CONTROL, 1, 1, 0), +}; + +/* Right Playback Mixer */ +static const struct snd_kcontrol_new wm8350_right_play_mixer_controls[] = { + SOC_DAPM_SINGLE("Playback Switch", + WM8350_RIGHT_MIXER_CONTROL, 12, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", + WM8350_RIGHT_MIXER_CONTROL, 3, 1, 0), + SOC_DAPM_SINGLE("Left Playback Switch", + WM8350_RIGHT_MIXER_CONTROL, 11, 1, 0), + SOC_DAPM_SINGLE("Left Sidetone Switch", + WM8350_RIGHT_MIXER_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("Right Sidetone Switch", + WM8350_RIGHT_MIXER_CONTROL, 1, 1, 0), +}; + +/* Out4 Mixer */ +static const struct snd_kcontrol_new wm8350_out4_mixer_controls[] = { + SOC_DAPM_SINGLE("Right Playback Switch", + WM8350_OUT4_MIXER_CONTROL, 12, 1, 0), + SOC_DAPM_SINGLE("Left Playback Switch", + WM8350_OUT4_MIXER_CONTROL, 11, 1, 0), + SOC_DAPM_SINGLE("Right Capture Switch", + WM8350_OUT4_MIXER_CONTROL, 9, 1, 0), + SOC_DAPM_SINGLE("Out3 Playback Switch", + WM8350_OUT4_MIXER_CONTROL, 2, 1, 0), + SOC_DAPM_SINGLE("Right Mixer Switch", + WM8350_OUT4_MIXER_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("Left Mixer Switch", + WM8350_OUT4_MIXER_CONTROL, 0, 1, 0), +}; + +/* Out3 Mixer */ +static const struct snd_kcontrol_new wm8350_out3_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", + WM8350_OUT3_MIXER_CONTROL, 11, 1, 0), + SOC_DAPM_SINGLE("Left Capture Switch", + WM8350_OUT3_MIXER_CONTROL, 8, 1, 0), + SOC_DAPM_SINGLE("Out4 Playback Switch", + WM8350_OUT3_MIXER_CONTROL, 3, 1, 0), + SOC_DAPM_SINGLE("Left Mixer Switch", + WM8350_OUT3_MIXER_CONTROL, 0, 1, 0), +}; + +/* Left Input Mixer */ +static const struct snd_kcontrol_new wm8350_left_capt_mixer_controls[] = { + SOC_DAPM_SINGLE_TLV("L2 Capture Volume", + WM8350_INPUT_MIXER_VOLUME_L, 1, 7, 0, out_mix_tlv), + SOC_DAPM_SINGLE_TLV("L3 Capture Volume", + WM8350_INPUT_MIXER_VOLUME_L, 9, 7, 0, out_mix_tlv), + SOC_DAPM_SINGLE("PGA Capture Switch", + WM8350_LEFT_INPUT_VOLUME, 14, 1, 0), +}; + +/* Right Input Mixer */ +static const struct snd_kcontrol_new wm8350_right_capt_mixer_controls[] = { + SOC_DAPM_SINGLE_TLV("L2 Capture Volume", + WM8350_INPUT_MIXER_VOLUME_R, 5, 7, 0, out_mix_tlv), + SOC_DAPM_SINGLE_TLV("L3 Capture Volume", + WM8350_INPUT_MIXER_VOLUME_R, 13, 7, 0, out_mix_tlv), + SOC_DAPM_SINGLE("PGA Capture Switch", + WM8350_RIGHT_INPUT_VOLUME, 14, 1, 0), +}; + +/* Left Mic Mixer */ +static const struct snd_kcontrol_new wm8350_left_mic_mixer_controls[] = { + SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 1, 1, 0), + SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 0, 1, 0), + SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 2, 1, 0), +}; + +/* Right Mic Mixer */ +static const struct snd_kcontrol_new wm8350_right_mic_mixer_controls[] = { + SOC_DAPM_SINGLE("INN Capture Switch", WM8350_INPUT_CONTROL, 9, 1, 0), + SOC_DAPM_SINGLE("INP Capture Switch", WM8350_INPUT_CONTROL, 8, 1, 0), + SOC_DAPM_SINGLE("IN2 Capture Switch", WM8350_INPUT_CONTROL, 10, 1, 0), +}; + +/* Beep Switch */ +static const struct snd_kcontrol_new wm8350_beep_switch_controls = +SOC_DAPM_SINGLE("Switch", WM8350_BEEP_VOLUME, 15, 1, 1); + +/* Out4 Capture Mux */ +static const struct snd_kcontrol_new wm8350_out4_capture_controls = +SOC_DAPM_ENUM("Route", wm8350_enum[8]); + +static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = { + + SND_SOC_DAPM_PGA("IN3R PGA", WM8350_POWER_MGMT_2, 11, 0, NULL, 0), + SND_SOC_DAPM_PGA("IN3L PGA", WM8350_POWER_MGMT_2, 10, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("Right Out2 PGA", WM8350_POWER_MGMT_3, 3, 0, NULL, + 0, pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Left Out2 PGA", WM8350_POWER_MGMT_3, 2, 0, NULL, 0, + pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Right Out1 PGA", WM8350_POWER_MGMT_3, 1, 0, NULL, + 0, pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Left Out1 PGA", WM8350_POWER_MGMT_3, 0, 0, NULL, 0, + pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_MIXER("Right Capture Mixer", WM8350_POWER_MGMT_2, + 7, 0, &wm8350_right_capt_mixer_controls[0], + ARRAY_SIZE(wm8350_right_capt_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left Capture Mixer", WM8350_POWER_MGMT_2, + 6, 0, &wm8350_left_capt_mixer_controls[0], + ARRAY_SIZE(wm8350_left_capt_mixer_controls)), + + SND_SOC_DAPM_MIXER("Out4 Mixer", WM8350_POWER_MGMT_2, 5, 0, + &wm8350_out4_mixer_controls[0], + ARRAY_SIZE(wm8350_out4_mixer_controls)), + + SND_SOC_DAPM_MIXER("Out3 Mixer", WM8350_POWER_MGMT_2, 4, 0, + &wm8350_out3_mixer_controls[0], + ARRAY_SIZE(wm8350_out3_mixer_controls)), + + SND_SOC_DAPM_MIXER("Right Playback Mixer", WM8350_POWER_MGMT_2, 1, 0, + &wm8350_right_play_mixer_controls[0], + ARRAY_SIZE(wm8350_right_play_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left Playback Mixer", WM8350_POWER_MGMT_2, 0, 0, + &wm8350_left_play_mixer_controls[0], + ARRAY_SIZE(wm8350_left_play_mixer_controls)), + + SND_SOC_DAPM_MIXER("Left Mic Mixer", WM8350_POWER_MGMT_2, 8, 0, + &wm8350_left_mic_mixer_controls[0], + ARRAY_SIZE(wm8350_left_mic_mixer_controls)), + + SND_SOC_DAPM_MIXER("Right Mic Mixer", WM8350_POWER_MGMT_2, 9, 0, + &wm8350_right_mic_mixer_controls[0], + ARRAY_SIZE(wm8350_right_mic_mixer_controls)), + + /* virtual mixer for Beep and Out2R */ + SND_SOC_DAPM_MIXER("Out2 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Beep", WM8350_POWER_MGMT_3, 7, 0, + &wm8350_beep_switch_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", + WM8350_POWER_MGMT_4, 3, 0), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", + WM8350_POWER_MGMT_4, 2, 0), + SND_SOC_DAPM_DAC("Right DAC", "Right Playback", + WM8350_POWER_MGMT_4, 5, 0), + SND_SOC_DAPM_DAC("Left DAC", "Left Playback", + WM8350_POWER_MGMT_4, 4, 0), + + SND_SOC_DAPM_MICBIAS("Mic Bias", WM8350_POWER_MGMT_1, 4, 0), + + SND_SOC_DAPM_MUX("Out4 Capture Channel", SND_SOC_NOPM, 0, 0, + &wm8350_out4_capture_controls), + + SND_SOC_DAPM_OUTPUT("OUT1R"), + SND_SOC_DAPM_OUTPUT("OUT1L"), + SND_SOC_DAPM_OUTPUT("OUT2R"), + SND_SOC_DAPM_OUTPUT("OUT2L"), + SND_SOC_DAPM_OUTPUT("OUT3"), + SND_SOC_DAPM_OUTPUT("OUT4"), + + SND_SOC_DAPM_INPUT("IN1RN"), + SND_SOC_DAPM_INPUT("IN1RP"), + SND_SOC_DAPM_INPUT("IN2R"), + SND_SOC_DAPM_INPUT("IN1LP"), + SND_SOC_DAPM_INPUT("IN1LN"), + SND_SOC_DAPM_INPUT("IN2L"), + SND_SOC_DAPM_INPUT("IN3R"), + SND_SOC_DAPM_INPUT("IN3L"), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + + /* left playback mixer */ + {"Left Playback Mixer", "Playback Switch", "Left DAC"}, + {"Left Playback Mixer", "Left Bypass Switch", "IN3L PGA"}, + {"Left Playback Mixer", "Right Playback Switch", "Right DAC"}, + {"Left Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"}, + {"Left Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"}, + + /* right playback mixer */ + {"Right Playback Mixer", "Playback Switch", "Right DAC"}, + {"Right Playback Mixer", "Right Bypass Switch", "IN3R PGA"}, + {"Right Playback Mixer", "Left Playback Switch", "Left DAC"}, + {"Right Playback Mixer", "Left Sidetone Switch", "Left Mic Mixer"}, + {"Right Playback Mixer", "Right Sidetone Switch", "Right Mic Mixer"}, + + /* out4 playback mixer */ + {"Out4 Mixer", "Right Playback Switch", "Right DAC"}, + {"Out4 Mixer", "Left Playback Switch", "Left DAC"}, + {"Out4 Mixer", "Right Capture Switch", "Right Capture Mixer"}, + {"Out4 Mixer", "Out3 Playback Switch", "Out3 Mixer"}, + {"Out4 Mixer", "Right Mixer Switch", "Right Playback Mixer"}, + {"Out4 Mixer", "Left Mixer Switch", "Left Playback Mixer"}, + {"OUT4", NULL, "Out4 Mixer"}, + + /* out3 playback mixer */ + {"Out3 Mixer", "Left Playback Switch", "Left DAC"}, + {"Out3 Mixer", "Left Capture Switch", "Left Capture Mixer"}, + {"Out3 Mixer", "Left Mixer Switch", "Left Playback Mixer"}, + {"Out3 Mixer", "Out4 Playback Switch", "Out4 Mixer"}, + {"OUT3", NULL, "Out3 Mixer"}, + + /* out2 */ + {"Right Out2 PGA", NULL, "Right Playback Mixer"}, + {"Left Out2 PGA", NULL, "Left Playback Mixer"}, + {"OUT2L", NULL, "Left Out2 PGA"}, + {"OUT2R", NULL, "Right Out2 PGA"}, + + /* out1 */ + {"Right Out1 PGA", NULL, "Right Playback Mixer"}, + {"Left Out1 PGA", NULL, "Left Playback Mixer"}, + {"OUT1L", NULL, "Left Out1 PGA"}, + {"OUT1R", NULL, "Right Out1 PGA"}, + + /* ADCs */ + {"Left ADC", NULL, "Left Capture Mixer"}, + {"Right ADC", NULL, "Right Capture Mixer"}, + + /* Left capture mixer */ + {"Left Capture Mixer", "L2 Capture Volume", "IN2L"}, + {"Left Capture Mixer", "L3 Capture Volume", "IN3L PGA"}, + {"Left Capture Mixer", "PGA Capture Switch", "Left Mic Mixer"}, + {"Left Capture Mixer", NULL, "Out4 Capture Channel"}, + + /* Right capture mixer */ + {"Right Capture Mixer", "L2 Capture Volume", "IN2R"}, + {"Right Capture Mixer", "L3 Capture Volume", "IN3R PGA"}, + {"Right Capture Mixer", "PGA Capture Switch", "Right Mic Mixer"}, + {"Right Capture Mixer", NULL, "Out4 Capture Channel"}, + + /* L3 Inputs */ + {"IN3L PGA", NULL, "IN3L"}, + {"IN3R PGA", NULL, "IN3R"}, + + /* Left Mic mixer */ + {"Left Mic Mixer", "INN Capture Switch", "IN1LN"}, + {"Left Mic Mixer", "INP Capture Switch", "IN1LP"}, + {"Left Mic Mixer", "IN2 Capture Switch", "IN2L"}, + + /* Right Mic mixer */ + {"Right Mic Mixer", "INN Capture Switch", "IN1RN"}, + {"Right Mic Mixer", "INP Capture Switch", "IN1RP"}, + {"Right Mic Mixer", "IN2 Capture Switch", "IN2R"}, + + /* out 4 capture */ + {"Out4 Capture Channel", NULL, "Out4 Mixer"}, + + /* Beep */ + {"Beep", NULL, "IN3R PGA"}, +}; + +static int wm8350_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8350_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8350_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + + return 0; +} + +static int wm8350_add_widgets(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_dapm_new_controls(codec, + wm8350_dapm_widgets, + ARRAY_SIZE(wm8350_dapm_widgets)); + if (ret != 0) { + dev_err(codec->dev, "dapm control register failed\n"); + return ret; + } + + /* set up audio paths */ + ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + if (ret != 0) { + dev_err(codec->dev, "DAPM route register failed\n"); + return ret; + } + + return snd_soc_dapm_new_widgets(codec); +} + +static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8350 *wm8350 = codec->control_data; + u16 fll_4; + + switch (clk_id) { + case WM8350_MCLK_SEL_MCLK: + wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_1, + WM8350_MCLK_SEL); + break; + case WM8350_MCLK_SEL_PLL_MCLK: + case WM8350_MCLK_SEL_PLL_DAC: + case WM8350_MCLK_SEL_PLL_ADC: + case WM8350_MCLK_SEL_PLL_32K: + wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1, + WM8350_MCLK_SEL); + fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & + ~WM8350_FLL_CLK_SRC_MASK; + wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id); + break; + } + + /* MCLK direction */ + if (dir == WM8350_MCLK_DIR_OUT) + wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_2, + WM8350_MCLK_DIR); + else + wm8350_clear_bits(wm8350, WM8350_CLOCK_CONTROL_2, + WM8350_MCLK_DIR); + + return 0; +} + +static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 val; + + switch (div_id) { + case WM8350_ADC_CLKDIV: + val = wm8350_codec_read(codec, WM8350_ADC_DIVIDER) & + ~WM8350_ADC_CLKDIV_MASK; + wm8350_codec_write(codec, WM8350_ADC_DIVIDER, val | div); + break; + case WM8350_DAC_CLKDIV: + val = wm8350_codec_read(codec, WM8350_DAC_CLOCK_CONTROL) & + ~WM8350_DAC_CLKDIV_MASK; + wm8350_codec_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div); + break; + case WM8350_BCLK_CLKDIV: + val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) & + ~WM8350_BCLK_DIV_MASK; + wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div); + break; + case WM8350_OPCLK_CLKDIV: + val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) & + ~WM8350_OPCLK_DIV_MASK; + wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div); + break; + case WM8350_SYS_CLKDIV: + val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) & + ~WM8350_MCLK_DIV_MASK; + wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div); + break; + case WM8350_DACLR_CLKDIV: + val = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) & + ~WM8350_DACLRC_RATE_MASK; + wm8350_codec_write(codec, WM8350_DAC_LR_RATE, val | div); + break; + case WM8350_ADCLR_CLKDIV: + val = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) & + ~WM8350_ADCLRC_RATE_MASK; + wm8350_codec_write(codec, WM8350_ADC_LR_RATE, val | div); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) & + ~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK); + u16 master = wm8350_codec_read(codec, WM8350_AI_DAC_CONTROL) & + ~WM8350_BCLK_MSTR; + u16 dac_lrc = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) & + ~WM8350_DACLRC_ENA; + u16 adc_lrc = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) & + ~WM8350_ADCLRC_ENA; + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + master |= WM8350_BCLK_MSTR; + dac_lrc |= WM8350_DACLRC_ENA; + adc_lrc |= WM8350_ADCLRC_ENA; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + iface |= 0x2 << 8; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + iface |= 0x1 << 8; + break; + case SND_SOC_DAIFMT_DSP_A: + iface |= 0x3 << 8; + break; + case SND_SOC_DAIFMT_DSP_B: + iface |= 0x3 << 8; /* lg not sure which mode */ + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= WM8350_AIF_LRCLK_INV | WM8350_AIF_BCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= WM8350_AIF_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + iface |= WM8350_AIF_LRCLK_INV; + break; + default: + return -EINVAL; + } + + wm8350_codec_write(codec, WM8350_AI_FORMATING, iface); + wm8350_codec_write(codec, WM8350_AI_DAC_CONTROL, master); + wm8350_codec_write(codec, WM8350_DAC_LR_RATE, dac_lrc); + wm8350_codec_write(codec, WM8350_ADC_LR_RATE, adc_lrc); + return 0; +} + +static int wm8350_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int master = wm8350_codec_cache_read(codec, WM8350_AI_DAC_CONTROL) & + WM8350_BCLK_MSTR; + int enabled = 0; + + /* Check that the DACs or ADCs are enabled since they are + * required for LRC in master mode. The DACs or ADCs need a + * valid audio path i.e. pin -> ADC or DAC -> pin before + * the LRC will be enabled in master mode. */ + if (!master && cmd != SNDRV_PCM_TRIGGER_START) + return 0; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) & + (WM8350_ADCR_ENA | WM8350_ADCL_ENA); + } else { + enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) & + (WM8350_DACR_ENA | WM8350_DACL_ENA); + } + + if (!enabled) { + dev_err(codec->dev, + "%s: invalid audio path - no clocks available\n", + __func__); + return -EINVAL; + } + return 0; +} + +static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) & + ~WM8350_AIF_WL_MASK; + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= 0x1 << 10; + break; + case SNDRV_PCM_FORMAT_S24_LE: + iface |= 0x2 << 10; + break; + case SNDRV_PCM_FORMAT_S32_LE: + iface |= 0x3 << 10; + break; + } + + wm8350_codec_write(codec, WM8350_AI_FORMATING, iface); + return 0; +} + +static int wm8350_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8350 *wm8350 = codec->control_data; + + if (mute) + wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA); + else + wm8350_clear_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA); + return 0; +} + +/* FLL divisors */ +struct _fll_div { + int div; /* FLL_OUTDIV */ + int n; + int k; + int ratio; /* FLL_FRATIO */ +}; + +/* The size in bits of the fll divide multiplied by 10 + * to allow rounding later */ +#define FIXED_FLL_SIZE ((1 << 16) * 10) + +static inline int fll_factors(struct _fll_div *fll_div, unsigned int input, + unsigned int output) +{ + u64 Kpart; + unsigned int t1, t2, K, Nmod; + + if (output >= 2815250 && output <= 3125000) + fll_div->div = 0x4; + else if (output >= 5625000 && output <= 6250000) + fll_div->div = 0x3; + else if (output >= 11250000 && output <= 12500000) + fll_div->div = 0x2; + else if (output >= 22500000 && output <= 25000000) + fll_div->div = 0x1; + else { + printk(KERN_ERR "wm8350: fll freq %d out of range\n", output); + return -EINVAL; + } + + if (input > 48000) + fll_div->ratio = 1; + else + fll_div->ratio = 8; + + t1 = output * (1 << (fll_div->div + 1)); + t2 = input * fll_div->ratio; + + fll_div->n = t1 / t2; + Nmod = t1 % t2; + + if (Nmod) { + Kpart = FIXED_FLL_SIZE * (long long)Nmod; + do_div(Kpart, t2); + K = Kpart & 0xFFFFFFFF; + + /* Check if we need to round */ + if ((K % 10) >= 5) + K += 5; + + /* Move down to proper range now rounding is done */ + K /= 10; + fll_div->k = K; + } else + fll_div->k = 0; + + return 0; +} + +static int wm8350_set_fll(struct snd_soc_dai *codec_dai, + int pll_id, unsigned int freq_in, + unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8350 *wm8350 = codec->control_data; + struct _fll_div fll_div; + int ret = 0; + u16 fll_1, fll_4; + + /* power down FLL - we need to do this for reconfiguration */ + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, + WM8350_FLL_ENA | WM8350_FLL_OSC_ENA); + + if (freq_out == 0 || freq_in == 0) + return ret; + + ret = fll_factors(&fll_div, freq_in, freq_out); + if (ret < 0) + return ret; + dev_dbg(wm8350->dev, + "FLL in %d FLL out %d N 0x%x K 0x%x div %d ratio %d", + freq_in, freq_out, fll_div.n, fll_div.k, fll_div.div, + fll_div.ratio); + + /* set up N.K & dividers */ + fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) & + ~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000); + wm8350_codec_write(codec, WM8350_FLL_CONTROL_1, + fll_1 | (fll_div.div << 8) | 0x50); + wm8350_codec_write(codec, WM8350_FLL_CONTROL_2, + (fll_div.ratio << 11) | (fll_div. + n & WM8350_FLL_N_MASK)); + wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k); + fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) & + ~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF); + wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, + fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) | + (fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0)); + + /* power FLL on */ + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA); + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA); + + return 0; +} + +static int wm8350_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct wm8350 *wm8350 = codec->control_data; + struct wm8350_data *priv = codec->private_data; + struct wm8350_audio_platform_data *platform = + wm8350->codec.platform_data; + u16 pm1; + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1 | WM8350_VMID_50K | + platform->codec_current_on << 14); + break; + + case SND_SOC_BIAS_PREPARE: + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1); + pm1 &= ~WM8350_VMID_MASK; + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1 | WM8350_VMID_50K); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret != 0) + return ret; + + /* Enable the system clock */ + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, + WM8350_SYSCLK_ENA); + + /* mute DAC & outputs */ + wm8350_set_bits(wm8350, WM8350_DAC_MUTE, + WM8350_DAC_MUTE_ENA); + + /* discharge cap memory */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, + platform->dis_out1 | + (platform->dis_out2 << 2) | + (platform->dis_out3 << 4) | + (platform->dis_out4 << 6)); + + /* wait for discharge */ + schedule_timeout_interruptible(msecs_to_jiffies + (platform-> + cap_discharge_msecs)); + + /* enable antipop */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, + (platform->vmid_s_curve << 8)); + + /* ramp up vmid */ + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + (platform-> + codec_current_charge << 14) | + WM8350_VMID_5K | WM8350_VMIDEN | + WM8350_VBUFEN); + + /* wait for vmid */ + schedule_timeout_interruptible(msecs_to_jiffies + (platform-> + vmid_charge_msecs)); + + /* turn on vmid 300k */ + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK); + pm1 |= WM8350_VMID_300K | + (platform->codec_current_standby << 14); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1); + + + /* enable analogue bias */ + pm1 |= WM8350_BIASEN; + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1); + + /* disable antipop */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0); + + } else { + /* turn on vmid 300k and reduce current */ + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~(WM8350_VMID_MASK | WM8350_CODEC_ISEL_MASK); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1 | WM8350_VMID_300K | + (platform-> + codec_current_standby << 14)); + + } + break; + + case SND_SOC_BIAS_OFF: + + /* mute DAC & enable outputs */ + wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA); + + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_3, + WM8350_OUT1L_ENA | WM8350_OUT1R_ENA | + WM8350_OUT2L_ENA | WM8350_OUT2R_ENA); + + /* enable anti pop S curve */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, + (platform->vmid_s_curve << 8)); + + /* turn off vmid */ + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~WM8350_VMIDEN; + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1); + + /* wait */ + schedule_timeout_interruptible(msecs_to_jiffies + (platform-> + vmid_discharge_msecs)); + + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, + (platform->vmid_s_curve << 8) | + platform->dis_out1 | + (platform->dis_out2 << 2) | + (platform->dis_out3 << 4) | + (platform->dis_out4 << 6)); + + /* turn off VBuf and drain */ + pm1 = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_1) & + ~(WM8350_VBUFEN | WM8350_VMID_MASK); + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, + pm1 | WM8350_OUTPUT_DRAIN_EN); + + /* wait */ + schedule_timeout_interruptible(msecs_to_jiffies + (platform->drain_msecs)); + + pm1 &= ~WM8350_BIASEN; + wm8350_reg_write(wm8350, WM8350_POWER_MGMT_1, pm1); + + /* disable anti-pop */ + wm8350_reg_write(wm8350, WM8350_ANTI_POP_CONTROL, 0); + + wm8350_clear_bits(wm8350, WM8350_LOUT1_VOLUME, + WM8350_OUT1L_ENA); + wm8350_clear_bits(wm8350, WM8350_ROUT1_VOLUME, + WM8350_OUT1R_ENA); + wm8350_clear_bits(wm8350, WM8350_LOUT2_VOLUME, + WM8350_OUT2L_ENA); + wm8350_clear_bits(wm8350, WM8350_ROUT2_VOLUME, + WM8350_OUT2R_ENA); + + /* disable clock gen */ + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, + WM8350_SYSCLK_ENA); + + regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + priv->supplies); + break; + } + codec->bias_level = level; + return 0; +} + +static int wm8350_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int wm8350_resume(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + + wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + if (codec->suspend_bias_level == SND_SOC_BIAS_ON) + wm8350_set_bias_level(codec, SND_SOC_BIAS_ON); + + return 0; +} + +static struct snd_soc_codec *wm8350_codec; + +static int wm8350_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + struct wm8350 *wm8350; + struct wm8350_data *priv; + int ret; + struct wm8350_output *out1; + struct wm8350_output *out2; + + BUG_ON(!wm8350_codec); + + socdev->codec = wm8350_codec; + codec = socdev->codec; + wm8350 = codec->control_data; + priv = codec->private_data; + + /* Enable the codec */ + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); + + /* Enable robust clocking mode in ADC */ + wm8350_codec_write(codec, WM8350_SECURITY, 0xa7); + wm8350_codec_write(codec, 0xde, 0x13); + wm8350_codec_write(codec, WM8350_SECURITY, 0); + + /* read OUT1 & OUT2 volumes */ + out1 = &priv->out1; + out2 = &priv->out2; + out1->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT1_VOLUME) & + WM8350_OUT1L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; + out1->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT1_VOLUME) & + WM8350_OUT1R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; + out2->left_vol = (wm8350_reg_read(wm8350, WM8350_LOUT2_VOLUME) & + WM8350_OUT2L_VOL_MASK) >> WM8350_OUT1L_VOL_SHIFT; + out2->right_vol = (wm8350_reg_read(wm8350, WM8350_ROUT2_VOLUME) & + WM8350_OUT2R_VOL_MASK) >> WM8350_OUT1R_VOL_SHIFT; + wm8350_reg_write(wm8350, WM8350_LOUT1_VOLUME, 0); + wm8350_reg_write(wm8350, WM8350_ROUT1_VOLUME, 0); + wm8350_reg_write(wm8350, WM8350_LOUT2_VOLUME, 0); + wm8350_reg_write(wm8350, WM8350_ROUT2_VOLUME, 0); + + /* Latch VU bits & mute */ + wm8350_set_bits(wm8350, WM8350_LOUT1_VOLUME, + WM8350_OUT1_VU | WM8350_OUT1L_MUTE); + wm8350_set_bits(wm8350, WM8350_LOUT2_VOLUME, + WM8350_OUT2_VU | WM8350_OUT2L_MUTE); + wm8350_set_bits(wm8350, WM8350_ROUT1_VOLUME, + WM8350_OUT1_VU | WM8350_OUT1R_MUTE); + wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, + WM8350_OUT2_VU | WM8350_OUT2R_MUTE); + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to create pcms\n"); + return ret; + } + + wm8350_add_controls(codec); + wm8350_add_widgets(codec); + + wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register card\n"); + goto card_err; + } + + return 0; + +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + return ret; +} + +static int wm8350_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = socdev->codec; + struct wm8350 *wm8350 = codec->control_data; + int ret; + + /* cancel any work waiting to be queued. */ + ret = cancel_delayed_work(&codec->delayed_work); + + /* if there was any work waiting then we run it now and + * wait for its completion */ + if (ret) { + schedule_delayed_work(&codec->delayed_work, 0); + flush_scheduled_work(); + } + + wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); + + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); + + return 0; +} + +#define WM8350_RATES (SNDRV_PCM_RATE_8000_96000) + +#define WM8350_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +struct snd_soc_dai wm8350_dai = { + .name = "WM8350", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = WM8350_RATES, + .formats = WM8350_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8350_RATES, + .formats = WM8350_FORMATS, + }, + .ops = { + .hw_params = wm8350_pcm_hw_params, + .digital_mute = wm8350_mute, + .trigger = wm8350_pcm_trigger, + .set_fmt = wm8350_set_dai_fmt, + .set_sysclk = wm8350_set_dai_sysclk, + .set_pll = wm8350_set_fll, + .set_clkdiv = wm8350_set_clkdiv, + }, +}; +EXPORT_SYMBOL_GPL(wm8350_dai); + +struct snd_soc_codec_device soc_codec_dev_wm8350 = { + .probe = wm8350_probe, + .remove = wm8350_remove, + .suspend = wm8350_suspend, + .resume = wm8350_resume, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8350); + +static int wm8350_codec_probe(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = platform_get_drvdata(pdev); + struct wm8350_data *priv; + struct snd_soc_codec *codec; + int ret, i; + + if (wm8350->codec.platform_data == NULL) { + dev_err(&pdev->dev, "No audio platform data supplied\n"); + return -EINVAL; + } + + priv = kzalloc(sizeof(struct wm8350_data), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + 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), + priv->supplies); + if (ret != 0) + goto err_priv; + + codec = &priv->codec; + wm8350->codec.codec = codec; + + wm8350_dai.dev = &pdev->dev; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + codec->dev = &pdev->dev; + codec->name = "WM8350"; + codec->owner = THIS_MODULE; + codec->read = wm8350_codec_read; + codec->write = wm8350_codec_write; + codec->bias_level = SND_SOC_BIAS_OFF; + codec->set_bias_level = wm8350_set_bias_level; + codec->dai = &wm8350_dai; + codec->num_dai = 1; + codec->reg_cache_size = WM8350_MAX_REGISTER; + codec->private_data = priv; + codec->control_data = wm8350; + + /* Put the codec into reset if it wasn't already */ + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); + + INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work); + ret = snd_soc_register_codec(codec); + if (ret != 0) + goto err_supply; + + wm8350_codec = codec; + + ret = snd_soc_register_dai(&wm8350_dai); + if (ret != 0) + goto err_codec; + return 0; + +err_codec: + snd_soc_unregister_codec(codec); +err_supply: + regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies); +err_priv: + kfree(priv); + wm8350_codec = NULL; + return ret; +} + +static int wm8350_codec_remove(struct platform_device *pdev) +{ + struct wm8350 *wm8350 = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = wm8350->codec.codec; + struct wm8350_data *priv = codec->private_data; + + snd_soc_unregister_dai(&wm8350_dai); + snd_soc_unregister_codec(codec); + regulator_bulk_free(ARRAY_SIZE(priv->supplies), priv->supplies); + kfree(priv); + wm8350_codec = NULL; + return 0; +} + +static struct platform_driver wm8350_codec_driver = { + .driver = { + .name = "wm8350-codec", + .owner = THIS_MODULE, + }, + .probe = wm8350_codec_probe, + .remove = __devexit_p(wm8350_codec_remove), +}; + +static __init int wm8350_init(void) +{ + return platform_driver_register(&wm8350_codec_driver); +} +module_init(wm8350_init); + +static __exit void wm8350_exit(void) +{ + platform_driver_unregister(&wm8350_codec_driver); +} +module_exit(wm8350_exit); + +MODULE_DESCRIPTION("ASoC WM8350 driver"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8350-codec"); diff --git a/sound/soc/codecs/wm8350.h b/sound/soc/codecs/wm8350.h new file mode 100644 index 000000000000..cc2887aa6c38 --- /dev/null +++ b/sound/soc/codecs/wm8350.h @@ -0,0 +1,20 @@ +/* + * wm8350.h - WM8903 audio codec interface + * + * Copyright 2008 Wolfson Microelectronics PLC. + * + * 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. + */ + +#ifndef _WM8350_H +#define _WM8350_H + +#include + +extern struct snd_soc_dai wm8350_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8350; + +#endif From cae51176c1082ecb59706056910f8a217d433981 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 08:36:53 +0100 Subject: [PATCH 338/367] ALSA: split HD-audio model list to HD-Audio-Models.txt Split the list of model option values to a separate file, HD-Audio-Models.txt, from ALSA-Configuration.txt. Signed-off-by: Takashi Iwai --- .../sound/alsa/ALSA-Configuration.txt | 323 +--------------- Documentation/sound/alsa/HD-Audio-Models.txt | 348 ++++++++++++++++++ 2 files changed, 353 insertions(+), 318 deletions(-) create mode 100644 Documentation/sound/alsa/HD-Audio-Models.txt diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index d5b6b1171035..a4f3a22caba3 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -772,328 +772,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards and autoprobe. + See Documentation/sound/alsa/HD-Audio.txt for more details about + HD-audio driver. + Each codec may have a model table for different configurations. If your machine isn't listed there, the default (usually minimal) configuration is set up. You can pass "model=" option to specify a certain model in such a case. There are different - models depending on the codec chip. - - See Documentation/sound/alsa/HD-Audio.txt for some details. - - Model name Description - ---------- ----------- - ALC880 - 3stack 3-jack in back and a headphone out - 3stack-digout 3-jack in back, a HP out and a SPDIF out - 5stack 5-jack in back, 2-jack in front - 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out - 6stack 6-jack in back, 2-jack in front - 6stack-digout 6-jack with a SPDIF out - w810 3-jack - z71v 3-jack (HP shared SPDIF) - asus 3-jack (ASUS Mobo) - asus-w1v ASUS W1V - asus-dig ASUS with SPDIF out - asus-dig2 ASUS with SPDIF out (using GPIO2) - uniwill 3-jack - fujitsu Fujitsu Laptops (Pi1536) - F1734 2-jack - lg LG laptop (m1 express dual) - lg-lw LG LW20/LW25 laptop - tcl TCL S700 - clevo Clevo laptops (m520G, m665n) - medion Medion Rim 2150 - test for testing/debugging purpose, almost all controls can be - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC260 - hp HP machines - hp-3013 HP machines (3013-variant) - hp-dc7600 HP DC7600 - fujitsu Fujitsu S7020 - acer Acer TravelMate - will Will laptops (PB V7900) - replacer Replacer 672V - basic fixed pin assignment (old default model) - test for testing/debugging purpose, almost all controls can - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC262 - fujitsu Fujitsu Laptop - hp-bpc HP xw4400/6400/8400/9400 laptops - hp-bpc-d7000 HP BPC D7000 - hp-tc-t5735 HP Thin Client T5735 - hp-rp5700 HP RP5700 - benq Benq ED8 - benq-t31 Benq T31 - hippo Hippo (ATI) with jack detection, Sony UX-90s - hippo_1 Hippo (Benq) with jack detection - sony-assamd Sony ASSAMD - toshiba-s06 Toshiba S06 - toshiba-rx1 Toshiba RX1 - ultra Samsung Q1 Ultra Vista model - lenovo-3000 Lenovo 3000 y410 - nec NEC Versa S9100 - basic fixed pin assignment w/o SPDIF - auto auto-config reading BIOS (default) - - ALC267/268 - quanta-il1 Quanta IL1 mini-notebook - 3stack 3-stack model - toshiba Toshiba A205 - acer Acer laptops - acer-dmic Acer laptops with digital-mic - acer-aspire Acer Aspire One - dell Dell OEM laptops (Vostro 1200) - zepto Zepto laptops - test for testing/debugging purpose, almost all controls can - adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - auto auto-config reading BIOS (default) - - ALC269 - basic Basic preset - quanta Quanta FL1 - eeepc-p703 ASUS Eeepc P703 P900A - eeepc-p901 ASUS Eeepc P901 S101 - fujitsu FSC Amilo - auto auto-config reading BIOS (default) - - ALC662/663 - 3stack-dig 3-stack (2-channel) with SPDIF - 3stack-6ch 3-stack (6-channel) - 3stack-6ch-dig 3-stack (6-channel) with SPDIF - 6stack-dig 6-stack with SPDIF - lenovo-101e Lenovo laptop - eeepc-p701 ASUS Eeepc P701 - eeepc-ep20 ASUS Eeepc EP20 - ecs ECS/Foxconn mobo - m51va ASUS M51VA - g71v ASUS G71V - h13 ASUS H13 - g50v ASUS G50V - asus-mode1 ASUS - asus-mode2 ASUS - asus-mode3 ASUS - asus-mode4 ASUS - asus-mode5 ASUS - asus-mode6 ASUS - auto auto-config reading BIOS (default) - - ALC882/885 - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack digital with SPDIF I/O - arima Arima W820Di1 - targa Targa T8, MSI-1049 T8 - asus-a7j ASUS A7J - asus-a7m ASUS A7M - macpro MacPro support - mbp3 Macbook Pro rev3 - imac24 iMac 24'' with jack detection - w2jc ASUS W2JC - auto auto-config reading BIOS (default) - - ALC883/888 - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack digital with SPDIF I/O - 3stack-6ch 3-jack 6-channel - 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O - 6stack-dig-demo 6-jack digital for Intel demo board - acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) - acer-aspire Acer Aspire 9810 - acer-aspire-4930g Acer Aspire 4930G - medion Medion Laptops - medion-md2 Medion MD2 - targa-dig Targa/MSI - targa-2ch-dig Targs/MSI with 2-channel - laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) - lenovo-101e Lenovo 101E - lenovo-nb0763 Lenovo NB0763 - lenovo-ms7195-dig Lenovo MS7195 - lenovo-sky Lenovo Sky - haier-w66 Haier W66 - 3stack-hp HP machines with 3stack (Lucknow, Samba boards) - 6stack-dell Dell machines with 6stack (Inspiron 530) - mitac Mitac 8252D - clevo-m720 Clevo M720 laptop series - fujitsu-pi2515 Fujitsu AMILO Pi2515 - fujitsu-xa3530 Fujitsu AMILO XA3530 - 3stack-6ch-intel Intel DG33* boards - auto auto-config reading BIOS (default) - - ALC861/660 - 3stack 3-jack - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack with SPDIF I/O - 3stack-660 3-jack (for ALC660) - uniwill-m31 Uniwill M31 laptop - toshiba Toshiba laptop support - asus Asus laptop support - asus-laptop ASUS F2/F3 laptops - auto auto-config reading BIOS (default) - - ALC861VD/660VD - 3stack 3-jack - 3stack-dig 3-jack with SPDIF OUT - 6stack-dig 6-jack with SPDIF OUT - 3stack-660 3-jack (for ALC660VD) - 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) - lenovo Lenovo 3000 C200 - dallas Dallas laptops - hp HP TX1000 - asus-v1s ASUS V1Sn - auto auto-config reading BIOS (default) - - CMI9880 - minimal 3-jack in back - min_fp 3-jack in back, 2-jack in front - full 6-jack in back, 2-jack in front - full_dig 6-jack in back, 2-jack in front, SPDIF I/O - allout 5-jack in back, 2-jack in front, SPDIF out - auto auto-config reading BIOS (default) - - AD1882 / AD1882A - 3stack 3-stack mode (default) - 6stack 6-stack mode - - AD1884A / AD1883 / AD1984A / AD1984B - desktop 3-stack desktop (default) - laptop laptop with HP jack sensing - mobile mobile devices with HP jack sensing - thinkpad Lenovo Thinkpad X300 - - AD1884 - N/A - - AD1981 - basic 3-jack (default) - hp HP nx6320 - thinkpad Lenovo Thinkpad T60/X60/Z60 - toshiba Toshiba U205 - - AD1983 - N/A - - AD1984 - basic default configuration - thinkpad Lenovo Thinkpad T61/X61 - dell Dell T3400 - - AD1986A - 6stack 6-jack, separate surrounds (default) - 3stack 3-stack, shared surrounds - laptop 2-channel only (FSC V2060, Samsung M50) - laptop-eapd 2-channel with EAPD (ASUS A6J) - laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) - ultra 2-channel with EAPD (Samsung Ultra tablet PC) - samsung 2-channel with EAPD (Samsung R65) - - AD1988/AD1988B/AD1989A/AD1989B - 6stack 6-jack - 6stack-dig ditto with SPDIF - 3stack 3-jack - 3stack-dig ditto with SPDIF - laptop 3-jack with hp-jack automute - laptop-dig ditto with SPDIF - auto auto-config reading BIOS (default) - - Conexant 5045 - laptop-hpsense Laptop with HP sense (old model laptop) - laptop-micsense Laptop with Mic sense (old model fujitsu) - laptop-hpmicsense Laptop with HP and Mic senses - benq Benq R55E - test for testing/debugging purpose, almost all controls - can be adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - - Conexant 5047 - laptop Basic Laptop config - laptop-hp Laptop config for some HP models (subdevice 30A5) - laptop-eapd Laptop config with EAPD support - test for testing/debugging purpose, almost all controls - can be adjusted. Appearing only when compiled with - $CONFIG_SND_DEBUG=y - - Conexant 5051 - laptop Basic Laptop config (default) - hp HP Spartan laptop - - STAC9200 - ref Reference board - dell-d21 Dell (unknown) - dell-d22 Dell (unknown) - dell-d23 Dell (unknown) - dell-m21 Dell Inspiron 630m, Dell Inspiron 640m - dell-m22 Dell Latitude D620, Dell Latitude D820 - dell-m23 Dell XPS M1710, Dell Precision M90 - dell-m24 Dell Latitude 120L - dell-m25 Dell Inspiron E1505n - dell-m26 Dell Inspiron 1501 - dell-m27 Dell Inspiron E1705/9400 - gateway Gateway laptops with EAPD control - panasonic Panasonic CF-74 - - STAC9205/9254 - ref Reference board - dell-m42 Dell (unknown) - dell-m43 Dell Precision - dell-m44 Dell Inspiron - - STAC9220/9221 - ref Reference board - 3stack D945 3stack - 5stack D945 5stack + SPDIF - intel-mac-v1 Intel Mac Type 1 - intel-mac-v2 Intel Mac Type 2 - intel-mac-v3 Intel Mac Type 3 - intel-mac-v4 Intel Mac Type 4 - intel-mac-v5 Intel Mac Type 5 - intel-mac-auto Intel Mac (detect type according to subsystem id) - macmini Intel Mac Mini (equivalent with type 3) - macbook Intel Mac Book (eq. type 5) - macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3) - macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) - imac-intel Intel iMac (eq. type 2) - imac-intel-20 Intel iMac (newer version) (eq. type 3) - dell-d81 Dell (unknown) - dell-d82 Dell (unknown) - dell-m81 Dell (unknown) - dell-m82 Dell XPS M1210 - - STAC9202/9250/9251 - ref Reference board, base config - m2-2 Some Gateway MX series laptops - m6 Some Gateway NX series laptops - pa6 Gateway NX860 series - - STAC9227/9228/9229/927x - ref Reference board - ref-no-jd Reference board without HP/Mic jack detection - 3stack D965 3stack - 5stack D965 5stack + SPDIF - dell-3stack Dell Dimension E520 - dell-bios Fixes with Dell BIOS setup - - STAC92HD71B* - ref Reference board - dell-m4-1 Dell desktops - dell-m4-2 Dell desktops - dell-m4-3 Dell desktops - - STAC92HD73* - ref Reference board - no-jd BIOS setup but without jack-detection - dell-m6-amic Dell desktops/laptops with analog mics - dell-m6-dmic Dell desktops/laptops with digital mics - dell-m6 Dell desktops/laptops with both type of mics - - STAC9872 - vaio Setup for VAIO FE550G/SZ110 - vaio-ar Setup for VAIO AR + models depending on the codec chip. The list of available models + is found in HD-Audio-Models.txt The model name "genric" is treated as a special case. When this model is given, the driver uses the generic codec parser without diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt new file mode 100644 index 000000000000..4b7ac21ea9eb --- /dev/null +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -0,0 +1,348 @@ + Model name Description + ---------- ----------- +ALC880 +====== + 3stack 3-jack in back and a headphone out + 3stack-digout 3-jack in back, a HP out and a SPDIF out + 5stack 5-jack in back, 2-jack in front + 5stack-digout 5-jack in back, 2-jack in front, a SPDIF out + 6stack 6-jack in back, 2-jack in front + 6stack-digout 6-jack with a SPDIF out + w810 3-jack + z71v 3-jack (HP shared SPDIF) + asus 3-jack (ASUS Mobo) + asus-w1v ASUS W1V + asus-dig ASUS with SPDIF out + asus-dig2 ASUS with SPDIF out (using GPIO2) + uniwill 3-jack + fujitsu Fujitsu Laptops (Pi1536) + F1734 2-jack + lg LG laptop (m1 express dual) + lg-lw LG LW20/LW25 laptop + tcl TCL S700 + clevo Clevo laptops (m520G, m665n) + medion Medion Rim 2150 + test for testing/debugging purpose, almost all controls can be + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC260 +====== + hp HP machines + hp-3013 HP machines (3013-variant) + hp-dc7600 HP DC7600 + fujitsu Fujitsu S7020 + acer Acer TravelMate + will Will laptops (PB V7900) + replacer Replacer 672V + basic fixed pin assignment (old default model) + test for testing/debugging purpose, almost all controls can + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC262 +====== + fujitsu Fujitsu Laptop + hp-bpc HP xw4400/6400/8400/9400 laptops + hp-bpc-d7000 HP BPC D7000 + hp-tc-t5735 HP Thin Client T5735 + hp-rp5700 HP RP5700 + benq Benq ED8 + benq-t31 Benq T31 + hippo Hippo (ATI) with jack detection, Sony UX-90s + hippo_1 Hippo (Benq) with jack detection + sony-assamd Sony ASSAMD + toshiba-s06 Toshiba S06 + toshiba-rx1 Toshiba RX1 + ultra Samsung Q1 Ultra Vista model + lenovo-3000 Lenovo 3000 y410 + nec NEC Versa S9100 + basic fixed pin assignment w/o SPDIF + auto auto-config reading BIOS (default) + +ALC267/268 +========== + quanta-il1 Quanta IL1 mini-notebook + 3stack 3-stack model + toshiba Toshiba A205 + acer Acer laptops + acer-dmic Acer laptops with digital-mic + acer-aspire Acer Aspire One + dell Dell OEM laptops (Vostro 1200) + zepto Zepto laptops + test for testing/debugging purpose, almost all controls can + adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + auto auto-config reading BIOS (default) + +ALC269 +====== + basic Basic preset + quanta Quanta FL1 + eeepc-p703 ASUS Eeepc P703 P900A + eeepc-p901 ASUS Eeepc P901 S101 + fujitsu FSC Amilo + auto auto-config reading BIOS (default) + +ALC662/663 +========== + 3stack-dig 3-stack (2-channel) with SPDIF + 3stack-6ch 3-stack (6-channel) + 3stack-6ch-dig 3-stack (6-channel) with SPDIF + 6stack-dig 6-stack with SPDIF + lenovo-101e Lenovo laptop + eeepc-p701 ASUS Eeepc P701 + eeepc-ep20 ASUS Eeepc EP20 + ecs ECS/Foxconn mobo + m51va ASUS M51VA + g71v ASUS G71V + h13 ASUS H13 + g50v ASUS G50V + asus-mode1 ASUS + asus-mode2 ASUS + asus-mode3 ASUS + asus-mode4 ASUS + asus-mode5 ASUS + asus-mode6 ASUS + auto auto-config reading BIOS (default) + +ALC882/885 +========== + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O + arima Arima W820Di1 + targa Targa T8, MSI-1049 T8 + asus-a7j ASUS A7J + asus-a7m ASUS A7M + macpro MacPro support + mbp3 Macbook Pro rev3 + imac24 iMac 24'' with jack detection + w2jc ASUS W2JC + auto auto-config reading BIOS (default) + +ALC883/888 +========== + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack digital with SPDIF I/O + 3stack-6ch 3-jack 6-channel + 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O + 6stack-dig-demo 6-jack digital for Intel demo board + acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc) + acer-aspire Acer Aspire 9810 + acer-aspire-4930g Acer Aspire 4930G + medion Medion Laptops + medion-md2 Medion MD2 + targa-dig Targa/MSI + targa-2ch-dig Targs/MSI with 2-channel + laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE) + lenovo-101e Lenovo 101E + lenovo-nb0763 Lenovo NB0763 + lenovo-ms7195-dig Lenovo MS7195 + lenovo-sky Lenovo Sky + haier-w66 Haier W66 + 3stack-hp HP machines with 3stack (Lucknow, Samba boards) + 6stack-dell Dell machines with 6stack (Inspiron 530) + mitac Mitac 8252D + clevo-m720 Clevo M720 laptop series + fujitsu-pi2515 Fujitsu AMILO Pi2515 + fujitsu-xa3530 Fujitsu AMILO XA3530 + 3stack-6ch-intel Intel DG33* boards + auto auto-config reading BIOS (default) + +ALC861/660 +========== + 3stack 3-jack + 3stack-dig 3-jack with SPDIF I/O + 6stack-dig 6-jack with SPDIF I/O + 3stack-660 3-jack (for ALC660) + uniwill-m31 Uniwill M31 laptop + toshiba Toshiba laptop support + asus Asus laptop support + asus-laptop ASUS F2/F3 laptops + auto auto-config reading BIOS (default) + +ALC861VD/660VD +============== + 3stack 3-jack + 3stack-dig 3-jack with SPDIF OUT + 6stack-dig 6-jack with SPDIF OUT + 3stack-660 3-jack (for ALC660VD) + 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD) + lenovo Lenovo 3000 C200 + dallas Dallas laptops + hp HP TX1000 + asus-v1s ASUS V1Sn + auto auto-config reading BIOS (default) + +CMI9880 +======= + minimal 3-jack in back + min_fp 3-jack in back, 2-jack in front + full 6-jack in back, 2-jack in front + full_dig 6-jack in back, 2-jack in front, SPDIF I/O + allout 5-jack in back, 2-jack in front, SPDIF out + auto auto-config reading BIOS (default) + +AD1882 / AD1882A +================ + 3stack 3-stack mode (default) + 6stack 6-stack mode + +AD1884A / AD1883 / AD1984A / AD1984B +==================================== + desktop 3-stack desktop (default) + laptop laptop with HP jack sensing + mobile mobile devices with HP jack sensing + thinkpad Lenovo Thinkpad X300 + +AD1884 +====== + N/A + +AD1981 +====== + basic 3-jack (default) + hp HP nx6320 + thinkpad Lenovo Thinkpad T60/X60/Z60 + toshiba Toshiba U205 + +AD1983 +====== + N/A + +AD1984 +====== + basic default configuration + thinkpad Lenovo Thinkpad T61/X61 + dell Dell T3400 + +AD1986A +======= + 6stack 6-jack, separate surrounds (default) + 3stack 3-stack, shared surrounds + laptop 2-channel only (FSC V2060, Samsung M50) + laptop-eapd 2-channel with EAPD (ASUS A6J) + laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100) + ultra 2-channel with EAPD (Samsung Ultra tablet PC) + samsung 2-channel with EAPD (Samsung R65) + +AD1988/AD1988B/AD1989A/AD1989B +============================== + 6stack 6-jack + 6stack-dig ditto with SPDIF + 3stack 3-jack + 3stack-dig ditto with SPDIF + laptop 3-jack with hp-jack automute + laptop-dig ditto with SPDIF + auto auto-config reading BIOS (default) + +Conexant 5045 +============= + laptop-hpsense Laptop with HP sense (old model laptop) + laptop-micsense Laptop with Mic sense (old model fujitsu) + laptop-hpmicsense Laptop with HP and Mic senses + benq Benq R55E + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + +Conexant 5047 +============= + laptop Basic Laptop config + laptop-hp Laptop config for some HP models (subdevice 30A5) + laptop-eapd Laptop config with EAPD support + test for testing/debugging purpose, almost all controls + can be adjusted. Appearing only when compiled with + $CONFIG_SND_DEBUG=y + +Conexant 5051 +============= + laptop Basic Laptop config (default) + hp HP Spartan laptop + +STAC9200 +======== + ref Reference board + dell-d21 Dell (unknown) + dell-d22 Dell (unknown) + dell-d23 Dell (unknown) + dell-m21 Dell Inspiron 630m, Dell Inspiron 640m + dell-m22 Dell Latitude D620, Dell Latitude D820 + dell-m23 Dell XPS M1710, Dell Precision M90 + dell-m24 Dell Latitude 120L + dell-m25 Dell Inspiron E1505n + dell-m26 Dell Inspiron 1501 + dell-m27 Dell Inspiron E1705/9400 + gateway Gateway laptops with EAPD control + panasonic Panasonic CF-74 + +STAC9205/9254 +============= + ref Reference board + dell-m42 Dell (unknown) + dell-m43 Dell Precision + dell-m44 Dell Inspiron + +STAC9220/9221 +============= + ref Reference board + 3stack D945 3stack + 5stack D945 5stack + SPDIF + intel-mac-v1 Intel Mac Type 1 + intel-mac-v2 Intel Mac Type 2 + intel-mac-v3 Intel Mac Type 3 + intel-mac-v4 Intel Mac Type 4 + intel-mac-v5 Intel Mac Type 5 + intel-mac-auto Intel Mac (detect type according to subsystem id) + macmini Intel Mac Mini (equivalent with type 3) + macbook Intel Mac Book (eq. type 5) + macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3) + macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3) + imac-intel Intel iMac (eq. type 2) + imac-intel-20 Intel iMac (newer version) (eq. type 3) + dell-d81 Dell (unknown) + dell-d82 Dell (unknown) + dell-m81 Dell (unknown) + dell-m82 Dell XPS M1210 + +STAC9202/9250/9251 +================== + ref Reference board, base config + m2-2 Some Gateway MX series laptops + m6 Some Gateway NX series laptops + pa6 Gateway NX860 series + +STAC9227/9228/9229/927x +======================= + ref Reference board + ref-no-jd Reference board without HP/Mic jack detection + 3stack D965 3stack + 5stack D965 5stack + SPDIF + dell-3stack Dell Dimension E520 + dell-bios Fixes with Dell BIOS setup + +STAC92HD71B* +============ + ref Reference board + dell-m4-1 Dell desktops + dell-m4-2 Dell desktops + dell-m4-3 Dell desktops + +STAC92HD73* +=========== + ref Reference board + no-jd BIOS setup but without jack-detection + dell-m6-amic Dell desktops/laptops with analog mics + dell-m6-dmic Dell desktops/laptops with digital mics + dell-m6 Dell desktops/laptops with both type of mics + +STAC92HD83* +=========== + ref Reference board + +STAC9872 +======== + vaio Setup for VAIO FE550G/SZ110 + vaio-ar Setup for VAIO AR From 827057f5c12f5e10dc0279596db940aa6ddf8d9b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 10:12:02 +0100 Subject: [PATCH 339/367] ALSA: hda - Add missing initializations of amp and verb caches The re-initializations of codec amp and verb caches are missing at reconfig, which may cause Oops occasionally. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8459d6ba2055..625fe5984dd6 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1288,6 +1288,8 @@ void snd_hda_codec_reset(struct hda_codec *codec) codec->spec = NULL; free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); + init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); + init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; From 4f2d23e1c3fe0abaf87fead3033c6cc3671b4d1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 10:14:13 +0100 Subject: [PATCH 340/367] ALSA: hda - Use snd_hda_ctl_add() in patch_sigmatel.c Fixed the call of snd_ctl_add() by replacing with snd_hda_ctl_add() so that this mixer element can be tracked for re-configuration. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 71c3ccfcde16..31662c65e8fd 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1293,7 +1293,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) spec->spdif_mute = 1; } stac_smux_mixer.count = spec->num_smuxes; - err = snd_ctl_add(codec->bus->card, + err = snd_hda_ctl_add(codec, snd_ctl_new1(&stac_smux_mixer, codec)); if (err < 0) return err; From 86effd7e12ca63cecfd218717473d606e138e5e1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 12:04:06 +0100 Subject: [PATCH 341/367] ALSA: ca0106 - Don't override the values at resume Don't override some values in ca0106_init_chip() at resume. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 41 +++++++++++++++------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index c13aa41a35b4..2c71f9b896cd 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1303,9 +1303,10 @@ static unsigned int i2c_adc_init[][2] = { { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ }; -static void ca0106_init_chip(struct snd_ca0106 *chip) +static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) { int ch; + unsigned int def_bits; outl(0, chip->port + INTE); @@ -1323,30 +1324,21 @@ static void ca0106_init_chip(struct snd_ca0106 *chip) * AN = 0 (Audio data) * P = 0 (Consumer) */ - chip->spdif_bits[0] = + def_bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; - snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); + if (!resume) { + chip->spdif_bits[0] = def_bits; + chip->spdif_bits[1] = def_bits; + chip->spdif_bits[2] = def_bits; + chip->spdif_bits[3] = def_bits; + } /* Only SPCS1 has been tested */ - chip->spdif_bits[1] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); - chip->spdif_bits[2] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; + snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); - chip->spdif_bits[3] = - SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | - SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | - SPCS_GENERATIONSTATUS | 0x00001200 | - 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); @@ -1407,17 +1399,20 @@ static void ca0106_init_chip(struct snd_ca0106 *chip) /* Select MIC, Line in, TAD in, AUX in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Default to CAPTURE_SOURCE to i2s in */ - chip->capture_source = 3; + if (!resume) + chip->capture_source = 3; } else if (chip->details->ac97 == 1) { /* Default to AC97 in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x444400e4); /* Default to CAPTURE_SOURCE to AC97 in */ - chip->capture_source = 4; + if (!resume) + chip->capture_source = 4; } else { /* Select MIC, Line in, TAD in, AUX in */ snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Default to Set CAPTURE_SOURCE to i2s in */ - chip->capture_source = 3; + if (!resume) + chip->capture_source = 3; } if (chip->details->gpio_type == 2) { @@ -1583,7 +1578,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, sprintf(card->longname, "%s at 0x%lx irq %i", c->name, chip->port, chip->irq); - ca0106_init_chip(chip); + ca0106_init_chip(chip, 0); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { @@ -1784,7 +1779,7 @@ static int snd_ca0106_resume(struct pci_dev *pci) pci_set_master(pci); - ca0106_init_chip(chip); + ca0106_init_chip(chip, 1); snd_ac97_resume(chip->ac97); snd_ca0106_mixer_resume(chip); From 3d4758299fa6180ff9304634c67ffdd44272c8e8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 12:13:18 +0100 Subject: [PATCH 342/367] ALSA: ca0106 - Add IEC958 PCM Stream controls Added "IEC958 PCM Stream" controls for the per-stream IEC958 status bits. Using this instead of "IEC958 Default" is safer since the status bits will be recovered to the default states after closing the PCM stream. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106.h | 3 +- sound/pci/ca0106/ca0106_main.c | 30 ++++++++---- sound/pci/ca0106/ca0106_mixer.c | 83 ++++++++++++++++++++++++++------- 3 files changed, 90 insertions(+), 26 deletions(-) diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 1c14ff424116..ec0f17ded4e0 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h @@ -690,7 +690,8 @@ struct snd_ca0106 { struct snd_ca0106_channel playback_channels[4]; struct snd_ca0106_channel capture_channels[4]; - u32 spdif_bits[4]; /* s/pdif out setup */ + u32 spdif_bits[4]; /* s/pdif out default setup */ + u32 spdif_str_bits[4]; /* s/pdif out per-stream setup */ int spdif_enable; int capture_source; int i2c_capture_source; diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 2c71f9b896cd..c27fd90101d6 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -479,6 +479,15 @@ static const int spi_dacd_bit[] = { [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, }; +static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) +{ + if (chip->spdif_str_bits[idx] != chip->spdif_bits[idx]) { + chip->spdif_str_bits[idx] = chip->spdif_bits[idx]; + snd_ca0106_ptr_write(chip, SPCS0 + idx, 0, + chip->spdif_str_bits[idx]); + } +} + /* open_playback callback */ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, int channel_id) @@ -524,6 +533,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr if (err < 0) return err; } + + restore_spdif_bits(chip, channel_id); + return 0; } @@ -535,6 +547,8 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) struct snd_ca0106_pcm *epcm = runtime->private_data; chip->playback_channels[epcm->channel_id].use = 0; + restore_spdif_bits(chip, epcm->channel_id); + if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { const int reg = spi_dacd_reg[epcm->channel_id]; @@ -1330,16 +1344,16 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; if (!resume) { - chip->spdif_bits[0] = def_bits; - chip->spdif_bits[1] = def_bits; - chip->spdif_bits[2] = def_bits; - chip->spdif_bits[3] = def_bits; + chip->spdif_str_bits[0] = chip->spdif_bits[0] = def_bits; + chip->spdif_str_bits[1] = chip->spdif_bits[1] = def_bits; + chip->spdif_str_bits[2] = chip->spdif_bits[2] = def_bits; + chip->spdif_str_bits[3] = chip->spdif_bits[3] = def_bits; } /* Only SPCS1 has been tested */ - snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); - snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); - snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); - snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); + snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_str_bits[1]); + snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_str_bits[0]); + snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_str_bits[2]); + snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_str_bits[3]); snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index cccc32cdb943..8727881a10b8 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -148,7 +148,7 @@ static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) { - snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); + snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]); } /* @@ -353,16 +353,33 @@ static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol, return 0; } -static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol, +static void decode_spdif_bits(unsigned char *status, unsigned int bits) +{ + status[0] = (bits >> 0) & 0xff; + status[1] = (bits >> 8) & 0xff; + status[2] = (bits >> 16) & 0xff; + status[3] = (bits >> 24) & 0xff; +} + +static int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; - ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; - ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; - ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; + decode_spdif_bits(ucontrol->value.iec958.status, + emu->spdif_bits[idx]); + return 0; +} + +static int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + decode_spdif_bits(ucontrol->value.iec958.status, + emu->spdif_str_bits[idx]); return 0; } @@ -376,24 +393,48 @@ static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol, return 0; } -static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, +static unsigned int encode_spdif_bits(unsigned char *status) +{ + return ((unsigned int)status[0] << 0) | + ((unsigned int)status[1] << 8) | + ((unsigned int)status[2] << 16) | + ((unsigned int)status[3] << 24); +} + +static int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - int change; unsigned int val; - val = (ucontrol->value.iec958.status[0] << 0) | - (ucontrol->value.iec958.status[1] << 8) | - (ucontrol->value.iec958.status[2] << 16) | - (ucontrol->value.iec958.status[3] << 24); - change = val != emu->spdif_bits[idx]; - if (change) { + val = encode_spdif_bits(ucontrol->value.iec958.status); + if (val != emu->spdif_bits[idx]) { emu->spdif_bits[idx] = val; + /* FIXME: this isn't safe, but needed to keep the compatibility + * with older alsa-lib config + */ + emu->spdif_str_bits[idx] = val; ca0106_set_spdif_bits(emu, idx); + return 1; } - return change; + return 0; +} + +static int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); + unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int val; + + val = encode_spdif_bits(ucontrol->value.iec958.status); + if (val != emu->spdif_str_bits[idx]) { + emu->spdif_str_bits[idx] = val; + ca0106_set_spdif_bits(emu, idx); + return 1; + } + return 0; } static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol, @@ -604,8 +645,16 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .count = 4, .info = snd_ca0106_spdif_info, - .get = snd_ca0106_spdif_get, - .put = snd_ca0106_spdif_put + .get = snd_ca0106_spdif_get_default, + .put = snd_ca0106_spdif_put_default + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), + .count = 4, + .info = snd_ca0106_spdif_info, + .get = snd_ca0106_spdif_get_stream, + .put = snd_ca0106_spdif_put_stream }, }; From 692f90421d3716ef0d0f120d9d2c9684009a4a01 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 12:44:46 +0100 Subject: [PATCH 343/367] ALSA: hda - Fix HD-Audio.txt reference of model list The model list is now in HD-Audio-Models.txt. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 642a2b012541..8d68fff71839 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -162,8 +162,8 @@ PCI SSID look-up. What `model` option values are available depends on the codec chip. Check your codec chip from the codec proc file (see "Codec Proc-File" section below). It will show the vendor/product name of your codec -chip. Then, see Documentation/sound/alsa/ALSA-Configuration.txt -file, the section of HD-audio driver. You can find a list of codecs +chip. Then, see Documentation/sound/alsa/HD-Audio-Modelstxt file, +the section of HD-audio driver. You can find a list of codecs and `model` options belonging to each codec. For example, for Realtek ALC262 codec chip, pass `model=ultra` for devices that are compatible with Samsung Q1 Ultra. From 8df0f70751dc0e51d0550caee3416339183c5767 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 13:55:17 +0100 Subject: [PATCH 344/367] ALSA: ca0106 - Fix typo in resume code The register and channel_id pair were twisted in the pm code... Oh my. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index cccc32cdb943..9845a20f5427 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -806,8 +806,8 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) #ifdef CONFIG_PM struct ca0106_vol_tbl { - unsigned int reg; unsigned int channel_id; + unsigned int reg; }; static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { From c21ca4a872697aeda4fe91bf9b6cc8380c62827c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 09:26:08 +0100 Subject: [PATCH 345/367] ALSA: hda - Rework on STAC/IDT auto-configuration code The current auto-configuration code has several problems especially for the new IDT codecs, e.g. wrong assignment of pins and DACs or coupled volume for speaker and headphone. This patch is a fairly large rewrite of the auto-configuration code. Some remaks - mic_switch and line_switch contain NIDs instead of bool - dac_list isn't fixed for IDT 92HD* codecs now, they are all probed - extra HP and speakers are stored in extra_dacs[]. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 473 +++++++++++++++------------------ 1 file changed, 207 insertions(+), 266 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b7b419691803..171400216326 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -157,8 +157,6 @@ struct sigmatel_spec { int board_config; unsigned int eapd_switch: 1; unsigned int surr_switch: 1; - unsigned int line_switch: 1; - unsigned int mic_switch: 1; unsigned int alt_switch: 1; unsigned int hp_detect: 1; unsigned int spdif_mute: 1; @@ -195,6 +193,8 @@ struct sigmatel_spec { 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]; /* capture */ hda_nid_t *adc_nids; @@ -238,7 +238,9 @@ struct sigmatel_spec { /* i/o switches */ unsigned int io_switch[2]; unsigned int clfe_swap; - unsigned int hp_switch; /* NID of HP as line-out */ + 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 */ @@ -289,9 +291,6 @@ static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { }; #define STAC92HD73_DAC_COUNT 5 -static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = { - 0x15, 0x16, 0x17, 0x18, 0x19, -}; static hda_nid_t stac92hd73xx_mux_nids[4] = { 0x28, 0x29, 0x2a, 0x2b, @@ -310,11 +309,7 @@ static hda_nid_t stac92hd83xxx_dmic_nids[STAC92HD83XXX_NUM_DMICS + 1] = { 0x11, 0x12, 0 }; -#define STAC92HD81_DAC_COUNT 2 #define STAC92HD83_DAC_COUNT 3 -static hda_nid_t stac92hd83xxx_dac_nids[STAC92HD73_DAC_COUNT] = { - 0x13, 0x14, 0x22, -}; static hda_nid_t stac92hd83xxx_dmux_nids[2] = { 0x17, 0x18, @@ -356,10 +351,6 @@ static hda_nid_t stac92hd71bxx_smux_nids[2] = { 0x24, 0x25, }; -static hda_nid_t stac92hd71bxx_dac_nids[1] = { - 0x10, /*0x11, */ -}; - #define STAC92HD71BXX_NUM_DMICS 2 static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { 0x18, 0x19, 0 @@ -761,10 +752,6 @@ static struct hda_verb stac9200_eapd_init[] = { static struct hda_verb stac92hd73xx_6ch_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup audio connections */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -783,10 +770,6 @@ static struct hda_verb dell_eq_core_init[] = { /* set master volume to max value without distortion * and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec}, - /* setup audio connections */ - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x02}, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x01}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -800,10 +783,6 @@ static struct hda_verb dell_eq_core_init[] = { static struct hda_verb dell_m6_core_init[] = { { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup audio connections */ - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x02}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -818,13 +797,6 @@ static struct hda_verb dell_m6_core_init[] = { static struct hda_verb stac92hd73xx_8ch_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup audio connections */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* connect hp ports to dac3 */ - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03}, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -842,15 +814,8 @@ static struct hda_verb stac92hd73xx_8ch_core_init[] = { static struct hda_verb stac92hd73xx_10ch_core_init[] = { /* set master volume and direct control */ { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* setup audio connections */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 }, /* dac3 is connected to import3 mux */ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f}, - /* connect hp ports to dac4 */ - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04}, - { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04}, /* setup adcs to point to mixer */ { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, @@ -881,8 +846,6 @@ static struct hda_verb stac92hd83xxx_core_init[] = { static struct hda_verb stac92hd71bxx_core_init[] = { /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* connect headphone jack to dac1 */ - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -901,8 +864,6 @@ static struct hda_verb stac92hd71bxx_analog_core_init[] = { /* set master volume and direct control */ { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, - /* connect headphone jack to dac1 */ - { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* unmute right and left channels for nodes 0x0a, 0xd */ { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -2747,69 +2708,52 @@ static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type, return stac92xx_add_control_idx(spec, type, 0, name, val); } -/* flag inputs as additional dynamic lineouts */ -static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg) +/* 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; - unsigned int wcaps, wtype; - int i, num_dacs = 0; - - /* use the wcaps cache to count all DACs available for line-outs */ - for (i = 0; i < codec->num_nodes; i++) { - wcaps = codec->wcaps[i]; - wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - - if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) - num_dacs++; - } - - snd_printdd("%s: total dac count=%d\n", __func__, num_dacs); - - switch (cfg->line_outs) { - case 3: - /* add line-in as side */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 3) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - break; - case 2: - /* add line-in as clfe and mic as side */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 2) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 3) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_MIC]; - spec->mic_switch = 1; - cfg->line_outs++; - } - break; - case 1: - /* add line-in as surr and mic as clfe */ - if (cfg->input_pins[AUTO_PIN_LINE] && num_dacs > 1) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_LINE]; - spec->line_switch = 1; - cfg->line_outs++; - } - if (cfg->input_pins[AUTO_PIN_MIC] && num_dacs > 2) { - cfg->line_out_pins[cfg->line_outs] = - cfg->input_pins[AUTO_PIN_MIC]; - spec->mic_switch = 1; - cfg->line_outs++; - } - break; - } + struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t nid; + unsigned int pincap; + if (cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; + nid = cfg->input_pins[AUTO_PIN_LINE]; + pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (pincap & AC_PINCAP_OUT) + return nid; return 0; } +/* check whether the mic-input can be used as line-out */ +static hda_nid_t check_mic_out_switch(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int def_conf, pincap; + unsigned int mic_pin; + + if (cfg->line_out_type != AUTO_PIN_LINE_OUT) + return 0; + mic_pin = AUTO_PIN_MIC; + for (;;) { + hda_nid_t nid = cfg->input_pins[mic_pin]; + def_conf = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + /* some laptops have an internal analog microphone + * which can't be used as a output */ + if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { + pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (pincap & AC_PINCAP_OUT) + return nid; + } + if (mic_pin == AUTO_PIN_MIC) + mic_pin = AUTO_PIN_FRONT_MIC; + else + break; + } + return 0; +} static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) { @@ -2823,6 +2767,52 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) 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; + int j, conn_len; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; + unsigned int wcaps, wtype; + + conn_len = snd_hda_get_connections(codec, nid, conn, + HDA_MAX_CONNECTIONS); + for (j = 0; j < conn_len; j++) { + wcaps = snd_hda_param_read(codec, conn[j], + AC_PAR_AUDIO_WIDGET_CAP); + wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + /* 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]; + } + } + 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[] @@ -2830,31 +2820,17 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) * 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 auto_pin_cfg *cfg) +static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int i, j, conn_len = 0; - hda_nid_t nid, conn[HDA_MAX_CONNECTIONS]; - unsigned int wcaps, wtype; + 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]; - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); - for (j = 0; j < conn_len; j++) { - wcaps = snd_hda_param_read(codec, conn[j], - AC_PAR_AUDIO_WIDGET_CAP); - wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wtype != AC_WID_AUD_OUT || - (wcaps & AC_WCAP_DIGITAL)) - continue; - /* conn[j] is a DAC routed to this line-out */ - if (!is_in_dac_nids(spec, conn[j])) - break; - } - - if (j == conn_len) { + 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 @@ -2868,24 +2844,64 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, __func__, nid); return -ENODEV; } + add_spec_dacs(spec, dac); + } - spec->multiout.dac_nids[i] = conn[j]; - spec->multiout.num_dacs++; - 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); - + /* 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); + if (nid) { + dac = get_unassigned_dac(codec, nid); + if (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("dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + 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; + } + + 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; } @@ -2910,9 +2926,7 @@ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) { - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - else if (spec->multiout.num_dacs > 4) { + if (spec->multiout.num_dacs > 4) { printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); return 1; } else { @@ -2922,13 +2936,17 @@ static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) return 0; } -static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) +static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid) { - if (is_in_dac_nids(spec, nid)) - return 1; - if (spec->multiout.hp_nid == nid) - return 1; - return 0; + 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; } /* add playback controls from the parsed DAC table */ @@ -2944,13 +2962,8 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, struct sigmatel_spec *spec = codec->spec; unsigned int wid_caps, pincap; - - for (i = 0; i < cfg->line_outs && i < spec->multiout.num_dacs; i++) { - if (!spec->multiout.dac_nids[i]) - continue; - + for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { nid = spec->multiout.dac_nids[i]; - if (i == 2) { /* Center/LFE */ err = create_controls(spec, "Center", nid, 1); @@ -2978,10 +2991,6 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, } } - if ((spec->multiout.num_dacs - cfg->line_outs) > 0 && - cfg->hp_outs == 1 && !spec->multiout.hp_nid) - spec->multiout.hp_nid = nid; - if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_HP_SWITCH, @@ -2992,45 +3001,19 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, } if (spec->line_switch) { - nid = cfg->input_pins[AUTO_PIN_LINE]; - pincap = snd_hda_param_read(codec, nid, - AC_PAR_PIN_CAP); - if (pincap & AC_PINCAP_OUT) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_IO_SWITCH, - "Line In as Output Switch", nid << 8); - if (err < 0) - return err; - } + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, + "Line In as Output Switch", + spec->line_switch << 8); + if (err < 0) + return err; } if (spec->mic_switch) { - unsigned int def_conf; - unsigned int mic_pin = AUTO_PIN_MIC; -again: - nid = cfg->input_pins[mic_pin]; - def_conf = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); - /* some laptops have an internal analog microphone - * which can't be used as a output */ - if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { - pincap = snd_hda_param_read(codec, nid, - AC_PAR_PIN_CAP); - if (pincap & AC_PINCAP_OUT) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_IO_SWITCH, - "Mic as Output Switch", (nid << 8) | 1); - nid = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (!check_in_dac_nids(spec, nid)) - add_spec_dacs(spec, nid); - if (err < 0) - return err; - } - } else if (mic_pin == AUTO_PIN_MIC) { - mic_pin = AUTO_PIN_FRONT_MIC; - goto again; - } + err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, + "Mic as Output Switch", + (spec->mic_switch << 8) | 1); + if (err < 0) + return err; } return 0; @@ -3042,55 +3025,39 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, { struct sigmatel_spec *spec = codec->spec; hda_nid_t nid; - int i, old_num_dacs, err; + int i, err, nums; - old_num_dacs = spec->multiout.num_dacs; + nums = 0; for (i = 0; i < cfg->hp_outs; i++) { + static const char *pfxs[] = { + "Headphone", "Headphone2", "Headphone3", + }; unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); if (wid_caps & AC_WCAP_UNSOL_CAP) spec->hp_detect = 1; - nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) + if (nums >= ARRAY_SIZE(pfxs)) continue; - add_spec_dacs(spec, nid); + nid = spec->hp_dacs[i]; + if (!nid) + continue; + err = create_controls(spec, pfxs[nums++], nid, 3); + if (err < 0) + return err; } + nums = 0; for (i = 0; i < cfg->speaker_outs; i++) { - nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) - continue; - add_spec_dacs(spec, nid); - } - for (i = 0; i < cfg->line_outs; i++) { - nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - if (check_in_dac_nids(spec, nid)) - nid = 0; - if (! nid) - continue; - add_spec_dacs(spec, nid); - } - for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { static const char *pfxs[] = { "Speaker", "External Speaker", "Speaker2", }; - err = create_controls(spec, pfxs[i - old_num_dacs], - spec->multiout.dac_nids[i], 3); + if (nums >= ARRAY_SIZE(pfxs)) + continue; + nid = spec->speaker_dacs[i]; + if (!nid) + continue; + err = create_controls(spec, pfxs[nums++], nid, 3); if (err < 0) return err; } - if (spec->multiout.hp_nid) { - err = create_controls(spec, "Headphone", - spec->multiout.hp_nid, 3); - if (err < 0) - return err; - } - return 0; } @@ -3428,7 +3395,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out { struct sigmatel_spec *spec = codec->spec; int err; - int hp_speaker_swap = 0; if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, @@ -3446,13 +3412,15 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out * 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; - hp_speaker_swap = 1; + spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; + spec->autocfg.hp_outs = 0; } if (spec->autocfg.mono_out_pin) { int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & @@ -3504,11 +3472,11 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out AC_PINCTL_OUT_EN); } - if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) - return err; - if (spec->multiout.num_dacs == 0) - if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) + 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); @@ -3546,19 +3514,6 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out } #endif - if (hp_speaker_swap == 1) { - /* Restore the hp_outs and line_outs */ - memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, - sizeof(spec->autocfg.line_out_pins)); - spec->autocfg.hp_outs = spec->autocfg.line_outs; - memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins, - sizeof(spec->autocfg.speaker_pins)); - spec->autocfg.line_outs = spec->autocfg.speaker_outs; - memset(spec->autocfg.speaker_pins, 0, - sizeof(spec->autocfg.speaker_pins)); - spec->autocfg.speaker_outs = 0; - } - err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); if (err < 0) @@ -3870,8 +3825,7 @@ static void stac92xx_power_down(struct hda_codec *codec) /* power down inactive DACs */ hda_nid_t *dac; for (dac = spec->dac_list; *dac; dac++) - if (!is_in_dac_nids(spec, *dac) && - spec->multiout.hp_nid != *dac) + if (!check_all_dac_nids(spec, *dac)) snd_hda_codec_write(codec, *dac, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } @@ -4055,10 +4009,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, */ struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - if ((nid == cfg->input_pins[AUTO_PIN_LINE] && - spec->line_switch) || - (nid == cfg->input_pins[AUTO_PIN_MIC] && - spec->mic_switch)) + if (nid == spec->line_switch || nid == spec->mic_switch) return; } @@ -4100,11 +4051,9 @@ 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 (spec->line_switch && - cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_LINE]) + if (cfg->hp_pins[i] == spec->line_switch) return 1; - if (spec->mic_switch && - cfg->hp_pins[i] == cfg->input_pins[AUTO_PIN_MIC]) + 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) @@ -4515,6 +4464,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) struct sigmatel_spec *spec; hda_nid_t conn[STAC92HD73_DAC_COUNT + 2]; int err = 0; + int num_dacs; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -4541,33 +4491,29 @@ again: return err; } - spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, + num_dacs = snd_hda_get_connections(codec, 0x0a, conn, STAC92HD73_DAC_COUNT + 2) - 1; - if (spec->multiout.num_dacs < 0) { + if (num_dacs < 3 || num_dacs > 5) { printk(KERN_WARNING "hda_codec: Could not determine " "number of channels defaulting to DAC count\n"); - spec->multiout.num_dacs = STAC92HD73_DAC_COUNT; + num_dacs = STAC92HD73_DAC_COUNT; } - - switch (spec->multiout.num_dacs) { + switch (num_dacs) { case 0x3: /* 6 Channel */ - spec->multiout.hp_nid = 0x17; spec->mixer = stac92hd73xx_6ch_mixer; spec->init = stac92hd73xx_6ch_core_init; break; case 0x4: /* 8 Channel */ - spec->multiout.hp_nid = 0x18; spec->mixer = stac92hd73xx_8ch_mixer; spec->init = stac92hd73xx_8ch_core_init; break; case 0x5: /* 10 Channel */ - spec->multiout.hp_nid = 0x19; spec->mixer = stac92hd73xx_10ch_mixer; spec->init = stac92hd73xx_10ch_core_init; - }; + } + spec->multiout.dac_nids = spec->dac_nids; - spec->multiout.dac_nids = stac92hd73xx_dac_nids; spec->aloopback_mask = 0x01; spec->aloopback_shift = 8; @@ -4598,9 +4544,8 @@ again: spec->amp_nids = &stac92hd73xx_amp_nids[DELL_M6_AMP]; spec->eapd_switch = 0; spec->num_amps = 1; - spec->multiout.hp_nid = 0; /* dual HPs */ - if (!spec->init) + if (spec->board_config != STAC_DELL_EQ) spec->init = dell_m6_core_init; switch (spec->board_config) { case STAC_DELL_M6_AMIC: /* Analog Mics */ @@ -4691,17 +4636,15 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->pwr_nids = stac92hd83xxx_pwr_nids; spec->pwr_mapping = stac92hd83xxx_pwr_mapping; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); - spec->multiout.dac_nids = stac92hd83xxx_dac_nids; + spec->multiout.dac_nids = spec->dac_nids; spec->init = stac92hd83xxx_core_init; switch (codec->vendor_id) { case 0x111d7605: - spec->multiout.num_dacs = STAC92HD81_DAC_COUNT; break; default: spec->num_pwrs--; spec->init++; /* switch to config #2 */ - spec->multiout.num_dacs = STAC92HD83_DAC_COUNT; } spec->mixer = stac92hd83xxx_mixer; @@ -4892,9 +4835,7 @@ again: spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); }; - spec->multiout.num_dacs = 1; - spec->multiout.hp_nid = 0x11; - spec->multiout.dac_nids = stac92hd71bxx_dac_nids; + spec->multiout.dac_nids = spec->dac_nids; if (spec->dinput_mux) spec->private_dimux.num_items += spec->num_dmics - From 766245348db4b047a9b53548b5b893cd5115decc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 10:09:47 +0100 Subject: [PATCH 346/367] ALSA: hda - Use more distinct name for a unique volume in STAC/IDT When the line_out has only one DAC and it's unique (i.e. not shared by other outputs), assign a more reasonable and distinct mixer name such as "Headphone" or "Speaker". Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 171400216326..6b7eeba656ed 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2949,17 +2949,30 @@ static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid) return 1; } +static int is_unique_dac(struct sigmatel_spec *spec, hda_nid_t nid) +{ + int i; + + if (spec->autocfg.line_outs != 1) + return 0; + if (spec->multiout.hp_nid == nid) + return 0; + for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) + if (spec->multiout.extra_out_nid[i] == nid) + return 0; + return 1; +} + /* 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; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid = 0; - int i, err; - - struct sigmatel_spec *spec = codec->spec; + int i, err, num_dacs; unsigned int wid_caps, pincap; for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { @@ -2985,7 +2998,19 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, } } else { - err = create_controls(spec, chname[i], nid, 3); + const char *name = chname[i]; + /* if it's a single DAC, assign a better name */ + if (!i && is_unique_dac(spec, nid)) { + switch (cfg->line_out_type) { + case AUTO_PIN_HP_OUT: + name = "Headphone"; + break; + case AUTO_PIN_SPEAKER_OUT: + name = "Speaker"; + break; + } + } + err = create_controls(spec, name, nid, 3); if (err < 0) return err; } From d4d9cd0338892e7f0d65f8a110473d175535cd5d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 15:19:11 +0100 Subject: [PATCH 347/367] ALSA: hda - Add probe_only option Added probe_only module option to hd-audio driver. This option specifies whether the driver creates and initializes the codec-parser after probing. When this option is set, the driver skips the codec parsing and initialization but gives you proc and other accesses. It's useful to see the initial codec state for debugging. The default of this value is off, so the default behavior is as same as before. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 2 ++ sound/pci/hda/hda_codec.c | 12 +++++++----- sound/pci/hda/hda_codec.h | 2 +- sound/pci/hda/hda_intel.c | 11 ++++++++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index a4f3a22caba3..ee45454c50be 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -757,6 +757,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. model - force the model name position_fix - Fix DMA pointer (0 = auto, 1 = use LPIB, 2 = POSBUF) probe_mask - Bitmask to probe codecs (default = -1, meaning all slots) + probe_only - Only probing and no codec initialization (default=off); + Useful to check the initial codec status for debugging bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. Passing -1 will make the driver to choose the appropriate value based on the controller chip. diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 625fe5984dd6..e16cf63821ae 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -709,7 +709,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) * Returns 0 if successful, or a negative error code. */ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp) + int do_init, struct hda_codec **codecp) { struct hda_codec *codec; char component[31]; @@ -793,10 +793,12 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr if (bus->modelname) codec->modelname = kstrdup(bus->modelname, GFP_KERNEL); - err = snd_hda_codec_configure(codec); - if (err < 0) { - snd_hda_codec_free(codec); - return err; + if (do_init) { + err = snd_hda_codec_configure(codec); + if (err < 0) { + snd_hda_codec_free(codec); + return err; + } } snd_hda_codec_proc_new(codec); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 5587d416229f..729fc7642d7f 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -811,7 +811,7 @@ enum { int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, struct hda_bus **busp); int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp); + int do_init, struct hda_codec **codecp); /* * low level functions diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a26ae8c4cf70..6613b6bef9eb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -58,6 +58,7 @@ static char *model[SNDRV_CARDS]; static int position_fix[SNDRV_CARDS]; 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 single_cmd; static int enable_msi; @@ -76,6 +77,8 @@ module_param_array(bdl_pos_adj, int, NULL, 0644); MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset."); module_param_array(probe_mask, int, NULL, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); +module_param_array(probe_only, bool, NULL, 0444); +MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); module_param(single_cmd, bool, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); @@ -1224,7 +1227,8 @@ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { }; static int __devinit azx_codec_create(struct azx *chip, const char *model, - unsigned int codec_probe_mask) + unsigned int codec_probe_mask, + int no_init) { struct hda_bus_template bus_temp; int c, codecs, err; @@ -1282,7 +1286,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, for (c = 0; c < max_slots; c++) { if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { struct hda_codec *codec; - err = snd_hda_codec_new(chip->bus, c, &codec); + err = snd_hda_codec_new(chip->bus, c, !no_init, &codec); if (err < 0) continue; codecs++; @@ -2340,7 +2344,8 @@ static int __devinit azx_probe(struct pci_dev *pci, card->private_data = chip; /* create codec instances */ - err = azx_codec_create(chip, model[dev], probe_mask[dev]); + err = azx_codec_create(chip, model[dev], probe_mask[dev], + probe_only[dev]); if (err < 0) goto out_free; From 9158923228822c08ed3116bfe21472261a05a725 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 15:59:40 +0100 Subject: [PATCH 348/367] ALSA: hda - Fix unused variable warnings in patch_sigmatel.c Fixed "unused varible" warnings in patch_sigmatel.c that have been introduced by the last changes. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6b7eeba656ed..d9a89ced3c89 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2972,8 +2972,8 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid = 0; - int i, err, num_dacs; - unsigned int wid_caps, pincap; + int i, err; + unsigned int wid_caps; for (i = 0; i < cfg->line_outs && spec->multiout.dac_nids[i]; i++) { nid = spec->multiout.dac_nids[i]; @@ -4033,7 +4033,6 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, * "xxx as Output" mixer switch */ struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; if (nid == spec->line_switch || nid == spec->mic_switch) return; } From eb63212868c348cc6d3ec6929d7d98f7d29493e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Dec 2008 16:39:48 +0100 Subject: [PATCH 349/367] ALSA: hda - Power up always when no jack detection is available When no jack detection is available, the pins should be always turned on since it can't be turned on/off dynamically via unsol events. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d9a89ced3c89..2cadf7c3b71b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3946,7 +3946,13 @@ static int stac92xx_init(struct hda_codec *codec) hda_nid_t nid = spec->pwr_nids[i]; int pinctl, def_conf; - if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) + /* power on when no jack detection is available */ + if (!spec->hp_detect) { + stac_toggle_power_map(codec, nid, 1); + continue; + } + + if (is_nid_hp_pin(cfg, nid)) continue; /* already has an unsol event */ pinctl = snd_hda_codec_read(codec, nid, 0, @@ -3955,8 +3961,10 @@ static int stac92xx_init(struct hda_codec *codec) * any attempts on powering down a input port cause the * referenced VREF to act quirky. */ - if (pinctl & AC_PINCTL_IN_EN) + if (pinctl & AC_PINCTL_IN_EN) { + stac_toggle_power_map(codec, nid, 1); continue; + } def_conf = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); def_conf = get_defcfg_connect(def_conf); From 50232d62cace101e03f8f40ca151b978c0db5a0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 09:42:09 +0100 Subject: [PATCH 350/367] ALSA: ca0106 - Check ac97 availability at PM Check the availability of ac97 at PM suspend/resume callbacks. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 2c71f9b896cd..e01ecd3db324 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1752,7 +1752,8 @@ static int snd_ca0106_suspend(struct pci_dev *pci, pm_message_t state) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < 4; i++) snd_pcm_suspend_all(chip->pcm[i]); - snd_ac97_suspend(chip->ac97); + if (chip->details->ac97) + snd_ac97_suspend(chip->ac97); snd_ca0106_mixer_suspend(chip); ca0106_stop_chip(chip); @@ -1781,7 +1782,8 @@ static int snd_ca0106_resume(struct pci_dev *pci) ca0106_init_chip(chip, 1); - snd_ac97_resume(chip->ac97); + if (chip->details->ac97) + snd_ac97_resume(chip->ac97); snd_ca0106_mixer_resume(chip); if (chip->details->spi_dac) { for (i = 0; i < ARRAY_SIZE(chip->spi_dac_reg); i++) From 72077aa336d0f4c5e3c7014d7471c79bc69873bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 11:12:51 +0100 Subject: [PATCH 351/367] ALSA: ca0106 - Add missing card->private_data initialization Added the missing card->private_data initialization that caused obvious problems at PM. Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index e01ecd3db324..7ead6c8a85f1 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1694,6 +1694,7 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, err = snd_ca0106_create(dev, card, pci, &chip); if (err < 0) goto error; + card->private_data = chip; for (i = 0; i < 4; i++) { err = snd_ca0106_pcm(chip, i); From ff75427a7f641c4468610fbda2ccb69218174cd1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 11:20:55 +0100 Subject: [PATCH 352/367] ALSA: ca0106 - disable 44.1kHz capture The capture with 44.1kHz on ca0106 seems to cause loud noises on later playbacks, which doesn't support 44.1kHz. A simple fix is to disable 44.1kHz, as the "default" PCM with dsnoop is anyway only with 48kHz. Reference: Novell bnc#447624 https://bugzilla.novell.com/show_bug.cgi?id=447624 Signed-off-by: Takashi Iwai --- sound/pci/ca0106/ca0106_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 88fbf285d2b7..31b5b89fc7bf 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -305,9 +305,15 @@ static struct snd_pcm_hardware snd_ca0106_capture_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, +#if 0 /* FIXME: looks like 44.1kHz capture causes noisy output on 48kHz */ .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), .rate_min = 44100, +#else + .rates = (SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), + .rate_min = 48000, +#endif /* FIXME */ .rate_max = 192000, .channels_min = 2, .channels_max = 2, From 1152a1959f8440db9536f6df758274443f9b5b37 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 18 Dec 2008 12:36:40 -0700 Subject: [PATCH 353/367] ALSA: ASoC: DaVinci: davinvi-evm, make requests explicit Add constants with a value of 0 to show more explicitly what is being requested. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-evm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index d87b91179cc8..5c041bf05f31 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -38,12 +38,14 @@ static int evm_hw_params(struct snd_pcm_substream *substream, /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM); + SND_SOC_DAIFMT_CBM_CFM | + SND_SOC_DAIFMT_NB_NF); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF); if (ret < 0) return ret; From 664b4af859d43714fd2a90aa434e454355659d0e Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 18 Dec 2008 12:36:41 -0700 Subject: [PATCH 354/367] ALSA: ASoC: DaVinci: davinci-i2s add comments to explain polarity Document the current polarity choices. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 81ff5c37ab56..156e3e95d914 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -235,18 +235,45 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_NF: + /* CLKRP Receive clock polarity, + * 1 - sampled on rising edge of CLKR + * valid on rising edge + * CLKXP Transmit clock polarity, + * 1 - clocked on falling edge of CLKX + * valid on rising edge + * FSRP Receive frame sync pol, 0 - active high + * FSXP Transmit frame sync pol, 0 - active high + */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP, 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); break; case SND_SOC_DAIFMT_NB_IF: + /* CLKRP Receive clock polarity, + * 0 - sampled on falling edge of CLKR + * valid on falling edge + * CLKXP Transmit clock polarity, + * 0 - clocked on rising edge of CLKX + * valid on falling edge + * FSRP Receive frame sync pol, 1 - active low + * FSXP Transmit frame sync pol, 1 - active low + */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP, 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); break; case SND_SOC_DAIFMT_IB_IF: + /* CLKRP Receive clock polarity, + * 1 - sampled on rising edge of CLKR + * valid on rising edge + * CLKXP Transmit clock polarity, + * 1 - clocked on falling edge of CLKX + * valid on rising edge + * FSRP Receive frame sync pol, 1 - active low + * FSXP Transmit frame sync pol, 1 - active low + */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | @@ -255,6 +282,15 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); break; case SND_SOC_DAIFMT_NB_NF: + /* CLKRP Receive clock polarity, + * 0 - sampled on falling edge of CLKR + * valid on falling edge + * CLKXP Transmit clock polarity, + * 0 - clocked on rising edge of CLKX + * valid on falling edge + * FSRP Receive frame sync pol, 0 - active high + * FSXP Transmit frame sync pol, 0 - active high + */ break; default: return -EINVAL; From 21903c1c9ecb7a210eb985aa8d82ad68c78283cc Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 18 Dec 2008 12:36:43 -0700 Subject: [PATCH 355/367] ALSA: ASoC: DaVinci: davinci-i2s clean up Just at little cleanup of davinci_i2s_set_dai_fmt Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 85 ++++++++++++++------------------- 1 file changed, 37 insertions(+), 48 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 156e3e95d914..028682846f4e 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -200,36 +200,41 @@ static int davinci_i2s_startup(struct snd_pcm_substream *substream, return 0; } +#define DEFAULT_BITPERSAMPLE 16 + static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct davinci_mcbsp_dev *dev = cpu_dai->private_data; - u32 w; + unsigned int pcr; + unsigned int srgr; + unsigned int rcr; + unsigned int xcr; + srgr = DAVINCI_MCBSP_SRGR_FSGM | + DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | + DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, - DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM | - DAVINCI_MCBSP_PCR_CLKXM | - DAVINCI_MCBSP_PCR_CLKRM); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, - DAVINCI_MCBSP_SRGR_FSGM); + /* cpu is master */ + pcr = DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM | + DAVINCI_MCBSP_PCR_CLKXM | + DAVINCI_MCBSP_PCR_CLKRM; break; case SND_SOC_DAIFMT_CBM_CFS: /* McBSP CLKR pin is the input for the Sample Rate Generator. * McBSP FSR and FSX are driven by the Sample Rate Generator. */ - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, - DAVINCI_MCBSP_PCR_SCLKME | - DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, - DAVINCI_MCBSP_SRGR_FSGM); + pcr = DAVINCI_MCBSP_PCR_SCLKME | + DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM; break; case SND_SOC_DAIFMT_CBM_CFM: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); + /* codec is master */ + pcr = 0; break; default: + printk(KERN_ERR "%s:bad master\n", __func__); return -EINVAL; } @@ -244,10 +249,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, * FSRP Receive frame sync pol, 0 - active high * FSXP Transmit frame sync pol, 0 - active high */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | - DAVINCI_MCBSP_PCR_CLKRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP); break; case SND_SOC_DAIFMT_NB_IF: /* CLKRP Receive clock polarity, @@ -259,10 +261,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, * FSRP Receive frame sync pol, 1 - active low * FSXP Transmit frame sync pol, 1 - active low */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_FSXP | - DAVINCI_MCBSP_PCR_FSRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; case SND_SOC_DAIFMT_IB_IF: /* CLKRP Receive clock polarity, @@ -274,12 +273,8 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, * FSRP Receive frame sync pol, 1 - active low * FSXP Transmit frame sync pol, 1 - active low */ - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | - DAVINCI_MCBSP_PCR_CLKRP | - DAVINCI_MCBSP_PCR_FSXP | - DAVINCI_MCBSP_PCR_FSRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | + DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; case SND_SOC_DAIFMT_NB_NF: /* CLKRP Receive clock polarity, @@ -296,28 +291,24 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } + rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); + xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(0)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(0) | - DAVINCI_MCBSP_XCR_XFIG); break; case SND_SOC_DAIFMT_I2S: - default: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(1)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(1) | - DAVINCI_MCBSP_XCR_XFIG); + case SND_SOC_DAIFMT_DSP_B: + rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); + xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); break; + default: + printk(KERN_ERR "%s:bad format\n", __func__); + return -EINVAL; } - + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); return 0; } @@ -343,12 +334,10 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, } i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); + w = DAVINCI_MCBSP_SRGR_FSGM; MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1), 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w); From 69ab820c862250d460dfaaf82164972a4a69418a Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Thu, 18 Dec 2008 12:36:44 -0700 Subject: [PATCH 356/367] ALSA: ASoC: DaVinci: davinci-i2s clean up Minor, just move a block of code to make next patch clearer. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 028682846f4e..24fe9db2c75e 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -238,6 +238,21 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } + rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); + xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_DSP_B: + rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); + xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); + break; + default: + printk(KERN_ERR "%s:bad format\n", __func__); + return -EINVAL; + } + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_IB_NF: /* CLKRP Receive clock polarity, @@ -290,21 +305,6 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, default: return -EINVAL; } - - rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); - xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_RIGHT_J: - break; - case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_DSP_B: - rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); - xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); - break; - default: - printk(KERN_ERR "%s:bad format\n", __func__); - return -EINVAL; - } davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); From 07d8d9dca4615821d928f4b5087fdc61e292e1dc Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 19 Dec 2008 13:05:24 -0700 Subject: [PATCH 357/367] ALSA: ASoC: DaVinci: document I2S limitations DaVinci does not support true I2S or right justified mode so not all I2S codecs will work with it when the codec is master. Document this limitation. Add dsp_a, dsp_b mode options Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 24fe9db2c75e..51ceded8a245 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -241,10 +241,27 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_DSP_B: break; case SND_SOC_DAIFMT_I2S: - case SND_SOC_DAIFMT_DSP_B: + /* Davinci doesn't support TRUE I2S, but some codecs will have + * the left and right channels contiguous. This allows + * dsp_a mode to be used with an inverted normal frame clk. + * If your codec is master and does not have contiguous + * channels, then you will have sound on only one channel. + * Try using a different mode, or codec as slave. + * + * The TLV320AIC33 is an example of a codec where this works. + * It has a variable bit clock frequency allowing it to have + * valid data on every bit clock. + * + * The TLV320AIC23 is an example of a codec where this does not + * work. It has a fixed bit clock frequency with progressively + * more empty bit clock slots between channels as the sample + * rate is lowered. + */ + fmt ^= SND_SOC_DAIFMT_NB_IF; + case SND_SOC_DAIFMT_DSP_A: rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); break; From a24f4f682661b8069d374a9197bc491525a7c799 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 19 Dec 2008 13:05:22 -0700 Subject: [PATCH 358/367] ALSA: ASoC: tlv320aic3x add dsp_a Add SND_SOC_DAIFMT_DSP_A mode option. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 4 ++++ sound/soc/codecs/tlv320aic3x.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 8da9e5d2e2fb..b47a749c5ea2 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -891,6 +891,7 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; struct aic3x_priv *aic3x = codec->private_data; u8 iface_areg, iface_breg; + int delay = 0; iface_areg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; iface_breg = aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; @@ -916,6 +917,8 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, SND_SOC_DAIFMT_INV_MASK)) { case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): break; + case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF): + delay = 1; case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF): iface_breg |= (0x01 << 6); break; @@ -932,6 +935,7 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set iface */ aic3x_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); + aic3x_write(codec, AIC3X_ASD_INTF_CTRLC, delay); return 0; } diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 73e35b6ec929..ac827e578c4d 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -35,6 +35,8 @@ #define AIC3X_ASD_INTF_CTRLA 8 /* Audio serial data interface control register B */ #define AIC3X_ASD_INTF_CTRLB 9 +/* Audio serial data interface control register C */ +#define AIC3X_ASD_INTF_CTRLC 10 /* Audio overflow status and PLL R value programming register */ #define AIC3X_OVRF_STATUS_AND_PLLR_REG 11 /* Audio codec digital filter control register */ From 9e031624d50c82a47671e09cc996eebb9e36f698 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 19 Dec 2008 13:05:23 -0700 Subject: [PATCH 359/367] ALSA: ASoC: DaVinci: i2s, evm, pass same value to codec and cpu_dai Fix the meaning of SND_SOC_DAIFMT_NB_NF to match that used in the codec. Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-evm.c | 10 ++++------ sound/soc/davinci/davinci-i2s.c | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 5c041bf05f31..d2476e206a87 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -28,6 +28,8 @@ #define EVM_CODEC_CLOCK 22579200 +#define AUDIO_FORMAT (SND_SOC_DAIFMT_I2S | \ + SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF) static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -37,16 +39,12 @@ static int evm_hw_params(struct snd_pcm_substream *substream, int ret = 0; /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_NB_NF); + ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_IB_NF); + ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); if (ret < 0) return ret; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 51ceded8a245..0fee779e3c76 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -271,7 +271,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_NF: + case SND_SOC_DAIFMT_NB_NF: /* CLKRP Receive clock polarity, * 1 - sampled on rising edge of CLKR * valid on rising edge @@ -283,7 +283,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, */ pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP); break; - case SND_SOC_DAIFMT_NB_IF: + case SND_SOC_DAIFMT_IB_IF: /* CLKRP Receive clock polarity, * 0 - sampled on falling edge of CLKR * valid on falling edge @@ -295,7 +295,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, */ pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; - case SND_SOC_DAIFMT_IB_IF: + case SND_SOC_DAIFMT_NB_IF: /* CLKRP Receive clock polarity, * 1 - sampled on rising edge of CLKR * valid on rising edge @@ -308,7 +308,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; - case SND_SOC_DAIFMT_NB_NF: + case SND_SOC_DAIFMT_IB_NF: /* CLKRP Receive clock polarity, * 0 - sampled on falling edge of CLKR * valid on falling edge From d6f833965e594015ee05341e43ff4a86f11596b3 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 19 Dec 2008 13:05:25 -0700 Subject: [PATCH 360/367] ALSA: ASoc: DaVinci: davinci-evm use dsp_b mode Sense DaVinci does not support true I2S mode and we don't have to use the hack, use dsp_b mode instead Signed-off-by: Troy Kisky Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-evm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index d2476e206a87..01b948bb55a1 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -28,8 +28,8 @@ #define EVM_CODEC_CLOCK 22579200 -#define AUDIO_FORMAT (SND_SOC_DAIFMT_I2S | \ - SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_NF) +#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ + SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { From a31501d1041c9d0a6c3f520736ae2b2fa081493a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 16:50:53 +0100 Subject: [PATCH 361/367] ALSA: ASoC - Add missing __devexit annotation to wm8350.c Added the missing __devexit annotation to wm8350_codec_remove(): sound/soc/codecs/wm8350.c:1546: warning: 'wm8350_codec_remove' defined but not used Signed-off-by: Takashi Iwai --- sound/soc/codecs/wm8350.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 4bbfb5a5894b..e3989d406f54 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1542,7 +1542,7 @@ err_priv: return ret; } -static int wm8350_codec_remove(struct platform_device *pdev) +static int __devexit wm8350_codec_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct snd_soc_codec *codec = wm8350->codec.codec; From 69dfaefee4a2dfdfee3488a306403fe1e51f0be5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 20 Dec 2008 16:57:50 +0100 Subject: [PATCH 362/367] ALSA: hda - Add quirk for another HP dv7 Added the model=hp-m4 quirk for another HP dv7 (103c:30fc) with IDT 92HD71b* codec. Reference: Novell bnc#461108 https://bugzilla.novell.com/show_bug.cgi?id=461108 Cc: stable@kernel.org Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2cadf7c3b71b..e2941cd8aeea 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1731,6 +1731,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP dv5", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30f4, "HP dv7", STAC_HP_M4), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fc, + "HP dv7", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a, "unknown HP", STAC_HP_M4), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, From f8ccbf65afde5df81a6238b9dc92868fbbd397f7 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 20 Dec 2008 17:36:28 -0500 Subject: [PATCH 363/367] ALSA: hda: dinput_mux check Add check to determine if dinput_mux is set by any of patch_stac*() functions, otherwise a invalid pointer my be referenced causing gibberish to mixer values. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index e2941cd8aeea..7ee4d4df8932 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3589,7 +3589,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out spec->mixers[spec->num_mixers++] = spec->kctls.list; spec->input_mux = &spec->private_imux; - spec->dinput_mux = &spec->private_dimux; + if (!spec->dinput_mux) + spec->dinput_mux = &spec->private_dimux; spec->sinput_mux = &spec->private_smux; spec->mono_mux = &spec->private_mono_mux; spec->amp_mux = &spec->private_amp_mux; From 74b7ff48a93f44198ac03cc4e628d713f53d4668 Mon Sep 17 00:00:00 2001 From: Matthew Ranostay Date: Sat, 20 Dec 2008 17:47:24 -0500 Subject: [PATCH 364/367] ALSA: hda: fix incorrect mixer index values for 92hd83xx Fixed incorrect mixer index values for 92hd83xx codec's audio input mixer. Signed-off-by: Matthew Ranostay Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7ee4d4df8932..71d3a773e94b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1063,21 +1063,21 @@ static struct snd_kcontrol_new stac92hd83xxx_mixer[] = { HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0, HDA_INPUT), - HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0, HDA_INPUT), + HDA_CODEC_VOLUME("DAC0 Capture Volume", 0x1b, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("DAC0 Capture Switch", 0x1b, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("DAC1 Capture Volume", 0x1b, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("DAC1 Capture Switch", 0x1b, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Capture Volume", 0x1b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Capture Switch", 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Line In Capture Volume", 0x1b, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("Line In Capture Switch", 0x1b, 0x2, HDA_INPUT), /* - HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Capture Volume", 0x1b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Capture Switch", 0x1b 0x1, HDA_INPUT), */ { } /* end */ }; From bd25867a6cbe7a00ef7dbe8d9ddebc91b00b9b3f Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 22 Dec 2008 10:21:36 +0200 Subject: [PATCH 365/367] ASoC: Fix incorrect DSP format in OMAP McBSP DAI and affected drivers - OMAP McBSP DAI driver claims to support DSP_A format which has 1-bit data delay but configures link for 0-bit data delay which is in fact DSP_B - Fix this by changing format from DSP_A to DSP_B - Fix also TLV320AIC23 codec and OSK5912 machine drivers since the same error is populated also there Signed-off-by: Jarkko Nikula Acked-by: Arun KS Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic23.c | 2 +- sound/soc/omap/omap-mcbsp.c | 4 ++-- sound/soc/omap/osk5912.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 39f5b981d25a..cfdea007c4cb 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -541,7 +541,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_I2S: iface_reg |= TLV320AIC23_FOR_I2S; break; - case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: iface_reg |= TLV320AIC23_FOR_DSP; break; case SND_SOC_DAIFMT_RIGHT_J: diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 7b86373007ca..ec5e18a78758 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -270,7 +270,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, regs->srgr2 |= FPER(wlen * 2 - 1); regs->srgr1 |= FWID(wlen - 1); break; - case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: regs->srgr2 |= FPER(wlen * channels - 1); regs->srgr1 |= FWID(wlen * channels - 2); break; @@ -309,7 +309,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, regs->rcr2 |= RDATDLY(1); regs->xcr2 |= XDATDLY(1); break; - case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: /* 0-bit data delay */ regs->rcr2 |= RDATDLY(0); regs->xcr2 |= XDATDLY(0); diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index 845bf41335b9..cd41a948df7b 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -61,7 +61,7 @@ static int osk_hw_params(struct snd_pcm_substream *substream, /* Set codec DAI configuration */ err = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBM_CFM); if (err < 0) { @@ -71,7 +71,7 @@ static int osk_hw_params(struct snd_pcm_substream *substream, /* Set cpu DAI configuration */ err = snd_soc_dai_set_fmt(cpu_dai, - SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBM_CFM); if (err < 0) { From c69134858722977a82f58cae88e7ffdb28e1e858 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 22 Dec 2008 10:57:33 +0200 Subject: [PATCH 366/367] ASoC: Fix DSP formats in SSM2602 audio codec Thanks to Troy Kisky for noticing. - DSP_A format has 1-bit data delay which corresponds to SSM6202 submode 2 - DSP_B has 0-bit data delay which corresponds to submode 1 - Currently driver sets them opposite so swap the submode setting Signed-off-by: Jarkko Nikula Cc: Cliff Cai Signed-off-by: Mark Brown --- sound/soc/codecs/ssm2602.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 2325aefea411..cac373616768 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -454,10 +454,10 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, iface |= 0x0001; break; case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; + iface |= 0x0013; break; case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0013; + iface |= 0x0003; break; default: return -EINVAL; From 472346da9cc4231bec03ff2032e0d5fd4037232c Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 22 Dec 2008 17:40:45 +0100 Subject: [PATCH 367/367] ALSA: ASoC: fix a typo in omp-pcm.c Fix a typo (& and &&) Signed-off-by: Roel Kluin Signed-off-by: Liam Girdwood Signed-off-by: Takashi Iwai --- sound/soc/omap/omap-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 803581c9280d..b0362dfd5b71 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -97,7 +97,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, prtd->dma_data = dma_data; err = omap_request_dma(dma_data->dma_req, dma_data->name, omap_pcm_dma_irq, substream, &prtd->dma_ch); - if (!err & !cpu_is_omap1510()) { + if (!err && !cpu_is_omap1510()) { /* * Link channel with itself so DMA doesn't need any * reprogramming while looping the buffer