xref: /openbmc/linux/sound/usb/clock.c (revision f25ecf8f)
179f920fbSDaniel Mack /*
279f920fbSDaniel Mack  *   Clock domain and sample rate management functions
379f920fbSDaniel Mack  *
479f920fbSDaniel Mack  *   This program is free software; you can redistribute it and/or modify
579f920fbSDaniel Mack  *   it under the terms of the GNU General Public License as published by
679f920fbSDaniel Mack  *   the Free Software Foundation; either version 2 of the License, or
779f920fbSDaniel Mack  *   (at your option) any later version.
879f920fbSDaniel Mack  *
979f920fbSDaniel Mack  *   This program is distributed in the hope that it will be useful,
1079f920fbSDaniel Mack  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
1179f920fbSDaniel Mack  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1279f920fbSDaniel Mack  *   GNU General Public License for more details.
1379f920fbSDaniel Mack  *
1479f920fbSDaniel Mack  *   You should have received a copy of the GNU General Public License
1579f920fbSDaniel Mack  *   along with this program; if not, write to the Free Software
1679f920fbSDaniel Mack  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
1779f920fbSDaniel Mack  *
1879f920fbSDaniel Mack  */
1979f920fbSDaniel Mack 
2079f920fbSDaniel Mack #include <linux/bitops.h>
2179f920fbSDaniel Mack #include <linux/init.h>
2279f920fbSDaniel Mack #include <linux/string.h>
2379f920fbSDaniel Mack #include <linux/usb.h>
2479f920fbSDaniel Mack #include <linux/usb/audio.h>
2579f920fbSDaniel Mack #include <linux/usb/audio-v2.h>
269a2fe9b8SRuslan Bilovol #include <linux/usb/audio-v3.h>
2779f920fbSDaniel Mack 
2879f920fbSDaniel Mack #include <sound/core.h>
2979f920fbSDaniel Mack #include <sound/info.h>
3079f920fbSDaniel Mack #include <sound/pcm.h>
3179f920fbSDaniel Mack 
3279f920fbSDaniel Mack #include "usbaudio.h"
3379f920fbSDaniel Mack #include "card.h"
3479f920fbSDaniel Mack #include "helper.h"
35f22aa949SDaniel Mack #include "clock.h"
3621bb5aafSDaniel Mack #include "quirks.h"
3779f920fbSDaniel Mack 
38f7645bd6STakashi Iwai static void *find_uac_clock_desc(struct usb_host_interface *iface, int id,
39f7645bd6STakashi Iwai 				 bool (*validator)(void *, int), u8 type)
4079f920fbSDaniel Mack {
41f7645bd6STakashi Iwai 	void *cs = NULL;
4279f920fbSDaniel Mack 
43f7645bd6STakashi Iwai 	while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen,
44f7645bd6STakashi Iwai 					     cs, type))) {
45f7645bd6STakashi Iwai 		if (validator(cs, id))
4679f920fbSDaniel Mack 			return cs;
4779f920fbSDaniel Mack 	}
4879f920fbSDaniel Mack 
4979f920fbSDaniel Mack 	return NULL;
5079f920fbSDaniel Mack }
5179f920fbSDaniel Mack 
52f7645bd6STakashi Iwai static bool validate_clock_source_v2(void *p, int id)
539a2fe9b8SRuslan Bilovol {
54f7645bd6STakashi Iwai 	struct uac_clock_source_descriptor *cs = p;
55f5d76e9cSTakashi Iwai 	return cs->bLength == sizeof(*cs) && cs->bClockID == id;
569a2fe9b8SRuslan Bilovol }
579a2fe9b8SRuslan Bilovol 
58f7645bd6STakashi Iwai static bool validate_clock_source_v3(void *p, int id)
5979f920fbSDaniel Mack {
60f7645bd6STakashi Iwai 	struct uac3_clock_source_descriptor *cs = p;
61b580fbffSTakashi Iwai 	return cs->bLength == sizeof(*cs) && cs->bClockID == id;
620a62d6c9STakashi Iwai }
6379f920fbSDaniel Mack 
64f7645bd6STakashi Iwai static bool validate_clock_selector_v2(void *p, int id)
659a2fe9b8SRuslan Bilovol {
66f7645bd6STakashi Iwai 	struct uac_clock_selector_descriptor *cs = p;
67f7645bd6STakashi Iwai 	return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
68f5d76e9cSTakashi Iwai 		cs->bLength == 7 + cs->bNrInPins;
699a2fe9b8SRuslan Bilovol }
709a2fe9b8SRuslan Bilovol 
71f7645bd6STakashi Iwai static bool validate_clock_selector_v3(void *p, int id)
7279f920fbSDaniel Mack {
73f7645bd6STakashi Iwai 	struct uac3_clock_selector_descriptor *cs = p;
74b580fbffSTakashi Iwai 	return cs->bLength >= sizeof(*cs) && cs->bClockID == id &&
75b580fbffSTakashi Iwai 		cs->bLength == 11 + cs->bNrInPins;
7679f920fbSDaniel Mack }
7779f920fbSDaniel Mack 
78f7645bd6STakashi Iwai static bool validate_clock_multiplier_v2(void *p, int id)
799a2fe9b8SRuslan Bilovol {
80f7645bd6STakashi Iwai 	struct uac_clock_multiplier_descriptor *cs = p;
81f5d76e9cSTakashi Iwai 	return cs->bLength == sizeof(*cs) && cs->bClockID == id;
829a2fe9b8SRuslan Bilovol }
839a2fe9b8SRuslan Bilovol 
84f7645bd6STakashi Iwai static bool validate_clock_multiplier_v3(void *p, int id)
85f7645bd6STakashi Iwai {
86f7645bd6STakashi Iwai 	struct uac3_clock_multiplier_descriptor *cs = p;
87b580fbffSTakashi Iwai 	return cs->bLength == sizeof(*cs) && cs->bClockID == id;
889a2fe9b8SRuslan Bilovol }
899a2fe9b8SRuslan Bilovol 
90f7645bd6STakashi Iwai #define DEFINE_FIND_HELPER(name, obj, validator, type)		\
91f7645bd6STakashi Iwai static obj *name(struct usb_host_interface *iface, int id)	\
92f7645bd6STakashi Iwai {								\
93f7645bd6STakashi Iwai 	return find_uac_clock_desc(iface, id, validator, type);	\
94f7645bd6STakashi Iwai }
95f7645bd6STakashi Iwai 
96f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_source,
97f7645bd6STakashi Iwai 		   struct uac_clock_source_descriptor,
98f7645bd6STakashi Iwai 		   validate_clock_source_v2, UAC2_CLOCK_SOURCE);
99f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3,
100f7645bd6STakashi Iwai 		   struct uac3_clock_source_descriptor,
101f7645bd6STakashi Iwai 		   validate_clock_source_v3, UAC3_CLOCK_SOURCE);
102f7645bd6STakashi Iwai 
103f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_selector,
104f7645bd6STakashi Iwai 		   struct uac_clock_selector_descriptor,
105f7645bd6STakashi Iwai 		   validate_clock_selector_v2, UAC2_CLOCK_SELECTOR);
106f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3,
107f7645bd6STakashi Iwai 		   struct uac3_clock_selector_descriptor,
108f7645bd6STakashi Iwai 		   validate_clock_selector_v3, UAC3_CLOCK_SELECTOR);
109f7645bd6STakashi Iwai 
110f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
111f7645bd6STakashi Iwai 		   struct uac_clock_multiplier_descriptor,
112f7645bd6STakashi Iwai 		   validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER);
113f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3,
114f7645bd6STakashi Iwai 		   struct uac3_clock_multiplier_descriptor,
115f7645bd6STakashi Iwai 		   validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER);
116f7645bd6STakashi Iwai 
11779f920fbSDaniel Mack static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
11879f920fbSDaniel Mack {
11979f920fbSDaniel Mack 	unsigned char buf;
12079f920fbSDaniel Mack 	int ret;
12179f920fbSDaniel Mack 
12279f920fbSDaniel Mack 	ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
12379f920fbSDaniel Mack 			      UAC2_CS_CUR,
12479f920fbSDaniel Mack 			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
12511bcbc44SDaniel Mack 			      UAC2_CX_CLOCK_SELECTOR << 8,
12611bcbc44SDaniel Mack 			      snd_usb_ctrl_intf(chip) | (selector_id << 8),
12717d900c4SClemens Ladisch 			      &buf, sizeof(buf));
12879f920fbSDaniel Mack 
12979f920fbSDaniel Mack 	if (ret < 0)
13079f920fbSDaniel Mack 		return ret;
13179f920fbSDaniel Mack 
13279f920fbSDaniel Mack 	return buf;
13379f920fbSDaniel Mack }
13479f920fbSDaniel Mack 
1358c55af3fSEldad Zack static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
1368c55af3fSEldad Zack 					unsigned char pin)
1378c55af3fSEldad Zack {
1388c55af3fSEldad Zack 	int ret;
1398c55af3fSEldad Zack 
1408c55af3fSEldad Zack 	ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
1418c55af3fSEldad Zack 			      UAC2_CS_CUR,
1428c55af3fSEldad Zack 			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
1438c55af3fSEldad Zack 			      UAC2_CX_CLOCK_SELECTOR << 8,
1448c55af3fSEldad Zack 			      snd_usb_ctrl_intf(chip) | (selector_id << 8),
1458c55af3fSEldad Zack 			      &pin, sizeof(pin));
1468c55af3fSEldad Zack 	if (ret < 0)
1478c55af3fSEldad Zack 		return ret;
1488c55af3fSEldad Zack 
1498c55af3fSEldad Zack 	if (ret != sizeof(pin)) {
1500ba41d91STakashi Iwai 		usb_audio_err(chip,
1510ba41d91STakashi Iwai 			"setting selector (id %d) unexpected length %d\n",
1520ba41d91STakashi Iwai 			selector_id, ret);
1538c55af3fSEldad Zack 		return -EINVAL;
1548c55af3fSEldad Zack 	}
1558c55af3fSEldad Zack 
1568c55af3fSEldad Zack 	ret = uac_clock_selector_get_val(chip, selector_id);
1578c55af3fSEldad Zack 	if (ret < 0)
1588c55af3fSEldad Zack 		return ret;
1598c55af3fSEldad Zack 
1608c55af3fSEldad Zack 	if (ret != pin) {
1610ba41d91STakashi Iwai 		usb_audio_err(chip,
1620ba41d91STakashi Iwai 			"setting selector (id %d) to %x failed (current: %d)\n",
1630ba41d91STakashi Iwai 			selector_id, pin, ret);
1648c55af3fSEldad Zack 		return -EINVAL;
1658c55af3fSEldad Zack 	}
1668c55af3fSEldad Zack 
1678c55af3fSEldad Zack 	return ret;
1688c55af3fSEldad Zack }
1698c55af3fSEldad Zack 
1709a2fe9b8SRuslan Bilovol static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
1719a2fe9b8SRuslan Bilovol 				      int protocol,
1729a2fe9b8SRuslan Bilovol 				      int source_id)
17379f920fbSDaniel Mack {
17479f920fbSDaniel Mack 	int err;
17579f920fbSDaniel Mack 	unsigned char data;
17679f920fbSDaniel Mack 	struct usb_device *dev = chip->dev;
1779a2fe9b8SRuslan Bilovol 	u32 bmControls;
1789a2fe9b8SRuslan Bilovol 
1799a2fe9b8SRuslan Bilovol 	if (protocol == UAC_VERSION_3) {
1809a2fe9b8SRuslan Bilovol 		struct uac3_clock_source_descriptor *cs_desc =
1819a2fe9b8SRuslan Bilovol 			snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id);
1829a2fe9b8SRuslan Bilovol 
1839a2fe9b8SRuslan Bilovol 		if (!cs_desc)
1849a2fe9b8SRuslan Bilovol 			return 0;
1859a2fe9b8SRuslan Bilovol 		bmControls = le32_to_cpu(cs_desc->bmControls);
1869a2fe9b8SRuslan Bilovol 	} else { /* UAC_VERSION_1/2 */
1873bc6fbc7SDaniel Mack 		struct uac_clock_source_descriptor *cs_desc =
1883bc6fbc7SDaniel Mack 			snd_usb_find_clock_source(chip->ctrl_intf, source_id);
1893bc6fbc7SDaniel Mack 
1903bc6fbc7SDaniel Mack 		if (!cs_desc)
1913bc6fbc7SDaniel Mack 			return 0;
1929a2fe9b8SRuslan Bilovol 		bmControls = cs_desc->bmControls;
1939a2fe9b8SRuslan Bilovol 	}
1943bc6fbc7SDaniel Mack 
1953bc6fbc7SDaniel Mack 	/* If a clock source can't tell us whether it's valid, we assume it is */
1969a2fe9b8SRuslan Bilovol 	if (!uac_v2v3_control_is_readable(bmControls,
19721e9b3e9SAndrew Chant 				      UAC2_CS_CONTROL_CLOCK_VALID))
1983bc6fbc7SDaniel Mack 		return 1;
19979f920fbSDaniel Mack 
20079f920fbSDaniel Mack 	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
20179f920fbSDaniel Mack 			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
20211bcbc44SDaniel Mack 			      UAC2_CS_CONTROL_CLOCK_VALID << 8,
20311bcbc44SDaniel Mack 			      snd_usb_ctrl_intf(chip) | (source_id << 8),
20417d900c4SClemens Ladisch 			      &data, sizeof(data));
20579f920fbSDaniel Mack 
20679f920fbSDaniel Mack 	if (err < 0) {
2070ba41d91STakashi Iwai 		dev_warn(&dev->dev,
2080ba41d91STakashi Iwai 			 "%s(): cannot get clock validity for id %d\n",
20979f920fbSDaniel Mack 			   __func__, source_id);
2103bc6fbc7SDaniel Mack 		return 0;
21179f920fbSDaniel Mack 	}
21279f920fbSDaniel Mack 
21379f920fbSDaniel Mack 	return !!data;
21479f920fbSDaniel Mack }
21579f920fbSDaniel Mack 
2169a2fe9b8SRuslan Bilovol static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id,
2179a2fe9b8SRuslan Bilovol 				   unsigned long *visited, bool validate)
21879f920fbSDaniel Mack {
21979f920fbSDaniel Mack 	struct uac_clock_source_descriptor *source;
22079f920fbSDaniel Mack 	struct uac_clock_selector_descriptor *selector;
22179f920fbSDaniel Mack 	struct uac_clock_multiplier_descriptor *multiplier;
22279f920fbSDaniel Mack 
22379f920fbSDaniel Mack 	entity_id &= 0xff;
22479f920fbSDaniel Mack 
22579f920fbSDaniel Mack 	if (test_and_set_bit(entity_id, visited)) {
2260ba41d91STakashi Iwai 		usb_audio_warn(chip,
22779f920fbSDaniel Mack 			 "%s(): recursive clock topology detected, id %d.\n",
22879f920fbSDaniel Mack 			 __func__, entity_id);
22979f920fbSDaniel Mack 		return -EINVAL;
23079f920fbSDaniel Mack 	}
23179f920fbSDaniel Mack 
23279f920fbSDaniel Mack 	/* first, see if the ID we're looking for is a clock source already */
2333d8d4dcfSDaniel Mack 	source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
23406ffc1ebSEldad Zack 	if (source) {
23506ffc1ebSEldad Zack 		entity_id = source->bClockID;
2369a2fe9b8SRuslan Bilovol 		if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2,
2379a2fe9b8SRuslan Bilovol 								entity_id)) {
2380ba41d91STakashi Iwai 			usb_audio_err(chip,
2390ba41d91STakashi Iwai 				"clock source %d is not valid, cannot use\n",
2400ba41d91STakashi Iwai 				entity_id);
24106ffc1ebSEldad Zack 			return -ENXIO;
24206ffc1ebSEldad Zack 		}
24306ffc1ebSEldad Zack 		return entity_id;
24406ffc1ebSEldad Zack 	}
24579f920fbSDaniel Mack 
2463d8d4dcfSDaniel Mack 	selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
24779f920fbSDaniel Mack 	if (selector) {
2488c55af3fSEldad Zack 		int ret, i, cur;
24979f920fbSDaniel Mack 
25079f920fbSDaniel Mack 		/* the entity ID we are looking for is a selector.
25179f920fbSDaniel Mack 		 * find out what it currently selects */
25279f920fbSDaniel Mack 		ret = uac_clock_selector_get_val(chip, selector->bClockID);
25379f920fbSDaniel Mack 		if (ret < 0)
25479f920fbSDaniel Mack 			return ret;
25579f920fbSDaniel Mack 
256157a57b6SDaniel Mack 		/* Selector values are one-based */
257157a57b6SDaniel Mack 
25879f920fbSDaniel Mack 		if (ret > selector->bNrInPins || ret < 1) {
2590ba41d91STakashi Iwai 			usb_audio_err(chip,
26079f920fbSDaniel Mack 				"%s(): selector reported illegal value, id %d, ret %d\n",
26179f920fbSDaniel Mack 				__func__, selector->bClockID, ret);
26279f920fbSDaniel Mack 
26379f920fbSDaniel Mack 			return -EINVAL;
26479f920fbSDaniel Mack 		}
26579f920fbSDaniel Mack 
2668c55af3fSEldad Zack 		cur = ret;
2678c55af3fSEldad Zack 		ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1],
26806ffc1ebSEldad Zack 					       visited, validate);
269ef02e29bSEldad Zack 		if (!validate || ret > 0 || !chip->autoclock)
2708c55af3fSEldad Zack 			return ret;
2718c55af3fSEldad Zack 
2728c55af3fSEldad Zack 		/* The current clock source is invalid, try others. */
2738c55af3fSEldad Zack 		for (i = 1; i <= selector->bNrInPins; i++) {
2748c55af3fSEldad Zack 			int err;
2758c55af3fSEldad Zack 
2768c55af3fSEldad Zack 			if (i == cur)
2778c55af3fSEldad Zack 				continue;
2788c55af3fSEldad Zack 
2798c55af3fSEldad Zack 			ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1],
2808c55af3fSEldad Zack 				visited, true);
2818c55af3fSEldad Zack 			if (ret < 0)
2828c55af3fSEldad Zack 				continue;
2838c55af3fSEldad Zack 
2848c55af3fSEldad Zack 			err = uac_clock_selector_set_val(chip, entity_id, i);
2858c55af3fSEldad Zack 			if (err < 0)
2868c55af3fSEldad Zack 				continue;
2878c55af3fSEldad Zack 
2880ba41d91STakashi Iwai 			usb_audio_info(chip,
2890ba41d91STakashi Iwai 				 "found and selected valid clock source %d\n",
2900ba41d91STakashi Iwai 				 ret);
2918c55af3fSEldad Zack 			return ret;
2928c55af3fSEldad Zack 		}
2938c55af3fSEldad Zack 
2948c55af3fSEldad Zack 		return -ENXIO;
29579f920fbSDaniel Mack 	}
29679f920fbSDaniel Mack 
29779f920fbSDaniel Mack 	/* FIXME: multipliers only act as pass-thru element for now */
2983d8d4dcfSDaniel Mack 	multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
29979f920fbSDaniel Mack 	if (multiplier)
3003d8d4dcfSDaniel Mack 		return __uac_clock_find_source(chip, multiplier->bCSourceID,
30106ffc1ebSEldad Zack 						visited, validate);
30279f920fbSDaniel Mack 
30379f920fbSDaniel Mack 	return -EINVAL;
30479f920fbSDaniel Mack }
30579f920fbSDaniel Mack 
3069a2fe9b8SRuslan Bilovol static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
3079a2fe9b8SRuslan Bilovol 				   unsigned long *visited, bool validate)
3089a2fe9b8SRuslan Bilovol {
3099a2fe9b8SRuslan Bilovol 	struct uac3_clock_source_descriptor *source;
3109a2fe9b8SRuslan Bilovol 	struct uac3_clock_selector_descriptor *selector;
3119a2fe9b8SRuslan Bilovol 	struct uac3_clock_multiplier_descriptor *multiplier;
3129a2fe9b8SRuslan Bilovol 
3139a2fe9b8SRuslan Bilovol 	entity_id &= 0xff;
3149a2fe9b8SRuslan Bilovol 
3159a2fe9b8SRuslan Bilovol 	if (test_and_set_bit(entity_id, visited)) {
3169a2fe9b8SRuslan Bilovol 		usb_audio_warn(chip,
3179a2fe9b8SRuslan Bilovol 			 "%s(): recursive clock topology detected, id %d.\n",
3189a2fe9b8SRuslan Bilovol 			 __func__, entity_id);
3199a2fe9b8SRuslan Bilovol 		return -EINVAL;
3209a2fe9b8SRuslan Bilovol 	}
3219a2fe9b8SRuslan Bilovol 
3229a2fe9b8SRuslan Bilovol 	/* first, see if the ID we're looking for is a clock source already */
3239a2fe9b8SRuslan Bilovol 	source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id);
3249a2fe9b8SRuslan Bilovol 	if (source) {
3259a2fe9b8SRuslan Bilovol 		entity_id = source->bClockID;
3269a2fe9b8SRuslan Bilovol 		if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3,
3279a2fe9b8SRuslan Bilovol 								entity_id)) {
3289a2fe9b8SRuslan Bilovol 			usb_audio_err(chip,
3299a2fe9b8SRuslan Bilovol 				"clock source %d is not valid, cannot use\n",
3309a2fe9b8SRuslan Bilovol 				entity_id);
3319a2fe9b8SRuslan Bilovol 			return -ENXIO;
3329a2fe9b8SRuslan Bilovol 		}
3339a2fe9b8SRuslan Bilovol 		return entity_id;
3349a2fe9b8SRuslan Bilovol 	}
3359a2fe9b8SRuslan Bilovol 
3369a2fe9b8SRuslan Bilovol 	selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id);
3379a2fe9b8SRuslan Bilovol 	if (selector) {
3389a2fe9b8SRuslan Bilovol 		int ret, i, cur;
3399a2fe9b8SRuslan Bilovol 
3409a2fe9b8SRuslan Bilovol 		/* the entity ID we are looking for is a selector.
3419a2fe9b8SRuslan Bilovol 		 * find out what it currently selects */
3429a2fe9b8SRuslan Bilovol 		ret = uac_clock_selector_get_val(chip, selector->bClockID);
3439a2fe9b8SRuslan Bilovol 		if (ret < 0)
3449a2fe9b8SRuslan Bilovol 			return ret;
3459a2fe9b8SRuslan Bilovol 
3469a2fe9b8SRuslan Bilovol 		/* Selector values are one-based */
3479a2fe9b8SRuslan Bilovol 
3489a2fe9b8SRuslan Bilovol 		if (ret > selector->bNrInPins || ret < 1) {
3499a2fe9b8SRuslan Bilovol 			usb_audio_err(chip,
3509a2fe9b8SRuslan Bilovol 				"%s(): selector reported illegal value, id %d, ret %d\n",
3519a2fe9b8SRuslan Bilovol 				__func__, selector->bClockID, ret);
3529a2fe9b8SRuslan Bilovol 
3539a2fe9b8SRuslan Bilovol 			return -EINVAL;
3549a2fe9b8SRuslan Bilovol 		}
3559a2fe9b8SRuslan Bilovol 
3569a2fe9b8SRuslan Bilovol 		cur = ret;
3579a2fe9b8SRuslan Bilovol 		ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1],
3589a2fe9b8SRuslan Bilovol 					       visited, validate);
3599a2fe9b8SRuslan Bilovol 		if (!validate || ret > 0 || !chip->autoclock)
3609a2fe9b8SRuslan Bilovol 			return ret;
3619a2fe9b8SRuslan Bilovol 
3629a2fe9b8SRuslan Bilovol 		/* The current clock source is invalid, try others. */
3639a2fe9b8SRuslan Bilovol 		for (i = 1; i <= selector->bNrInPins; i++) {
3649a2fe9b8SRuslan Bilovol 			int err;
3659a2fe9b8SRuslan Bilovol 
3669a2fe9b8SRuslan Bilovol 			if (i == cur)
3679a2fe9b8SRuslan Bilovol 				continue;
3689a2fe9b8SRuslan Bilovol 
3699a2fe9b8SRuslan Bilovol 			ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1],
3709a2fe9b8SRuslan Bilovol 				visited, true);
3719a2fe9b8SRuslan Bilovol 			if (ret < 0)
3729a2fe9b8SRuslan Bilovol 				continue;
3739a2fe9b8SRuslan Bilovol 
3749a2fe9b8SRuslan Bilovol 			err = uac_clock_selector_set_val(chip, entity_id, i);
3759a2fe9b8SRuslan Bilovol 			if (err < 0)
3769a2fe9b8SRuslan Bilovol 				continue;
3779a2fe9b8SRuslan Bilovol 
3789a2fe9b8SRuslan Bilovol 			usb_audio_info(chip,
3799a2fe9b8SRuslan Bilovol 				 "found and selected valid clock source %d\n",
3809a2fe9b8SRuslan Bilovol 				 ret);
3819a2fe9b8SRuslan Bilovol 			return ret;
3829a2fe9b8SRuslan Bilovol 		}
3839a2fe9b8SRuslan Bilovol 
3849a2fe9b8SRuslan Bilovol 		return -ENXIO;
3859a2fe9b8SRuslan Bilovol 	}
3869a2fe9b8SRuslan Bilovol 
3879a2fe9b8SRuslan Bilovol 	/* FIXME: multipliers only act as pass-thru element for now */
3889a2fe9b8SRuslan Bilovol 	multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf,
3899a2fe9b8SRuslan Bilovol 						      entity_id);
3909a2fe9b8SRuslan Bilovol 	if (multiplier)
3919a2fe9b8SRuslan Bilovol 		return __uac3_clock_find_source(chip, multiplier->bCSourceID,
3929a2fe9b8SRuslan Bilovol 						visited, validate);
3939a2fe9b8SRuslan Bilovol 
3949a2fe9b8SRuslan Bilovol 	return -EINVAL;
3959a2fe9b8SRuslan Bilovol }
3969a2fe9b8SRuslan Bilovol 
397157a57b6SDaniel Mack /*
398157a57b6SDaniel Mack  * For all kinds of sample rate settings and other device queries,
399157a57b6SDaniel Mack  * the clock source (end-leaf) must be used. However, clock selectors,
400157a57b6SDaniel Mack  * clock multipliers and sample rate converters may be specified as
401157a57b6SDaniel Mack  * clock source input to terminal. This functions walks the clock path
402157a57b6SDaniel Mack  * to its end and tries to find the source.
403157a57b6SDaniel Mack  *
404157a57b6SDaniel Mack  * The 'visited' bitfield is used internally to detect recursive loops.
405157a57b6SDaniel Mack  *
406157a57b6SDaniel Mack  * Returns the clock source UnitID (>=0) on success, or an error.
407157a57b6SDaniel Mack  */
4089a2fe9b8SRuslan Bilovol int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol,
4099a2fe9b8SRuslan Bilovol 			      int entity_id, bool validate)
41079f920fbSDaniel Mack {
41179f920fbSDaniel Mack 	DECLARE_BITMAP(visited, 256);
41279f920fbSDaniel Mack 	memset(visited, 0, sizeof(visited));
4139a2fe9b8SRuslan Bilovol 
4149a2fe9b8SRuslan Bilovol 	switch (protocol) {
4159a2fe9b8SRuslan Bilovol 	case UAC_VERSION_2:
4169a2fe9b8SRuslan Bilovol 		return __uac_clock_find_source(chip, entity_id, visited,
4179a2fe9b8SRuslan Bilovol 					       validate);
4189a2fe9b8SRuslan Bilovol 	case UAC_VERSION_3:
4199a2fe9b8SRuslan Bilovol 		return __uac3_clock_find_source(chip, entity_id, visited,
4209a2fe9b8SRuslan Bilovol 					       validate);
4219a2fe9b8SRuslan Bilovol 	default:
4229a2fe9b8SRuslan Bilovol 		return -EINVAL;
4239a2fe9b8SRuslan Bilovol 	}
42479f920fbSDaniel Mack }
42579f920fbSDaniel Mack 
42679f920fbSDaniel Mack static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
42779f920fbSDaniel Mack 			      struct usb_host_interface *alts,
42879f920fbSDaniel Mack 			      struct audioformat *fmt, int rate)
42979f920fbSDaniel Mack {
43079f920fbSDaniel Mack 	struct usb_device *dev = chip->dev;
43179f920fbSDaniel Mack 	unsigned int ep;
43279f920fbSDaniel Mack 	unsigned char data[3];
43379f920fbSDaniel Mack 	int err, crate;
43479f920fbSDaniel Mack 
435447d6275STakashi Iwai 	if (get_iface_desc(alts)->bNumEndpoints < 1)
436447d6275STakashi Iwai 		return -EINVAL;
43779f920fbSDaniel Mack 	ep = get_endpoint(alts, 0)->bEndpointAddress;
43879f920fbSDaniel Mack 
43979f920fbSDaniel Mack 	/* if endpoint doesn't have sampling rate control, bail out */
440d32d552eSClemens Ladisch 	if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE))
44179f920fbSDaniel Mack 		return 0;
44279f920fbSDaniel Mack 
44379f920fbSDaniel Mack 	data[0] = rate;
44479f920fbSDaniel Mack 	data[1] = rate >> 8;
44579f920fbSDaniel Mack 	data[2] = rate >> 16;
446f25ecf8fSTakashi Iwai 	err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
44779f920fbSDaniel Mack 			      USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
44879f920fbSDaniel Mack 			      UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
449f25ecf8fSTakashi Iwai 			      data, sizeof(data));
450f25ecf8fSTakashi Iwai 	if (err < 0) {
4510ba41d91STakashi Iwai 		dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n",
4520ba41d91STakashi Iwai 			iface, fmt->altsetting, rate, ep);
45379f920fbSDaniel Mack 		return err;
45479f920fbSDaniel Mack 	}
45579f920fbSDaniel Mack 
456b62b9980SJoe Turner 	/* Don't check the sample rate for devices which we know don't
457b62b9980SJoe Turner 	 * support reading */
458b62b9980SJoe Turner 	if (snd_usb_get_sample_rate_quirk(chip))
459b62b9980SJoe Turner 		return 0;
46057dd5414STakashi Iwai 	/* the firmware is likely buggy, don't repeat to fail too many times */
46157dd5414STakashi Iwai 	if (chip->sample_rate_read_error > 2)
46257dd5414STakashi Iwai 		return 0;
463b62b9980SJoe Turner 
464f25ecf8fSTakashi Iwai 	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
46579f920fbSDaniel Mack 			      USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
46679f920fbSDaniel Mack 			      UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
467f25ecf8fSTakashi Iwai 			      data, sizeof(data));
468f25ecf8fSTakashi Iwai 	if (err < 0) {
4690ba41d91STakashi Iwai 		dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n",
4700ba41d91STakashi Iwai 			iface, fmt->altsetting, ep);
47157dd5414STakashi Iwai 		chip->sample_rate_read_error++;
47279f920fbSDaniel Mack 		return 0; /* some devices don't support reading */
47379f920fbSDaniel Mack 	}
47479f920fbSDaniel Mack 
47579f920fbSDaniel Mack 	crate = data[0] | (data[1] << 8) | (data[2] << 16);
47679f920fbSDaniel Mack 	if (crate != rate) {
4770ba41d91STakashi Iwai 		dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate);
47879f920fbSDaniel Mack 		// runtime->rate = crate;
47979f920fbSDaniel Mack 	}
48079f920fbSDaniel Mack 
48179f920fbSDaniel Mack 	return 0;
48279f920fbSDaniel Mack }
48379f920fbSDaniel Mack 
4849a2fe9b8SRuslan Bilovol static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
4857c517465STakashi Iwai 			      int altsetting, int clock)
4867c517465STakashi Iwai {
4877c517465STakashi Iwai 	struct usb_device *dev = chip->dev;
488f6a8bc70SEldad Zack 	__le32 data;
4897c517465STakashi Iwai 	int err;
4907c517465STakashi Iwai 
4917c517465STakashi Iwai 	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
4927c517465STakashi Iwai 			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
4937c517465STakashi Iwai 			      UAC2_CS_CONTROL_SAM_FREQ << 8,
4947c517465STakashi Iwai 			      snd_usb_ctrl_intf(chip) | (clock << 8),
495f6a8bc70SEldad Zack 			      &data, sizeof(data));
4967c517465STakashi Iwai 	if (err < 0) {
4979a2fe9b8SRuslan Bilovol 		dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
4980ba41d91STakashi Iwai 			 iface, altsetting, err);
4997c517465STakashi Iwai 		return 0;
5007c517465STakashi Iwai 	}
5017c517465STakashi Iwai 
502f6a8bc70SEldad Zack 	return le32_to_cpu(data);
5037c517465STakashi Iwai }
5047c517465STakashi Iwai 
5059a2fe9b8SRuslan Bilovol static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
50679f920fbSDaniel Mack 			      struct usb_host_interface *alts,
50779f920fbSDaniel Mack 			      struct audioformat *fmt, int rate)
50879f920fbSDaniel Mack {
50979f920fbSDaniel Mack 	struct usb_device *dev = chip->dev;
510f6a8bc70SEldad Zack 	__le32 data;
511690a863fSTorstein Hegge 	int err, cur_rate, prev_rate;
5128c55af3fSEldad Zack 	int clock;
5131dc669feSEldad Zack 	bool writeable;
5149a2fe9b8SRuslan Bilovol 	u32 bmControls;
51579f920fbSDaniel Mack 
5169a2fe9b8SRuslan Bilovol 	clock = snd_usb_clock_find_source(chip, fmt->protocol,
5179a2fe9b8SRuslan Bilovol 					  fmt->clock, true);
51879f920fbSDaniel Mack 	if (clock < 0)
51979f920fbSDaniel Mack 		return clock;
52079f920fbSDaniel Mack 
5219a2fe9b8SRuslan Bilovol 	prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock);
522fa92dd77SDavid Henningsson 	if (prev_rate == rate)
523fa92dd77SDavid Henningsson 		return 0;
524690a863fSTorstein Hegge 
5259a2fe9b8SRuslan Bilovol 	if (fmt->protocol == UAC_VERSION_3) {
5269a2fe9b8SRuslan Bilovol 		struct uac3_clock_source_descriptor *cs_desc;
5279a2fe9b8SRuslan Bilovol 
5289a2fe9b8SRuslan Bilovol 		cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock);
5299a2fe9b8SRuslan Bilovol 		bmControls = le32_to_cpu(cs_desc->bmControls);
5309a2fe9b8SRuslan Bilovol 	} else {
5319a2fe9b8SRuslan Bilovol 		struct uac_clock_source_descriptor *cs_desc;
5329a2fe9b8SRuslan Bilovol 
5331dc669feSEldad Zack 		cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
5349a2fe9b8SRuslan Bilovol 		bmControls = cs_desc->bmControls;
5359a2fe9b8SRuslan Bilovol 	}
5369a2fe9b8SRuslan Bilovol 
53721e9b3e9SAndrew Chant 	writeable = uac_v2v3_control_is_writeable(bmControls,
53821e9b3e9SAndrew Chant 						  UAC2_CS_CONTROL_SAM_FREQ);
5391dc669feSEldad Zack 	if (writeable) {
540f6a8bc70SEldad Zack 		data = cpu_to_le32(rate);
5411dc669feSEldad Zack 		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
54279f920fbSDaniel Mack 				      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
54311bcbc44SDaniel Mack 				      UAC2_CS_CONTROL_SAM_FREQ << 8,
54411bcbc44SDaniel Mack 				      snd_usb_ctrl_intf(chip) | (clock << 8),
5451dc669feSEldad Zack 				      &data, sizeof(data));
5461dc669feSEldad Zack 		if (err < 0) {
5470ba41d91STakashi Iwai 			usb_audio_err(chip,
5489a2fe9b8SRuslan Bilovol 				"%d:%d: cannot set freq %d (v2/v3): err %d\n",
5490ba41d91STakashi Iwai 				iface, fmt->altsetting, rate, err);
55079f920fbSDaniel Mack 			return err;
55179f920fbSDaniel Mack 		}
55279f920fbSDaniel Mack 
5539a2fe9b8SRuslan Bilovol 		cur_rate = get_sample_rate_v2v3(chip, iface,
5549a2fe9b8SRuslan Bilovol 						fmt->altsetting, clock);
5551dc669feSEldad Zack 	} else {
5561dc669feSEldad Zack 		cur_rate = prev_rate;
5571dc669feSEldad Zack 	}
55879f920fbSDaniel Mack 
559690a863fSTorstein Hegge 	if (cur_rate != rate) {
5601dc669feSEldad Zack 		if (!writeable) {
5610ba41d91STakashi Iwai 			usb_audio_warn(chip,
5620ba41d91STakashi Iwai 				 "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
5630ba41d91STakashi Iwai 				 iface, fmt->altsetting, rate, cur_rate);
5641dc669feSEldad Zack 			return -ENXIO;
5651dc669feSEldad Zack 		}
5660ba41d91STakashi Iwai 		usb_audio_dbg(chip,
567690a863fSTorstein Hegge 			"current rate %d is different from the runtime rate %d\n",
568690a863fSTorstein Hegge 			cur_rate, rate);
569690a863fSTorstein Hegge 	}
570690a863fSTorstein Hegge 
571690a863fSTorstein Hegge 	/* Some devices doesn't respond to sample rate changes while the
572690a863fSTorstein Hegge 	 * interface is active. */
573690a863fSTorstein Hegge 	if (rate != prev_rate) {
574690a863fSTorstein Hegge 		usb_set_interface(dev, iface, 0);
57521bb5aafSDaniel Mack 		snd_usb_set_interface_quirk(dev);
576690a863fSTorstein Hegge 		usb_set_interface(dev, iface, fmt->altsetting);
57721bb5aafSDaniel Mack 		snd_usb_set_interface_quirk(dev);
578690a863fSTorstein Hegge 	}
57979f920fbSDaniel Mack 
58079f920fbSDaniel Mack 	return 0;
58179f920fbSDaniel Mack }
58279f920fbSDaniel Mack 
58379f920fbSDaniel Mack int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
58479f920fbSDaniel Mack 			     struct usb_host_interface *alts,
58579f920fbSDaniel Mack 			     struct audioformat *fmt, int rate)
58679f920fbSDaniel Mack {
5878f898e92SClemens Ladisch 	switch (fmt->protocol) {
58879f920fbSDaniel Mack 	case UAC_VERSION_1:
589a2acad82SClemens Ladisch 	default:
59079f920fbSDaniel Mack 		return set_sample_rate_v1(chip, iface, alts, fmt, rate);
59179f920fbSDaniel Mack 
5929a2fe9b8SRuslan Bilovol 	case UAC_VERSION_3:
59317156f23SRuslan Bilovol 		if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
59417156f23SRuslan Bilovol 			if (rate != UAC3_BADD_SAMPLING_RATE)
59517156f23SRuslan Bilovol 				return -ENXIO;
59617156f23SRuslan Bilovol 			else
59717156f23SRuslan Bilovol 				return 0;
59817156f23SRuslan Bilovol 		}
59917156f23SRuslan Bilovol 	/* fall through */
60017156f23SRuslan Bilovol 	case UAC_VERSION_2:
6019a2fe9b8SRuslan Bilovol 		return set_sample_rate_v2v3(chip, iface, alts, fmt, rate);
60279f920fbSDaniel Mack 	}
60379f920fbSDaniel Mack }
60479f920fbSDaniel Mack 
605