From b6f4bb383d69cac46f17e2305720f9a3d426c5ed Mon Sep 17 00:00:00 2001 From: "apatard@mandriva.com" Date: Sat, 15 May 2010 17:30:01 +0200 Subject: ASoC: Add SOC_DOUBLE_R_SX_TLV control This patch is adding a new control which has the following capabilities: - tlv - variable data size (for instance, 7 ou 8 bit) - double mixer - data range centered around 0 Signed-off-by: Arnaud Patard Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'include') diff --git a/include/sound/soc.h b/include/sound/soc.h index 697e7ffe39d7..65e9d03ed4f5 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -170,6 +170,21 @@ .get = xhandler_get, .put = xhandler_put, \ .private_value = (unsigned long)&xenum } +#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\ + xmin, xmax, 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_sx, \ + .get = snd_soc_get_volsw_2r_sx, \ + .put = snd_soc_put_volsw_2r_sx, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg_left, \ + .rreg = xreg_right, .shift = xshift, \ + .min = xmin, .max = xmax} } + + /* * Simplified versions of above macros, declaring a struct and calculating * ARRAY_SIZE internally @@ -329,6 +344,12 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_limit_volume(struct snd_soc_codec *codec, const char *name, int max); +int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); /** * struct snd_soc_jack_pin - Describes a pin to update based on jack detection -- cgit v1.2.3-59-g8ed1b From 15c0cee6c809a137e0fc7f1d2b0867cc03473c0c Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 28 May 2010 11:43:45 -0400 Subject: ALSA: pcm: Define G723 3-bit and 5-bit formats This defines the 24bps and 40bps (8khz sample rate) G.723 codec formats. They are going to be used once I submit the driver for an mpeg4/g723 compression card. I've updated the signed value to -1 as per Takashi's comments since these are non-linear formats. Signed-off-by: Ben Collins Signed-off-by: Takashi Iwai --- include/sound/asound.h | 6 +++++- include/sound/pcm.h | 4 ++++ sound/core/pcm_misc.c | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/sound/asound.h b/include/sound/asound.h index 9f1eecf99e6b..a1803ecea34d 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h @@ -212,7 +212,11 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */ #define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */ #define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */ -#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_U18_3BE +#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */ +#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ +#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ +#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B #ifdef SNDRV_LITTLE_ENDIAN #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE diff --git a/include/sound/pcm.h b/include/sound/pcm.h index dd76cdede64d..07fd630db88d 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -174,6 +174,10 @@ struct snd_pcm_ops { #define SNDRV_PCM_FMTBIT_U18_3LE (1ULL << SNDRV_PCM_FORMAT_U18_3LE) #define SNDRV_PCM_FMTBIT_S18_3BE (1ULL << SNDRV_PCM_FORMAT_S18_3BE) #define SNDRV_PCM_FMTBIT_U18_3BE (1ULL << SNDRV_PCM_FORMAT_U18_3BE) +#define SNDRV_PCM_FMTBIT_G723_24 (1ULL << SNDRV_PCM_FORMAT_G723_24) +#define SNDRV_PCM_FMTBIT_G723_24_1B (1ULL << SNDRV_PCM_FORMAT_G723_24_1B) +#define SNDRV_PCM_FMTBIT_G723_40 (1ULL << SNDRV_PCM_FORMAT_G723_40) +#define SNDRV_PCM_FMTBIT_G723_40_1B (1ULL << SNDRV_PCM_FORMAT_G723_40_1B) #ifdef SNDRV_LITTLE_ENDIAN #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index ea2bf82c9373..434af3c56d52 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -128,6 +128,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = { .width = 4, .phys = 4, .le = -1, .signd = -1, .silence = {}, }, + [SNDRV_PCM_FORMAT_G723_24] = { + .width = 3, .phys = 3, .le = -1, .signd = -1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_G723_40] = { + .width = 5, .phys = 5, .le = -1, .signd = -1, + .silence = {}, + }, /* FIXME: the following three formats are not defined properly yet */ [SNDRV_PCM_FORMAT_MPEG] = { .le = -1, .signd = -1, @@ -186,6 +194,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = { .width = 18, .phys = 24, .le = 0, .signd = 0, .silence = { 0x02, 0x00, 0x00 }, }, + [SNDRV_PCM_FORMAT_G723_24_1B] = { + .width = 3, .phys = 8, .le = -1, .signd = -1, + .silence = {}, + }, + [SNDRV_PCM_FORMAT_G723_40_1B] = { + .width = 5, .phys = 8, .le = -1, .signd = -1, + .silence = {}, + }, }; -- cgit v1.2.3-59-g8ed1b From ea762b047e13ba1cba4d58323b5c00a566610198 Mon Sep 17 00:00:00 2001 From: "apatard@mandriva.com" Date: Thu, 27 May 2010 14:57:40 +0200 Subject: ASoC: Add SND_SOC_DAPM_PRE_POST_PMD event Some systems codecs need to configure some registers before and after powering down some of their part. As a convenience add a macro for that. Signed-off-by: Arnaud Patard Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 66ff4c124dbd..c5d9987bc897 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -273,6 +273,8 @@ #define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */ #define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */ #define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */ +#define SND_SOC_DAPM_PRE_POST_PMD \ + (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD) /* convenience event type detection */ #define SND_SOC_DAPM_EVENT_ON(e) \ -- cgit v1.2.3-59-g8ed1b From 69da9bcb98ccbfb5d5f751bc13418f1307332925 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 16 Jun 2010 17:57:28 +0200 Subject: ALSA: usb-audio: unify UAC macros and struct names Get rid of the last occurances of _v1 suffixes, and move the version number right after the "uac" string. Now things are consitent again. Sorry for the forth and back, but it just looks much nicer this way. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- drivers/usb/gadget/f_audio.c | 6 +++--- drivers/usb/gadget/gmidi.c | 2 +- include/linux/usb/audio-v2.h | 2 +- include/linux/usb/audio.h | 12 ++++++------ sound/usb/card.c | 2 +- sound/usb/endpoint.c | 4 ++-- sound/usb/mixer.c | 14 +++++++------- 7 files changed, 21 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index b91115f84b13..1f48ceb55a77 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -61,7 +61,7 @@ DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \ + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0)) /* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac_ac_header_descriptor_v1_2 ac_header_desc = { +static struct uac1_ac_header_descriptor_2 ac_header_desc = { .bLength = UAC_DT_AC_HEADER_LENGTH, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_HEADER, @@ -125,7 +125,7 @@ static struct usb_audio_control_selector feature_unit = { }; #define OUTPUT_TERMINAL_ID 3 -static struct uac_output_terminal_descriptor_v1 output_terminal_desc = { +static struct uac1_output_terminal_descriptor output_terminal_desc = { .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, @@ -155,7 +155,7 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = { }; /* B.4.2 Class-Specific AS Interface Descriptor */ -static struct uac_as_header_descriptor_v1 as_header_desc = { +static struct uac1_as_header_descriptor as_header_desc = { .bLength = UAC_DT_AS_HEADER_SIZE, .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = UAC_AS_GENERAL, diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 2b56ce621852..b7bf88019b06 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -238,7 +238,7 @@ static const struct usb_interface_descriptor ac_interface_desc = { }; /* B.3.2 Class-Specific AC Interface Descriptor */ -static const struct uac_ac_header_descriptor_v1_1 ac_header_desc = { +static const struct uac1_ac_header_descriptor_1 ac_header_desc = { .bLength = UAC_DT_AC_HEADER_SIZE(1), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubtype = USB_MS_HEADER, diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 383b94ba8c20..716aebe339e8 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -121,7 +121,7 @@ struct uac2_feature_unit_descriptor { /* 4.9.2 Class-Specific AS Interface Descriptor */ -struct uac_as_header_descriptor_v2 { +struct uac2_as_header_descriptor { __u8 bLength; __u8 bDescriptorType; __u8 bDescriptorSubtype; diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index c51200c715e5..a54b8255d75f 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h @@ -39,8 +39,8 @@ #define UAC_MIXER_UNIT 0x04 #define UAC_SELECTOR_UNIT 0x05 #define UAC_FEATURE_UNIT 0x06 -#define UAC_PROCESSING_UNIT_V1 0x07 -#define UAC_EXTENSION_UNIT_V1 0x08 +#define UAC1_PROCESSING_UNIT 0x07 +#define UAC1_EXTENSION_UNIT 0x08 /* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */ #define UAC_AS_GENERAL 0x01 @@ -151,7 +151,7 @@ /* Terminal Control Selectors */ /* 4.3.2 Class-Specific AC Interface Descriptor */ -struct uac_ac_header_descriptor_v1 { +struct uac1_ac_header_descriptor { __u8 bLength; /* 8 + n */ __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ __u8 bDescriptorSubtype; /* UAC_MS_HEADER */ @@ -165,7 +165,7 @@ struct uac_ac_header_descriptor_v1 { /* As above, but more useful for defining your own descriptors: */ #define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n) \ -struct uac_ac_header_descriptor_v1_##n { \ +struct uac1_ac_header_descriptor_##n { \ __u8 bLength; \ __u8 bDescriptorType; \ __u8 bDescriptorSubtype; \ @@ -205,7 +205,7 @@ struct uac_input_terminal_descriptor { #define UAC_TERMINAL_CS_COPY_PROTECT_CONTROL 0x01 /* 4.3.2.2 Output Terminal Descriptor */ -struct uac_output_terminal_descriptor_v1 { +struct uac1_output_terminal_descriptor { __u8 bLength; /* in bytes: 9 */ __u8 bDescriptorType; /* CS_INTERFACE descriptor type */ __u8 bDescriptorSubtype; /* OUTPUT_TERMINAL descriptor subtype */ @@ -395,7 +395,7 @@ static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_desc } /* 4.5.2 Class-Specific AS Interface Descriptor */ -struct uac_as_header_descriptor_v1 { +struct uac1_as_header_descriptor { __u8 bLength; /* in bytes: 7 */ __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ __u8 bDescriptorSubtype; /* AS_GENERAL */ diff --git a/sound/usb/card.c b/sound/usb/card.c index 7a8ac1d81be7..9feb00c831a0 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -217,7 +217,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) switch (protocol) { case UAC_VERSION_1: { - struct uac_ac_header_descriptor_v1 *h1 = control_header; + struct uac1_ac_header_descriptor *h1 = control_header; if (!h1->bInCollection) { snd_printk(KERN_INFO "skipping empty audio interface (v1)\n"); diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 6f6596cf2b19..2af0f9e3dcdf 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -275,7 +275,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) /* get audio formats */ switch (protocol) { case UAC_VERSION_1: { - struct uac_as_header_descriptor_v1 *as = + struct uac1_as_header_descriptor *as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); if (!as) { @@ -297,7 +297,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) case UAC_VERSION_2: { struct uac2_input_terminal_descriptor *input_term; struct uac2_output_terminal_descriptor *output_term; - struct uac_as_header_descriptor_v2 *as = + struct uac2_as_header_descriptor *as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); if (!as) { diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 736d134cc03c..ba54eb6bb0c9 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -582,9 +582,9 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm switch (iterm->type >> 16) { case UAC_SELECTOR_UNIT: strcpy(name, "Selector"); return 8; - case UAC_PROCESSING_UNIT_V1: + case UAC1_PROCESSING_UNIT: strcpy(name, "Process Unit"); return 12; - case UAC_EXTENSION_UNIT_V1: + case UAC1_EXTENSION_UNIT: strcpy(name, "Ext Unit"); return 8; case UAC_MIXER_UNIT: strcpy(name, "Mixer"); return 5; @@ -672,8 +672,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ term->name = uac_selector_unit_iSelector(d); return 0; } - case UAC_PROCESSING_UNIT_V1: - case UAC_EXTENSION_UNIT_V1: { + case UAC1_PROCESSING_UNIT: + case UAC1_EXTENSION_UNIT: { struct uac_processing_unit_descriptor *d = p1; if (d->bNrInPins) { id = d->baSourceID[0]; @@ -1855,13 +1855,13 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) return parse_audio_selector_unit(state, unitid, p1); case UAC_FEATURE_UNIT: return parse_audio_feature_unit(state, unitid, p1); - case UAC_PROCESSING_UNIT_V1: + case UAC1_PROCESSING_UNIT: /* UAC2_EFFECT_UNIT has the same value */ if (state->mixer->protocol == UAC_VERSION_1) return parse_audio_processing_unit(state, unitid, p1); else return 0; /* FIXME - effect units not implemented yet */ - case UAC_EXTENSION_UNIT_V1: + case UAC1_EXTENSION_UNIT: /* UAC2_PROCESSING_UNIT_V2 has the same value */ if (state->mixer->protocol == UAC_VERSION_1) return parse_audio_extension_unit(state, unitid, p1); @@ -1925,7 +1925,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) p = NULL; while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { if (mixer->protocol == UAC_VERSION_1) { - struct uac_output_terminal_descriptor_v1 *desc = p; + struct uac1_output_terminal_descriptor *desc = p; if (desc->bLength < sizeof(*desc)) continue; /* invalid descriptor? */ -- cgit v1.2.3-59-g8ed1b From 157a57b6fae7d3c6d24b7623dcc6679c6d244621 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 16 Jun 2010 17:57:30 +0200 Subject: ALSA: usb-audio: move and add some comments Also add a list of open topics. Signed-off-by: Daniel Mack Signed-off-by: Takashi Iwai --- include/linux/usb/audio-v2.h | 15 +++++++++++++++ sound/usb/clock.c | 16 ++++++++++++++-- sound/usb/mixer.c | 24 ++++++++++++++++-------- 3 files changed, 45 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 716aebe339e8..964cb603f7c7 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -18,6 +18,21 @@ /* v1.0 and v2.0 of this standard have many things in common. For the rest * of the definitions, please refer to audio.h */ +/* + * bmControl field decoders + * + * From the USB Audio spec v2.0: + * + * bmaControls() is a (ch+1)-element array of 4-byte bitmaps, + * each containing a set of bit pairs. If a Control is present, + * it must be Host readable. If a certain Control is not + * present then the bit pair must be set to 0b00. + * If a Control is present but read-only, the bit pair must be + * set to 0b01. If a Control is also Host programmable, the bit + * pair must be set to 0b11. The value 0b10 is not allowed. + * + */ + static inline bool uac2_control_is_readable(u32 bmControls, u8 control) { return (bmControls >> (control * 2)) & 0x1; diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 386b09c5ce73..7279d6190875 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -120,8 +120,6 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) return !!data; } -/* Try to find the clock source ID of a given clock entity */ - static int __uac_clock_find_source(struct snd_usb_audio *chip, struct usb_host_interface *host_iface, int entity_id, unsigned long *visited) @@ -154,6 +152,8 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, if (ret < 0) return ret; + /* Selector values are one-based */ + if (ret > selector->bNrInPins || ret < 1) { printk(KERN_ERR "%s(): selector reported illegal value, id %d, ret %d\n", @@ -176,6 +176,17 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip, return -EINVAL; } +/* + * For all kinds of sample rate settings and other device queries, + * the clock source (end-leaf) must be used. However, clock selectors, + * clock multipliers and sample rate converters may be specified as + * clock source input to terminal. This functions walks the clock path + * to its end and tries to find the source. + * + * The 'visited' bitfield is used internally to detect recursive loops. + * + * Returns the clock source UnitID (>=0) on success, or an error. + */ int snd_usb_clock_find_source(struct snd_usb_audio *chip, struct usb_host_interface *host_iface, int entity_id) @@ -246,6 +257,7 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, return clock; if (!uac_clock_source_is_valid(chip, clock)) { + /* TODO: should we try to find valid clock setups by ourself? */ snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n", dev->devnum, iface, fmt->altsetting, clock); return -ENXIO; diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index ba54eb6bb0c9..1163ec3ca8a0 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -26,6 +26,22 @@ * */ +/* + * TODOs, for both the mixer and the streaming interfaces: + * + * - support for UAC2 effect units + * - support for graphical equalizers + * - RANGE and MEM set commands (UAC2) + * - RANGE and MEM interrupt dispatchers (UAC2) + * - audio channel clustering (UAC2) + * - audio sample rate converter units (UAC2) + * - proper handling of clock multipliers (UAC2) + * - dispatch clock change notifications (UAC2) + * - stop PCM streams which use a clock that became invalid + * - stop PCM streams which use a clock selector that has changed + * - parse available sample rates again when clock sources changed + */ + #include #include #include @@ -1199,14 +1215,6 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void } } else { /* UAC_VERSION_2 */ for (i = 0; i < 30/2; i++) { - /* From the USB Audio spec v2.0: - bmaControls() is a (ch+1)-element array of 4-byte bitmaps, - each containing a set of bit pairs. If a Control is present, - it must be Host readable. If a certain Control is not - present then the bit pair must be set to 0b00. - If a Control is present but read-only, the bit pair must be - set to 0b01. If a Control is also Host programmable, the bit - pair must be set to 0b11. The value 0b10 is not allowed. */ unsigned int ch_bits = 0; unsigned int ch_read_only = 0; -- cgit v1.2.3-59-g8ed1b From cc3202f5da3c81a99c5f3a605df527da7a77eed3 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 24 Jun 2010 17:38:50 +0400 Subject: ASoC: uda134x: replace a macro with a value in platform struct. This change wipes out a hardcoded macro, which enables codec bias level control. Now is_powered_on_standby value shall be used instead. Signed-off-by: Vladimir Zapolskiy Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/uda134x.h | 12 ++++++++++++ sound/soc/codecs/uda134x.c | 21 +++++---------------- 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h index 509efb050176..e475659bd3be 100644 --- a/include/sound/uda134x.h +++ b/include/sound/uda134x.h @@ -18,6 +18,18 @@ struct uda134x_platform_data { struct l3_pins l3; void (*power) (int); int model; + /* + ALSA SOC usually puts the device in standby mode when it's not used + for sometime. If you unset is_powered_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 + set is_powered_on_standby, 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. + */ + int is_powered_on_standby; #define UDA134X_UDA1340 1 #define UDA134X_UDA1341 2 #define UDA134X_UDA1344 3 diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 28aac53c97bb..30cf2f9d3298 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -28,19 +28,6 @@ #include "uda134x.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) @@ -531,9 +518,11 @@ static int uda134x_soc_probe(struct platform_device *pdev) 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 + + if (!pd->is_powered_on_standby) { + codec->set_bias_level = uda134x_set_bias_level; + } + INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); -- cgit v1.2.3-59-g8ed1b From 5daeba34d2aab669aea07abee13d53cd116578fb Mon Sep 17 00:00:00 2001 From: David Dillow Date: Sun, 27 Jun 2010 00:13:20 +0200 Subject: ALSA: pcm_lib: avoid timing jitter in snd_pcm_read/write() When using poll() to wait for the next period -- or avail_min samples -- one gets a consistent delay for each system call that is usually just a little short of the selected period time. However, When using snd_pcm_read/write(), one gets a jittery delay that alternates between less than a millisecond and approximately two period times. This is caused by snd_pcm_lib_{read,write}1() transferring any available samples to the user's buffer and adjusting the application pointer prior to sleeping to the end of the current period. When the next period interrupt occurs, there is then less than avail_min samples remaining to be transferred in the period, so we end up sleeping until a second period occurs. This is solved by using runtime->twake as the number of samples needed for a wakeup in addition to selecting the proper wait queue to wake in snd_pcm_update_state(). This requires twake to be non-zero when used by snd_pcm_lib_{read,write}1() even if avail_min is zero. Signed-off-by: Dave Dillow Signed-off-by: Jaroslav Kysela --- include/sound/pcm.h | 2 +- sound/core/pcm_lib.c | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index dd76cdede64d..83c6fa6aac43 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -313,7 +313,7 @@ struct snd_pcm_runtime { struct snd_pcm_mmap_control *control; /* -- locking / scheduling -- */ - unsigned int twake: 1; /* do transfer (!poll) wakeup */ + snd_pcm_uframes_t twake; /* do transfer (!poll) wakeup if non-zero */ wait_queue_head_t sleep; /* poll sleep */ wait_queue_head_t tsleep; /* transfer sleep */ struct fasync_struct *fasync; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e9d98be190c5..bcf95d3ff5c7 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -287,8 +287,11 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, return -EPIPE; } } - if (avail >= runtime->control->avail_min) - wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep); + if (runtime->twake) { + if (avail >= runtime->twake) + wake_up(&runtime->tsleep); + } else if (avail >= runtime->control->avail_min) + wake_up(&runtime->sleep); return 0; } @@ -1707,7 +1710,7 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed); * The available space is stored on availp. When err = 0 and avail = 0 * on the capture stream, it indicates the stream is in DRAINING state. */ -static int wait_for_avail_min(struct snd_pcm_substream *substream, +static int wait_for_avail(struct snd_pcm_substream *substream, snd_pcm_uframes_t *availp) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -1757,7 +1760,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, avail = snd_pcm_playback_avail(runtime); else avail = snd_pcm_capture_avail(runtime); - if (avail >= runtime->control->avail_min) + if (avail >= runtime->twake) break; } _endloop: @@ -1820,7 +1823,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->twake = 1; + runtime->twake = runtime->control->avail_min ? : 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -1833,7 +1836,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, err = -EAGAIN; goto _end_unlock; } - err = wait_for_avail_min(substream, &avail); + runtime->twake = min_t(snd_pcm_uframes_t, size, + runtime->control->avail_min ? : 1); + err = wait_for_avail(substream, &avail); if (err < 0) goto _end_unlock; } @@ -2042,7 +2047,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->twake = 1; + runtime->twake = runtime->control->avail_min ? : 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -2060,7 +2065,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, err = -EAGAIN; goto _end_unlock; } - err = wait_for_avail_min(substream, &avail); + runtime->twake = min_t(snd_pcm_uframes_t, size, + runtime->control->avail_min ? : 1); + err = wait_for_avail(substream, &avail); if (err < 0) goto _end_unlock; if (!avail) -- cgit v1.2.3-59-g8ed1b From 095687c48b2e3b9f849554ab7a65e74988d50269 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 13 Jul 2010 18:13:19 +0900 Subject: ASoC: fsi: modify format area definition on flags There is no necessity that each bit in this area has the meaning. This patch modify it to sequence number Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/sh_fsi.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index c0227361a876..3ecdb965b890 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -55,12 +55,12 @@ #define SH_FSI_GET_IFMT(x) ((x >> 8) & SH_FSI_FMT_MASK) #define SH_FSI_GET_OFMT(x) ((x >> 0) & SH_FSI_FMT_MASK) -#define SH_FSI_FMT_MONO (1 << 0) -#define SH_FSI_FMT_MONO_DELAY (1 << 1) -#define SH_FSI_FMT_PCM (1 << 2) -#define SH_FSI_FMT_I2S (1 << 3) -#define SH_FSI_FMT_TDM (1 << 4) -#define SH_FSI_FMT_TDM_DELAY (1 << 5) +#define SH_FSI_FMT_MONO 0 +#define SH_FSI_FMT_MONO_DELAY 1 +#define SH_FSI_FMT_PCM 2 +#define SH_FSI_FMT_I2S 3 +#define SH_FSI_FMT_TDM 4 +#define SH_FSI_FMT_TDM_DELAY 5 #define SH_FSI_IFMT_TDM_CH(x) \ (SH_FSI_IFMT(TDM) | SH_FSI_SET_CH_I(x)) -- cgit v1.2.3-59-g8ed1b From ccad7b44ccdc8341c1449bc5b864b42b197f8c2e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 13 Jul 2010 12:13:14 +0900 Subject: ASoC: fsi: Fixup for master mode This patch add hw_params to snd_soc_dai_ops, because board specific set_rate is needed when FSI was used as master mode. This patch remove fsi_clk_ctrl from fsi_dai_startup, because clock should be disabled before set_rate. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/sh_fsi.h | 32 +++++++++++++++++ sound/soc/sh/fsi.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 124 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 3ecdb965b890..2c6237e6c045 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -72,9 +72,41 @@ #define SH_FSI_OFMT_TDM_DELAY_CH(x) \ (SH_FSI_OFMT(TDM_DELAY) | SH_FSI_SET_CH_O(x)) + +/* + * set_rate return value + * + * see ACKMD/BPFMD on + * ACK_MD (FSI2) + * CKG1 (FSI) + * + * err: return value < 0 + * + * 0x-00000AB + * + * A: ACKMD value + * B: BPFMD value + */ + +#define SH_FSI_ACKMD_MASK (0xF << 0) +#define SH_FSI_ACKMD_512 (1 << 0) +#define SH_FSI_ACKMD_256 (2 << 0) +#define SH_FSI_ACKMD_128 (3 << 0) +#define SH_FSI_ACKMD_64 (4 << 0) +#define SH_FSI_ACKMD_32 (5 << 0) + +#define SH_FSI_BPFMD_MASK (0xF << 4) +#define SH_FSI_BPFMD_512 (1 << 4) +#define SH_FSI_BPFMD_256 (2 << 4) +#define SH_FSI_BPFMD_128 (3 << 4) +#define SH_FSI_BPFMD_64 (4 << 4) +#define SH_FSI_BPFMD_32 (5 << 4) +#define SH_FSI_BPFMD_16 (6 << 4) + struct sh_fsi_platform_info { unsigned long porta_flags; unsigned long portb_flags; + int (*set_rate)(int is_porta, int rate); /* for master mode */ }; extern struct snd_soc_dai fsi_soc_dai[2]; diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index e551ca45f03e..a1ce6089177c 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -65,6 +65,10 @@ #define ERR_UNDER 0x00000001 #define ST_ERR (ERR_OVER | ERR_UNDER) +/* CKG1 */ +#define ACKMD_MASK 0x00007000 +#define BPFMD_MASK 0x00000700 + /* CLK_RST */ #define B_CLK 0x00000010 #define A_CLK 0x00000001 @@ -734,12 +738,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, } fsi_reg_write(fsi, reg, data); - /* - * clear clk reset if master mode - */ - if (is_master) - fsi_clk_ctrl(fsi, 1); - /* irq clear */ fsi_irq_disable(fsi, is_play); fsi_irq_clear_status(fsi); @@ -786,10 +784,98 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static int fsi_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fsi_priv *fsi = fsi_get_priv(substream); + struct fsi_master *master = fsi_get_master(fsi); + int (*set_rate)(int is_porta, int rate) = master->info->set_rate; + int fsi_ver = master->core->ver; + int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + int ret; + + /* if slave mode, set_rate is not needed */ + if (!fsi_is_master_mode(fsi, is_play)) + return 0; + + /* it is error if no set_rate */ + if (!set_rate) + return -EIO; + + /* clock stop */ + pm_runtime_put_sync(dai->dev); + fsi_clk_ctrl(fsi, 0); + + ret = set_rate(fsi_is_port_a(fsi), params_rate(params)); + if (ret > 0) { + u32 data = 0; + + switch (ret & SH_FSI_ACKMD_MASK) { + default: + /* FALL THROUGH */ + case SH_FSI_ACKMD_512: + data |= (0x0 << 12); + break; + case SH_FSI_ACKMD_256: + data |= (0x1 << 12); + break; + case SH_FSI_ACKMD_128: + data |= (0x2 << 12); + break; + case SH_FSI_ACKMD_64: + data |= (0x3 << 12); + break; + case SH_FSI_ACKMD_32: + if (fsi_ver < 2) + dev_err(dai->dev, "unsupported ACKMD\n"); + else + data |= (0x4 << 12); + break; + } + + switch (ret & SH_FSI_BPFMD_MASK) { + default: + /* FALL THROUGH */ + case SH_FSI_BPFMD_32: + data |= (0x0 << 8); + break; + case SH_FSI_BPFMD_64: + data |= (0x1 << 8); + break; + case SH_FSI_BPFMD_128: + data |= (0x2 << 8); + break; + case SH_FSI_BPFMD_256: + data |= (0x3 << 8); + break; + case SH_FSI_BPFMD_512: + data |= (0x4 << 8); + break; + case SH_FSI_BPFMD_16: + if (fsi_ver < 2) + dev_err(dai->dev, "unsupported ACKMD\n"); + else + data |= (0x7 << 8); + break; + } + + fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); + udelay(10); + fsi_clk_ctrl(fsi, 1); + ret = 0; + } + pm_runtime_get_sync(dai->dev); + + return ret; + +} + static struct snd_soc_dai_ops fsi_dai_ops = { .startup = fsi_dai_startup, .shutdown = fsi_dai_shutdown, .trigger = fsi_dai_trigger, + .hw_params = fsi_dai_hw_params, }; /************************************************************************ -- cgit v1.2.3-59-g8ed1b From 3c2ef841c0e27f37923ed15dc5d744cd6ba704ae Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 16 Jul 2010 19:51:06 +0900 Subject: ASoC: fsi: Add specified ID for soc-audio Specified ID is necessary, when some codecs are used with FSI. Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/sh_fsi.h | 3 +++ sound/soc/sh/fsi-ak4642.c | 4 ++-- sound/soc/sh/fsi-da7210.c | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 2c6237e6c045..6ac71863c70f 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -12,6 +12,9 @@ * published by the Free Software Foundation. */ +#define FSI_PORT_A 0 +#define FSI_PORT_B 1 + /* flags format * 0xABCDEEFF diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c index 2871a200160c..dad575a22622 100644 --- a/sound/soc/sh/fsi-ak4642.c +++ b/sound/soc/sh/fsi-ak4642.c @@ -29,7 +29,7 @@ static int fsi_ak4642_dai_init(struct snd_soc_codec *codec) static struct snd_soc_dai_link fsi_dai_link = { .name = "AK4642", .stream_name = "AK4642", - .cpu_dai = &fsi_soc_dai[0], /* fsi */ + .cpu_dai = &fsi_soc_dai[FSI_PORT_A], .codec_dai = &ak4642_dai, .init = fsi_ak4642_dai_init, .ops = NULL, @@ -53,7 +53,7 @@ static int __init fsi_ak4642_init(void) { int ret = -ENOMEM; - fsi_snd_device = platform_device_alloc("soc-audio", -1); + fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_A); if (!fsi_snd_device) goto out; diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c index 4d4fd777b45a..121bbb07bb03 100644 --- a/sound/soc/sh/fsi-da7210.c +++ b/sound/soc/sh/fsi-da7210.c @@ -24,7 +24,7 @@ static int fsi_da7210_init(struct snd_soc_codec *codec) static struct snd_soc_dai_link fsi_da7210_dai = { .name = "DA7210", .stream_name = "DA7210", - .cpu_dai = &fsi_soc_dai[1], /* FSI B */ + .cpu_dai = &fsi_soc_dai[FSI_PORT_B], .codec_dai = &da7210_dai, .init = fsi_da7210_init, }; @@ -47,7 +47,7 @@ static int __init fsi_da7210_sound_init(void) { int ret; - fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1); + fsi_da7210_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B); if (!fsi_da7210_snd_device) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From f430a27f05d42d26d3e438aa262a92565170573f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 28 Jul 2010 15:26:54 +0300 Subject: ASoC: tlv320dac33: Revisit the FIFO Mode1 handling Replace the hardwired latency definition with platform data parameter, and simplify the nSample parameter calculation. Signed-off-by: Peter Ujfalusi Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- include/sound/tlv320dac33-plat.h | 1 + sound/soc/codecs/tlv320dac33.c | 71 +++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/include/sound/tlv320dac33-plat.h b/include/sound/tlv320dac33-plat.h index 3f428d53195b..1aa7bdbc208c 100644 --- a/include/sound/tlv320dac33-plat.h +++ b/include/sound/tlv320dac33-plat.h @@ -15,6 +15,7 @@ struct tlv320dac33_platform_data { int power_gpio; + int mode1_latency; /* latency caused by the i2c writes in us */ int keep_bclk; /* Keep the BCLK running in FIFO modes */ u8 burst_bclkdiv; }; diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 2fa946ce23a2..ced6fbbc9d91 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -49,8 +49,6 @@ #define NSAMPLE_MAX 5700 -#define LATENCY_TIME_MS 20 - #define MODE7_LTHR 10 #define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10) @@ -107,6 +105,8 @@ struct tlv320dac33_priv { * this */ enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ unsigned int nsample; /* burst read amount from host */ + int mode1_latency; /* latency caused by the i2c writes in + * us */ u8 burst_bclkdiv; /* BCLK divider value in burst mode */ unsigned int burst_rate; /* Interface speed in Burst modes */ @@ -649,7 +649,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) switch (dac33->fifo_mode) { case DAC33_FIFO_MODE1: dac33_write16(codec, DAC33_NSAMPLE_MSB, - DAC33_THRREG(dac33->nsample + dac33->alarm_threshold)); + DAC33_THRREG(dac33->nsample)); /* Take the timestamps */ spin_lock_irq(&dac33->lock); @@ -798,6 +798,10 @@ static void dac33_shutdown(struct snd_pcm_substream *substream, struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); dac33->substream = NULL; + + /* Reset the nSample restrictions */ + dac33->nsample_min = 0; + dac33->nsample_max = NSAMPLE_MAX; } static int dac33_hw_params(struct snd_pcm_substream *substream, @@ -1040,48 +1044,38 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); + unsigned int period_size = substream->runtime->period_size; + unsigned int rate = substream->runtime->rate; unsigned int nsample_limit; /* In bypass mode we don't need to calculate */ if (!dac33->fifo_mode) return; - /* Number of samples (16bit, stereo) in one period */ - dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4; - - /* Number of samples (16bit, stereo) in ALSA buffer */ - dac33->nsample_max = snd_pcm_lib_buffer_bytes(substream) / 4; - /* Subtract one period from the total */ - dac33->nsample_max -= dac33->nsample_min; - - /* Number of samples for LATENCY_TIME_MS / 2 */ - dac33->alarm_threshold = substream->runtime->rate / - (1000 / (LATENCY_TIME_MS / 2)); - - /* Find and fix up the lowest nsmaple limit */ - nsample_limit = substream->runtime->rate / (1000 / LATENCY_TIME_MS); - - if (dac33->nsample_min < nsample_limit) - dac33->nsample_min = nsample_limit; - - if (dac33->nsample < dac33->nsample_min) - dac33->nsample = dac33->nsample_min; - - /* - * Find and fix up the highest nsmaple limit - * In order to not overflow the DAC33 buffer substract the - * alarm_threshold value from the size of the DAC33 buffer - */ - nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold; - - if (dac33->nsample_max > nsample_limit) - dac33->nsample_max = nsample_limit; - - if (dac33->nsample > dac33->nsample_max) - dac33->nsample = dac33->nsample_max; - switch (dac33->fifo_mode) { case DAC33_FIFO_MODE1: + /* Number of samples under i2c latency */ + dac33->alarm_threshold = US_TO_SAMPLES(rate, + dac33->mode1_latency); + /* nSample time shall not be shorter than i2c latency */ + dac33->nsample_min = dac33->alarm_threshold; + /* + * nSample should not be bigger than alsa buffer minus + * size of one period to avoid overruns + */ + dac33->nsample_max = substream->runtime->buffer_size - + period_size; + nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - + dac33->alarm_threshold; + if (dac33->nsample_max > nsample_limit) + dac33->nsample_max = nsample_limit; + + /* Correct the nSample if it is outside of the ranges */ + if (dac33->nsample < dac33->nsample_min) + dac33->nsample = dac33->nsample_min; + if (dac33->nsample > dac33->nsample_max) + dac33->nsample = dac33->nsample_max; + dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate, dac33->nsample); dac33->t_stamp1 = 0; @@ -1519,6 +1513,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, /* Pre calculate the burst rate */ dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32; dac33->keep_bclk = pdata->keep_bclk; + dac33->mode1_latency = pdata->mode1_latency; + if (!dac33->mode1_latency) + dac33->mode1_latency = 10000; /* 10ms */ dac33->irq = client->irq; dac33->nsample = NSAMPLE_MAX; dac33->nsample_max = NSAMPLE_MAX; -- cgit v1.2.3-59-g8ed1b From a577b318fc7cb0c46f9f0cdefb5b267490ff8ce5 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 28 Jul 2010 15:26:55 +0300 Subject: ASoC: tlv320dac33: Add support for automatic FIFO configuration Platform parameter to enable automatic FIFO configuration when the codec is in Mode1 or Mode7 FIFO mode. When this mode is selected, the controls for changing nSample (in Mode1), and UTHR (in Mode7) are not added. The driver configures the FIFO configuration based on the stream's period size in a way, that every burst will read period size of data from the host. In Mode7 we need to use a formula, which gives close enough aproximation for the burst length from the host point of view. Signed-off-by: Peter Ujfalusi Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- include/sound/tlv320dac33-plat.h | 1 + sound/soc/codecs/tlv320dac33.c | 90 ++++++++++++++++++++++++++++------------ 2 files changed, 65 insertions(+), 26 deletions(-) (limited to 'include') diff --git a/include/sound/tlv320dac33-plat.h b/include/sound/tlv320dac33-plat.h index 1aa7bdbc208c..6c6649656798 100644 --- a/include/sound/tlv320dac33-plat.h +++ b/include/sound/tlv320dac33-plat.h @@ -16,6 +16,7 @@ struct tlv320dac33_platform_data { int power_gpio; int mode1_latency; /* latency caused by the i2c writes in us */ + int auto_fifo_config; /* FIFO config based on the period size */ int keep_bclk; /* Keep the BCLK running in FIFO modes */ u8 burst_bclkdiv; }; diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index ced6fbbc9d91..8651b01ed223 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -60,6 +60,9 @@ #define US_TO_SAMPLES(rate, us) \ (rate / (1000000 / us)) +#define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \ + ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate))) + static void dac33_calculate_times(struct snd_pcm_substream *substream); static int dac33_prepare_chip(struct snd_pcm_substream *substream); @@ -107,6 +110,8 @@ struct tlv320dac33_priv { unsigned int nsample; /* burst read amount from host */ int mode1_latency; /* latency caused by the i2c writes in * us */ + int auto_fifo_config; /* Configure the FIFO based on the + * period size */ u8 burst_bclkdiv; /* BCLK divider value in burst mode */ unsigned int burst_rate; /* Interface speed in Burst modes */ @@ -538,13 +543,16 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = { DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1), }; -static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { +static const struct snd_kcontrol_new dac33_mode_snd_controls[] = { + SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, + dac33_get_fifo_mode, dac33_set_fifo_mode), +}; + +static const struct snd_kcontrol_new dac33_fifo_snd_controls[] = { SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, - dac33_get_nsample, dac33_set_nsample), + dac33_get_nsample, dac33_set_nsample), SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0, dac33_get_uthr, dac33_set_uthr), - SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, - dac33_get_fifo_mode, dac33_set_fifo_mode), }; /* Analog bypass */ @@ -1057,24 +1065,38 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) /* Number of samples under i2c latency */ dac33->alarm_threshold = US_TO_SAMPLES(rate, dac33->mode1_latency); - /* nSample time shall not be shorter than i2c latency */ - dac33->nsample_min = dac33->alarm_threshold; - /* - * nSample should not be bigger than alsa buffer minus - * size of one period to avoid overruns - */ - dac33->nsample_max = substream->runtime->buffer_size - - period_size; - nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - - dac33->alarm_threshold; - if (dac33->nsample_max > nsample_limit) - dac33->nsample_max = nsample_limit; - - /* Correct the nSample if it is outside of the ranges */ - if (dac33->nsample < dac33->nsample_min) - dac33->nsample = dac33->nsample_min; - if (dac33->nsample > dac33->nsample_max) - dac33->nsample = dac33->nsample_max; + if (dac33->auto_fifo_config) { + if (period_size <= dac33->alarm_threshold) + /* + * Configure nSamaple to number of periods, + * which covers the latency requironment. + */ + dac33->nsample = period_size * + ((dac33->alarm_threshold / period_size) + + (dac33->alarm_threshold % period_size ? + 1 : 0)); + else + dac33->nsample = period_size; + } else { + /* nSample time shall not be shorter than i2c latency */ + dac33->nsample_min = dac33->alarm_threshold; + /* + * nSample should not be bigger than alsa buffer minus + * size of one period to avoid overruns + */ + dac33->nsample_max = substream->runtime->buffer_size - + period_size; + nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - + dac33->alarm_threshold; + if (dac33->nsample_max > nsample_limit) + dac33->nsample_max = nsample_limit; + + /* Correct the nSample if it is outside of the ranges */ + if (dac33->nsample < dac33->nsample_min) + dac33->nsample = dac33->nsample_min; + if (dac33->nsample > dac33->nsample_max) + dac33->nsample = dac33->nsample_max; + } dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate, dac33->nsample); @@ -1082,6 +1104,16 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) dac33->t_stamp2 = 0; break; case DAC33_FIFO_MODE7: + if (dac33->auto_fifo_config) { + dac33->uthr = UTHR_FROM_PERIOD_SIZE( + period_size, + rate, + dac33->burst_rate) + 9; + if (dac33->uthr > MODE7_UTHR) + dac33->uthr = MODE7_UTHR; + if (dac33->uthr < (MODE7_LTHR + 10)) + dac33->uthr = (MODE7_LTHR + 10); + } dac33->mode7_us_to_lthr = SAMPLES_TO_US(substream->runtime->rate, dac33->uthr - MODE7_LTHR + 1); @@ -1379,10 +1411,15 @@ static int dac33_soc_probe(struct platform_device *pdev) snd_soc_add_controls(codec, dac33_snd_controls, ARRAY_SIZE(dac33_snd_controls)); - /* Only add the nSample controls, if we have valid IRQ number */ - if (dac33->irq >= 0) - snd_soc_add_controls(codec, dac33_nsample_snd_controls, - ARRAY_SIZE(dac33_nsample_snd_controls)); + /* Only add the FIFO controls, if we have valid IRQ number */ + if (dac33->irq >= 0) { + snd_soc_add_controls(codec, dac33_mode_snd_controls, + ARRAY_SIZE(dac33_mode_snd_controls)); + /* FIFO usage controls only, if autoio config is not selected */ + if (!dac33->auto_fifo_config) + snd_soc_add_controls(codec, dac33_fifo_snd_controls, + ARRAY_SIZE(dac33_fifo_snd_controls)); + } dac33_add_widgets(codec); @@ -1513,6 +1550,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, /* Pre calculate the burst rate */ dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32; dac33->keep_bclk = pdata->keep_bclk; + dac33->auto_fifo_config = pdata->auto_fifo_config; dac33->mode1_latency = pdata->mode1_latency; if (!dac33->mode1_latency) dac33->mode1_latency = 10000; /* 10ms */ -- cgit v1.2.3-59-g8ed1b From 3bc280708e7b9a84cc6307c1f9acca57e0fafaac Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 29 Jul 2010 16:48:32 +0900 Subject: ASoC: fsi: Add new funtion for SPDIF Signed-off-by: Kuninori Morimoto Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/sh_fsi.h | 2 ++ sound/soc/sh/fsi.c | 60 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h index 6ac71863c70f..9d51d6f35893 100644 --- a/include/sound/sh_fsi.h +++ b/include/sound/sh_fsi.h @@ -64,6 +64,8 @@ #define SH_FSI_FMT_I2S 3 #define SH_FSI_FMT_TDM 4 #define SH_FSI_FMT_TDM_DELAY 5 +#define SH_FSI_FMT_SPDIF 6 + #define SH_FSI_IFMT_TDM_CH(x) \ (SH_FSI_IFMT(TDM) | SH_FSI_SET_CH_I(x)) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 4b09b3dfcc00..58c6bec642de 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -30,9 +30,11 @@ #define DIDT 0x0020 #define DODT 0x0024 #define MUTE_ST 0x0028 -#define REG_END MUTE_ST - +#define OUT_SEL 0x0030 +#define REG_END OUT_SEL +#define A_MST_CTLR 0x0180 +#define B_MST_CTLR 0x01A0 #define CPU_INT_ST 0x01F4 #define CPU_IEMSK 0x01F8 #define CPU_IMSK 0x01FC @@ -43,7 +45,7 @@ #define CLK_RST 0x0210 #define SOFT_RST 0x0214 #define FIFO_SZ 0x0218 -#define MREG_START CPU_INT_ST +#define MREG_START A_MST_CTLR #define MREG_END FIFO_SZ /* DO_FMT */ @@ -54,6 +56,7 @@ #define CR_I2S (0x3 << 4) #define CR_TDM (0x4 << 4) #define CR_TDM_D (0x5 << 4) +#define CR_SPDIF 0x00100120 /* DOFF_CTL */ /* DIFF_CTL */ @@ -69,6 +72,10 @@ #define ACKMD_MASK 0x00007000 #define BPFMD_MASK 0x00000700 +/* A/B MST_CTLR */ +#define BP (1 << 4) /* Fix the signal of Biphase output */ +#define SE (1 << 0) /* Fix the master clock */ + /* CLK_RST */ #define B_CLK 0x00000010 #define A_CLK 0x00000001 @@ -113,6 +120,8 @@ struct fsi_priv { int period_len; int buffer_len; int periods; + + u32 mst_ctrl; }; struct fsi_core { @@ -392,6 +401,29 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi) fsi_master_mask_set(master, master->core->int_st, data, 0); } +/************************************************************************ + + + SPDIF master clock function + +These functions are used later FSI2 +************************************************************************/ +static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) +{ + struct fsi_master *master = fsi_get_master(fsi); + u32 val = BP | SE; + + if (master->core->ver < 2) { + pr_err("fsi: register access err (%s)\n", __func__); + return; + } + + if (enable) + fsi_master_mask_set(master, fsi->mst_ctrl, val, val); + else + fsi_master_mask_set(master, fsi->mst_ctrl, val, 0); +} + /************************************************************************ @@ -671,6 +703,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, { struct fsi_priv *fsi = fsi_get_priv(substream); u32 flags = fsi_get_info_flags(fsi); + struct fsi_master *master = fsi_get_master(fsi); u32 fmt; u32 reg; u32 data; @@ -732,6 +765,16 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); data = CR_TDM_D | (fsi->chan - 1); break; + case SH_FSI_FMT_SPDIF: + if (master->core->ver < 2) { + dev_err(dai->dev, "This FSI can not use SPDIF\n"); + return -EINVAL; + } + data = CR_SPDIF; + fsi->chan = 2; + fsi_spdif_clk_ctrl(fsi, 1); + fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010); + break; default: dev_err(dai->dev, "unknown format.\n"); return -EINVAL; @@ -1071,14 +1114,21 @@ static int fsi_probe(struct platform_device *pdev) goto exit_kfree; } + /* master setting */ master->irq = irq; master->info = pdev->dev.platform_data; + master->core = (struct fsi_core *)id_entry->driver_data; + spin_lock_init(&master->lock); + + /* FSI A setting */ master->fsia.base = master->base; master->fsia.master = master; + master->fsia.mst_ctrl = A_MST_CTLR; + + /* FSI B setting */ master->fsib.base = master->base + 0x40; master->fsib.master = master; - master->core = (struct fsi_core *)id_entry->driver_data; - spin_lock_init(&master->lock); + master->fsib.mst_ctrl = B_MST_CTLR; pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); -- cgit v1.2.3-59-g8ed1b