xref: /openbmc/linux/sound/usb/clock.c (revision 1d4961d9)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
279f920fbSDaniel Mack /*
379f920fbSDaniel Mack  *   Clock domain and sample rate management functions
479f920fbSDaniel Mack  */
579f920fbSDaniel Mack 
679f920fbSDaniel Mack #include <linux/bitops.h>
779f920fbSDaniel Mack #include <linux/init.h>
879f920fbSDaniel Mack #include <linux/string.h>
979f920fbSDaniel Mack #include <linux/usb.h>
1079f920fbSDaniel Mack #include <linux/usb/audio.h>
1179f920fbSDaniel Mack #include <linux/usb/audio-v2.h>
129a2fe9b8SRuslan Bilovol #include <linux/usb/audio-v3.h>
1379f920fbSDaniel Mack 
1479f920fbSDaniel Mack #include <sound/core.h>
1579f920fbSDaniel Mack #include <sound/info.h>
1679f920fbSDaniel Mack #include <sound/pcm.h>
1779f920fbSDaniel Mack 
1879f920fbSDaniel Mack #include "usbaudio.h"
1979f920fbSDaniel Mack #include "card.h"
2079f920fbSDaniel Mack #include "helper.h"
21f22aa949SDaniel Mack #include "clock.h"
2221bb5aafSDaniel Mack #include "quirks.h"
2379f920fbSDaniel Mack 
24f7645bd6STakashi Iwai static void *find_uac_clock_desc(struct usb_host_interface *iface, int id,
25f7645bd6STakashi Iwai 				 bool (*validator)(void *, int), u8 type)
2679f920fbSDaniel Mack {
27f7645bd6STakashi Iwai 	void *cs = NULL;
2879f920fbSDaniel Mack 
29f7645bd6STakashi Iwai 	while ((cs = snd_usb_find_csint_desc(iface->extra, iface->extralen,
30f7645bd6STakashi Iwai 					     cs, type))) {
31f7645bd6STakashi Iwai 		if (validator(cs, id))
3279f920fbSDaniel Mack 			return cs;
3379f920fbSDaniel Mack 	}
3479f920fbSDaniel Mack 
3579f920fbSDaniel Mack 	return NULL;
3679f920fbSDaniel Mack }
3779f920fbSDaniel Mack 
38f7645bd6STakashi Iwai static bool validate_clock_source_v2(void *p, int id)
399a2fe9b8SRuslan Bilovol {
40f7645bd6STakashi Iwai 	struct uac_clock_source_descriptor *cs = p;
41b8e4f1fdSTakashi Iwai 	return cs->bClockID == id;
429a2fe9b8SRuslan Bilovol }
439a2fe9b8SRuslan Bilovol 
44f7645bd6STakashi Iwai static bool validate_clock_source_v3(void *p, int id)
4579f920fbSDaniel Mack {
46f7645bd6STakashi Iwai 	struct uac3_clock_source_descriptor *cs = p;
47b8e4f1fdSTakashi Iwai 	return cs->bClockID == id;
480a62d6c9STakashi Iwai }
4979f920fbSDaniel Mack 
50f7645bd6STakashi Iwai static bool validate_clock_selector_v2(void *p, int id)
519a2fe9b8SRuslan Bilovol {
52f7645bd6STakashi Iwai 	struct uac_clock_selector_descriptor *cs = p;
53b8e4f1fdSTakashi Iwai 	return cs->bClockID == id;
549a2fe9b8SRuslan Bilovol }
559a2fe9b8SRuslan Bilovol 
56f7645bd6STakashi Iwai static bool validate_clock_selector_v3(void *p, int id)
5779f920fbSDaniel Mack {
58f7645bd6STakashi Iwai 	struct uac3_clock_selector_descriptor *cs = p;
59b8e4f1fdSTakashi Iwai 	return cs->bClockID == id;
6079f920fbSDaniel Mack }
6179f920fbSDaniel Mack 
62f7645bd6STakashi Iwai static bool validate_clock_multiplier_v2(void *p, int id)
639a2fe9b8SRuslan Bilovol {
64f7645bd6STakashi Iwai 	struct uac_clock_multiplier_descriptor *cs = p;
65b8e4f1fdSTakashi Iwai 	return cs->bClockID == id;
669a2fe9b8SRuslan Bilovol }
679a2fe9b8SRuslan Bilovol 
68f7645bd6STakashi Iwai static bool validate_clock_multiplier_v3(void *p, int id)
69f7645bd6STakashi Iwai {
70f7645bd6STakashi Iwai 	struct uac3_clock_multiplier_descriptor *cs = p;
71b8e4f1fdSTakashi Iwai 	return cs->bClockID == id;
729a2fe9b8SRuslan Bilovol }
739a2fe9b8SRuslan Bilovol 
74f7645bd6STakashi Iwai #define DEFINE_FIND_HELPER(name, obj, validator, type)		\
75f7645bd6STakashi Iwai static obj *name(struct usb_host_interface *iface, int id)	\
76f7645bd6STakashi Iwai {								\
77f7645bd6STakashi Iwai 	return find_uac_clock_desc(iface, id, validator, type);	\
78f7645bd6STakashi Iwai }
79f7645bd6STakashi Iwai 
80f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_source,
81f7645bd6STakashi Iwai 		   struct uac_clock_source_descriptor,
82f7645bd6STakashi Iwai 		   validate_clock_source_v2, UAC2_CLOCK_SOURCE);
83f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_source_v3,
84f7645bd6STakashi Iwai 		   struct uac3_clock_source_descriptor,
85f7645bd6STakashi Iwai 		   validate_clock_source_v3, UAC3_CLOCK_SOURCE);
86f7645bd6STakashi Iwai 
87f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_selector,
88f7645bd6STakashi Iwai 		   struct uac_clock_selector_descriptor,
89f7645bd6STakashi Iwai 		   validate_clock_selector_v2, UAC2_CLOCK_SELECTOR);
90f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_selector_v3,
91f7645bd6STakashi Iwai 		   struct uac3_clock_selector_descriptor,
92f7645bd6STakashi Iwai 		   validate_clock_selector_v3, UAC3_CLOCK_SELECTOR);
93f7645bd6STakashi Iwai 
94f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
95f7645bd6STakashi Iwai 		   struct uac_clock_multiplier_descriptor,
96f7645bd6STakashi Iwai 		   validate_clock_multiplier_v2, UAC2_CLOCK_MULTIPLIER);
97f7645bd6STakashi Iwai DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier_v3,
98f7645bd6STakashi Iwai 		   struct uac3_clock_multiplier_descriptor,
99f7645bd6STakashi Iwai 		   validate_clock_multiplier_v3, UAC3_CLOCK_MULTIPLIER);
100f7645bd6STakashi Iwai 
10179f920fbSDaniel Mack static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
10279f920fbSDaniel Mack {
10379f920fbSDaniel Mack 	unsigned char buf;
10479f920fbSDaniel Mack 	int ret;
10579f920fbSDaniel Mack 
10679f920fbSDaniel Mack 	ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
10779f920fbSDaniel Mack 			      UAC2_CS_CUR,
10879f920fbSDaniel Mack 			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
10911bcbc44SDaniel Mack 			      UAC2_CX_CLOCK_SELECTOR << 8,
11011bcbc44SDaniel Mack 			      snd_usb_ctrl_intf(chip) | (selector_id << 8),
11117d900c4SClemens Ladisch 			      &buf, sizeof(buf));
11279f920fbSDaniel Mack 
11379f920fbSDaniel Mack 	if (ret < 0)
11479f920fbSDaniel Mack 		return ret;
11579f920fbSDaniel Mack 
11679f920fbSDaniel Mack 	return buf;
11779f920fbSDaniel Mack }
11879f920fbSDaniel Mack 
1198c55af3fSEldad Zack static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
1208c55af3fSEldad Zack 					unsigned char pin)
1218c55af3fSEldad Zack {
1228c55af3fSEldad Zack 	int ret;
1238c55af3fSEldad Zack 
1248c55af3fSEldad Zack 	ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
1258c55af3fSEldad Zack 			      UAC2_CS_CUR,
1268c55af3fSEldad Zack 			      USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
1278c55af3fSEldad Zack 			      UAC2_CX_CLOCK_SELECTOR << 8,
1288c55af3fSEldad Zack 			      snd_usb_ctrl_intf(chip) | (selector_id << 8),
1298c55af3fSEldad Zack 			      &pin, sizeof(pin));
1308c55af3fSEldad Zack 	if (ret < 0)
1318c55af3fSEldad Zack 		return ret;
1328c55af3fSEldad Zack 
1338c55af3fSEldad Zack 	if (ret != sizeof(pin)) {
1340ba41d91STakashi Iwai 		usb_audio_err(chip,
1350ba41d91STakashi Iwai 			"setting selector (id %d) unexpected length %d\n",
1360ba41d91STakashi Iwai 			selector_id, ret);
1378c55af3fSEldad Zack 		return -EINVAL;
1388c55af3fSEldad Zack 	}
1398c55af3fSEldad Zack 
1408c55af3fSEldad Zack 	ret = uac_clock_selector_get_val(chip, selector_id);
1418c55af3fSEldad Zack 	if (ret < 0)
1428c55af3fSEldad Zack 		return ret;
1438c55af3fSEldad Zack 
1448c55af3fSEldad Zack 	if (ret != pin) {
1450ba41d91STakashi Iwai 		usb_audio_err(chip,
1460ba41d91STakashi Iwai 			"setting selector (id %d) to %x failed (current: %d)\n",
1470ba41d91STakashi Iwai 			selector_id, pin, ret);
1488c55af3fSEldad Zack 		return -EINVAL;
1498c55af3fSEldad Zack 	}
1508c55af3fSEldad Zack 
1518c55af3fSEldad Zack 	return ret;
1528c55af3fSEldad Zack }
1538c55af3fSEldad Zack 
1549a2fe9b8SRuslan Bilovol static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
1559a2fe9b8SRuslan Bilovol 				      int protocol,
1569a2fe9b8SRuslan Bilovol 				      int source_id)
15779f920fbSDaniel Mack {
15879f920fbSDaniel Mack 	int err;
15979f920fbSDaniel Mack 	unsigned char data;
16079f920fbSDaniel Mack 	struct usb_device *dev = chip->dev;
1619a2fe9b8SRuslan Bilovol 	u32 bmControls;
1629a2fe9b8SRuslan Bilovol 
1639a2fe9b8SRuslan Bilovol 	if (protocol == UAC_VERSION_3) {
1649a2fe9b8SRuslan Bilovol 		struct uac3_clock_source_descriptor *cs_desc =
1659a2fe9b8SRuslan Bilovol 			snd_usb_find_clock_source_v3(chip->ctrl_intf, source_id);
1669a2fe9b8SRuslan Bilovol 
1679a2fe9b8SRuslan Bilovol 		if (!cs_desc)
1681d4961d9SSaurav Girepunje 			return false;
1699a2fe9b8SRuslan Bilovol 		bmControls = le32_to_cpu(cs_desc->bmControls);
1709a2fe9b8SRuslan Bilovol 	} else { /* UAC_VERSION_1/2 */
1713bc6fbc7SDaniel Mack 		struct uac_clock_source_descriptor *cs_desc =
1723bc6fbc7SDaniel Mack 			snd_usb_find_clock_source(chip->ctrl_intf, source_id);
1733bc6fbc7SDaniel Mack 
1743bc6fbc7SDaniel Mack 		if (!cs_desc)
1751d4961d9SSaurav Girepunje 			return false;
1769a2fe9b8SRuslan Bilovol 		bmControls = cs_desc->bmControls;
1779a2fe9b8SRuslan Bilovol 	}
1783bc6fbc7SDaniel Mack 
1793bc6fbc7SDaniel Mack 	/* If a clock source can't tell us whether it's valid, we assume it is */
1809a2fe9b8SRuslan Bilovol 	if (!uac_v2v3_control_is_readable(bmControls,
18121e9b3e9SAndrew Chant 				      UAC2_CS_CONTROL_CLOCK_VALID))
1821d4961d9SSaurav Girepunje 		return true;
18379f920fbSDaniel Mack 
18479f920fbSDaniel Mack 	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
18579f920fbSDaniel Mack 			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
18611bcbc44SDaniel Mack 			      UAC2_CS_CONTROL_CLOCK_VALID << 8,
18711bcbc44SDaniel Mack 			      snd_usb_ctrl_intf(chip) | (source_id << 8),
18817d900c4SClemens Ladisch 			      &data, sizeof(data));
18979f920fbSDaniel Mack 
19079f920fbSDaniel Mack 	if (err < 0) {
1910ba41d91STakashi Iwai 		dev_warn(&dev->dev,
1920ba41d91STakashi Iwai 			 "%s(): cannot get clock validity for id %d\n",
19379f920fbSDaniel Mack 			   __func__, source_id);
1941d4961d9SSaurav Girepunje 		return false;
19579f920fbSDaniel Mack 	}
19679f920fbSDaniel Mack 
1971d4961d9SSaurav Girepunje 	return data ? true :  false;
19879f920fbSDaniel Mack }
19979f920fbSDaniel Mack 
2009a2fe9b8SRuslan Bilovol static int __uac_clock_find_source(struct snd_usb_audio *chip, int entity_id,
2019a2fe9b8SRuslan Bilovol 				   unsigned long *visited, bool validate)
20279f920fbSDaniel Mack {
20379f920fbSDaniel Mack 	struct uac_clock_source_descriptor *source;
20479f920fbSDaniel Mack 	struct uac_clock_selector_descriptor *selector;
20579f920fbSDaniel Mack 	struct uac_clock_multiplier_descriptor *multiplier;
20679f920fbSDaniel Mack 
20779f920fbSDaniel Mack 	entity_id &= 0xff;
20879f920fbSDaniel Mack 
20979f920fbSDaniel Mack 	if (test_and_set_bit(entity_id, visited)) {
2100ba41d91STakashi Iwai 		usb_audio_warn(chip,
21179f920fbSDaniel Mack 			 "%s(): recursive clock topology detected, id %d.\n",
21279f920fbSDaniel Mack 			 __func__, entity_id);
21379f920fbSDaniel Mack 		return -EINVAL;
21479f920fbSDaniel Mack 	}
21579f920fbSDaniel Mack 
21679f920fbSDaniel Mack 	/* first, see if the ID we're looking for is a clock source already */
2173d8d4dcfSDaniel Mack 	source = snd_usb_find_clock_source(chip->ctrl_intf, entity_id);
21806ffc1ebSEldad Zack 	if (source) {
21906ffc1ebSEldad Zack 		entity_id = source->bClockID;
2209a2fe9b8SRuslan Bilovol 		if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_2,
2219a2fe9b8SRuslan Bilovol 								entity_id)) {
2220ba41d91STakashi Iwai 			usb_audio_err(chip,
2230ba41d91STakashi Iwai 				"clock source %d is not valid, cannot use\n",
2240ba41d91STakashi Iwai 				entity_id);
22506ffc1ebSEldad Zack 			return -ENXIO;
22606ffc1ebSEldad Zack 		}
22706ffc1ebSEldad Zack 		return entity_id;
22806ffc1ebSEldad Zack 	}
22979f920fbSDaniel Mack 
2303d8d4dcfSDaniel Mack 	selector = snd_usb_find_clock_selector(chip->ctrl_intf, entity_id);
23179f920fbSDaniel Mack 	if (selector) {
2328c55af3fSEldad Zack 		int ret, i, cur;
23379f920fbSDaniel Mack 
23479f920fbSDaniel Mack 		/* the entity ID we are looking for is a selector.
23579f920fbSDaniel Mack 		 * find out what it currently selects */
23679f920fbSDaniel Mack 		ret = uac_clock_selector_get_val(chip, selector->bClockID);
23779f920fbSDaniel Mack 		if (ret < 0)
23879f920fbSDaniel Mack 			return ret;
23979f920fbSDaniel Mack 
240157a57b6SDaniel Mack 		/* Selector values are one-based */
241157a57b6SDaniel Mack 
24279f920fbSDaniel Mack 		if (ret > selector->bNrInPins || ret < 1) {
2430ba41d91STakashi Iwai 			usb_audio_err(chip,
24479f920fbSDaniel Mack 				"%s(): selector reported illegal value, id %d, ret %d\n",
24579f920fbSDaniel Mack 				__func__, selector->bClockID, ret);
24679f920fbSDaniel Mack 
24779f920fbSDaniel Mack 			return -EINVAL;
24879f920fbSDaniel Mack 		}
24979f920fbSDaniel Mack 
2508c55af3fSEldad Zack 		cur = ret;
2518c55af3fSEldad Zack 		ret = __uac_clock_find_source(chip, selector->baCSourceID[ret - 1],
25206ffc1ebSEldad Zack 					       visited, validate);
253ef02e29bSEldad Zack 		if (!validate || ret > 0 || !chip->autoclock)
2548c55af3fSEldad Zack 			return ret;
2558c55af3fSEldad Zack 
2568c55af3fSEldad Zack 		/* The current clock source is invalid, try others. */
2578c55af3fSEldad Zack 		for (i = 1; i <= selector->bNrInPins; i++) {
2588c55af3fSEldad Zack 			int err;
2598c55af3fSEldad Zack 
2608c55af3fSEldad Zack 			if (i == cur)
2618c55af3fSEldad Zack 				continue;
2628c55af3fSEldad Zack 
2638c55af3fSEldad Zack 			ret = __uac_clock_find_source(chip, selector->baCSourceID[i - 1],
2648c55af3fSEldad Zack 				visited, true);
2658c55af3fSEldad Zack 			if (ret < 0)
2668c55af3fSEldad Zack 				continue;
2678c55af3fSEldad Zack 
2688c55af3fSEldad Zack 			err = uac_clock_selector_set_val(chip, entity_id, i);
2698c55af3fSEldad Zack 			if (err < 0)
2708c55af3fSEldad Zack 				continue;
2718c55af3fSEldad Zack 
2720ba41d91STakashi Iwai 			usb_audio_info(chip,
2730ba41d91STakashi Iwai 				 "found and selected valid clock source %d\n",
2740ba41d91STakashi Iwai 				 ret);
2758c55af3fSEldad Zack 			return ret;
2768c55af3fSEldad Zack 		}
2778c55af3fSEldad Zack 
2788c55af3fSEldad Zack 		return -ENXIO;
27979f920fbSDaniel Mack 	}
28079f920fbSDaniel Mack 
28179f920fbSDaniel Mack 	/* FIXME: multipliers only act as pass-thru element for now */
2823d8d4dcfSDaniel Mack 	multiplier = snd_usb_find_clock_multiplier(chip->ctrl_intf, entity_id);
28379f920fbSDaniel Mack 	if (multiplier)
2843d8d4dcfSDaniel Mack 		return __uac_clock_find_source(chip, multiplier->bCSourceID,
28506ffc1ebSEldad Zack 						visited, validate);
28679f920fbSDaniel Mack 
28779f920fbSDaniel Mack 	return -EINVAL;
28879f920fbSDaniel Mack }
28979f920fbSDaniel Mack 
2909a2fe9b8SRuslan Bilovol static int __uac3_clock_find_source(struct snd_usb_audio *chip, int entity_id,
2919a2fe9b8SRuslan Bilovol 				   unsigned long *visited, bool validate)
2929a2fe9b8SRuslan Bilovol {
2939a2fe9b8SRuslan Bilovol 	struct uac3_clock_source_descriptor *source;
2949a2fe9b8SRuslan Bilovol 	struct uac3_clock_selector_descriptor *selector;
2959a2fe9b8SRuslan Bilovol 	struct uac3_clock_multiplier_descriptor *multiplier;
2969a2fe9b8SRuslan Bilovol 
2979a2fe9b8SRuslan Bilovol 	entity_id &= 0xff;
2989a2fe9b8SRuslan Bilovol 
2999a2fe9b8SRuslan Bilovol 	if (test_and_set_bit(entity_id, visited)) {
3009a2fe9b8SRuslan Bilovol 		usb_audio_warn(chip,
3019a2fe9b8SRuslan Bilovol 			 "%s(): recursive clock topology detected, id %d.\n",
3029a2fe9b8SRuslan Bilovol 			 __func__, entity_id);
3039a2fe9b8SRuslan Bilovol 		return -EINVAL;
3049a2fe9b8SRuslan Bilovol 	}
3059a2fe9b8SRuslan Bilovol 
3069a2fe9b8SRuslan Bilovol 	/* first, see if the ID we're looking for is a clock source already */
3079a2fe9b8SRuslan Bilovol 	source = snd_usb_find_clock_source_v3(chip->ctrl_intf, entity_id);
3089a2fe9b8SRuslan Bilovol 	if (source) {
3099a2fe9b8SRuslan Bilovol 		entity_id = source->bClockID;
3109a2fe9b8SRuslan Bilovol 		if (validate && !uac_clock_source_is_valid(chip, UAC_VERSION_3,
3119a2fe9b8SRuslan Bilovol 								entity_id)) {
3129a2fe9b8SRuslan Bilovol 			usb_audio_err(chip,
3139a2fe9b8SRuslan Bilovol 				"clock source %d is not valid, cannot use\n",
3149a2fe9b8SRuslan Bilovol 				entity_id);
3159a2fe9b8SRuslan Bilovol 			return -ENXIO;
3169a2fe9b8SRuslan Bilovol 		}
3179a2fe9b8SRuslan Bilovol 		return entity_id;
3189a2fe9b8SRuslan Bilovol 	}
3199a2fe9b8SRuslan Bilovol 
3209a2fe9b8SRuslan Bilovol 	selector = snd_usb_find_clock_selector_v3(chip->ctrl_intf, entity_id);
3219a2fe9b8SRuslan Bilovol 	if (selector) {
3229a2fe9b8SRuslan Bilovol 		int ret, i, cur;
3239a2fe9b8SRuslan Bilovol 
3249a2fe9b8SRuslan Bilovol 		/* the entity ID we are looking for is a selector.
3259a2fe9b8SRuslan Bilovol 		 * find out what it currently selects */
3269a2fe9b8SRuslan Bilovol 		ret = uac_clock_selector_get_val(chip, selector->bClockID);
3279a2fe9b8SRuslan Bilovol 		if (ret < 0)
3289a2fe9b8SRuslan Bilovol 			return ret;
3299a2fe9b8SRuslan Bilovol 
3309a2fe9b8SRuslan Bilovol 		/* Selector values are one-based */
3319a2fe9b8SRuslan Bilovol 
3329a2fe9b8SRuslan Bilovol 		if (ret > selector->bNrInPins || ret < 1) {
3339a2fe9b8SRuslan Bilovol 			usb_audio_err(chip,
3349a2fe9b8SRuslan Bilovol 				"%s(): selector reported illegal value, id %d, ret %d\n",
3359a2fe9b8SRuslan Bilovol 				__func__, selector->bClockID, ret);
3369a2fe9b8SRuslan Bilovol 
3379a2fe9b8SRuslan Bilovol 			return -EINVAL;
3389a2fe9b8SRuslan Bilovol 		}
3399a2fe9b8SRuslan Bilovol 
3409a2fe9b8SRuslan Bilovol 		cur = ret;
3419a2fe9b8SRuslan Bilovol 		ret = __uac3_clock_find_source(chip, selector->baCSourceID[ret - 1],
3429a2fe9b8SRuslan Bilovol 					       visited, validate);
3439a2fe9b8SRuslan Bilovol 		if (!validate || ret > 0 || !chip->autoclock)
3449a2fe9b8SRuslan Bilovol 			return ret;
3459a2fe9b8SRuslan Bilovol 
3469a2fe9b8SRuslan Bilovol 		/* The current clock source is invalid, try others. */
3479a2fe9b8SRuslan Bilovol 		for (i = 1; i <= selector->bNrInPins; i++) {
3489a2fe9b8SRuslan Bilovol 			int err;
3499a2fe9b8SRuslan Bilovol 
3509a2fe9b8SRuslan Bilovol 			if (i == cur)
3519a2fe9b8SRuslan Bilovol 				continue;
3529a2fe9b8SRuslan Bilovol 
3539a2fe9b8SRuslan Bilovol 			ret = __uac3_clock_find_source(chip, selector->baCSourceID[i - 1],
3549a2fe9b8SRuslan Bilovol 				visited, true);
3559a2fe9b8SRuslan Bilovol 			if (ret < 0)
3569a2fe9b8SRuslan Bilovol 				continue;
3579a2fe9b8SRuslan Bilovol 
3589a2fe9b8SRuslan Bilovol 			err = uac_clock_selector_set_val(chip, entity_id, i);
3599a2fe9b8SRuslan Bilovol 			if (err < 0)
3609a2fe9b8SRuslan Bilovol 				continue;
3619a2fe9b8SRuslan Bilovol 
3629a2fe9b8SRuslan Bilovol 			usb_audio_info(chip,
3639a2fe9b8SRuslan Bilovol 				 "found and selected valid clock source %d\n",
3649a2fe9b8SRuslan Bilovol 				 ret);
3659a2fe9b8SRuslan Bilovol 			return ret;
3669a2fe9b8SRuslan Bilovol 		}
3679a2fe9b8SRuslan Bilovol 
3689a2fe9b8SRuslan Bilovol 		return -ENXIO;
3699a2fe9b8SRuslan Bilovol 	}
3709a2fe9b8SRuslan Bilovol 
3719a2fe9b8SRuslan Bilovol 	/* FIXME: multipliers only act as pass-thru element for now */
3729a2fe9b8SRuslan Bilovol 	multiplier = snd_usb_find_clock_multiplier_v3(chip->ctrl_intf,
3739a2fe9b8SRuslan Bilovol 						      entity_id);
3749a2fe9b8SRuslan Bilovol 	if (multiplier)
3759a2fe9b8SRuslan Bilovol 		return __uac3_clock_find_source(chip, multiplier->bCSourceID,
3769a2fe9b8SRuslan Bilovol 						visited, validate);
3779a2fe9b8SRuslan Bilovol 
3789a2fe9b8SRuslan Bilovol 	return -EINVAL;
3799a2fe9b8SRuslan Bilovol }
3809a2fe9b8SRuslan Bilovol 
381157a57b6SDaniel Mack /*
382157a57b6SDaniel Mack  * For all kinds of sample rate settings and other device queries,
383157a57b6SDaniel Mack  * the clock source (end-leaf) must be used. However, clock selectors,
384157a57b6SDaniel Mack  * clock multipliers and sample rate converters may be specified as
385157a57b6SDaniel Mack  * clock source input to terminal. This functions walks the clock path
386157a57b6SDaniel Mack  * to its end and tries to find the source.
387157a57b6SDaniel Mack  *
388157a57b6SDaniel Mack  * The 'visited' bitfield is used internally to detect recursive loops.
389157a57b6SDaniel Mack  *
390157a57b6SDaniel Mack  * Returns the clock source UnitID (>=0) on success, or an error.
391157a57b6SDaniel Mack  */
3929a2fe9b8SRuslan Bilovol int snd_usb_clock_find_source(struct snd_usb_audio *chip, int protocol,
3939a2fe9b8SRuslan Bilovol 			      int entity_id, bool validate)
39479f920fbSDaniel Mack {
39579f920fbSDaniel Mack 	DECLARE_BITMAP(visited, 256);
39679f920fbSDaniel Mack 	memset(visited, 0, sizeof(visited));
3979a2fe9b8SRuslan Bilovol 
3989a2fe9b8SRuslan Bilovol 	switch (protocol) {
3999a2fe9b8SRuslan Bilovol 	case UAC_VERSION_2:
4009a2fe9b8SRuslan Bilovol 		return __uac_clock_find_source(chip, entity_id, visited,
4019a2fe9b8SRuslan Bilovol 					       validate);
4029a2fe9b8SRuslan Bilovol 	case UAC_VERSION_3:
4039a2fe9b8SRuslan Bilovol 		return __uac3_clock_find_source(chip, entity_id, visited,
4049a2fe9b8SRuslan Bilovol 					       validate);
4059a2fe9b8SRuslan Bilovol 	default:
4069a2fe9b8SRuslan Bilovol 		return -EINVAL;
4079a2fe9b8SRuslan Bilovol 	}
40879f920fbSDaniel Mack }
40979f920fbSDaniel Mack 
41079f920fbSDaniel Mack static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
41179f920fbSDaniel Mack 			      struct usb_host_interface *alts,
41279f920fbSDaniel Mack 			      struct audioformat *fmt, int rate)
41379f920fbSDaniel Mack {
41479f920fbSDaniel Mack 	struct usb_device *dev = chip->dev;
41579f920fbSDaniel Mack 	unsigned int ep;
41679f920fbSDaniel Mack 	unsigned char data[3];
41779f920fbSDaniel Mack 	int err, crate;
41879f920fbSDaniel Mack 
419447d6275STakashi Iwai 	if (get_iface_desc(alts)->bNumEndpoints < 1)
420447d6275STakashi Iwai 		return -EINVAL;
42179f920fbSDaniel Mack 	ep = get_endpoint(alts, 0)->bEndpointAddress;
42279f920fbSDaniel Mack 
42379f920fbSDaniel Mack 	/* if endpoint doesn't have sampling rate control, bail out */
424d32d552eSClemens Ladisch 	if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE))
42579f920fbSDaniel Mack 		return 0;
42679f920fbSDaniel Mack 
42779f920fbSDaniel Mack 	data[0] = rate;
42879f920fbSDaniel Mack 	data[1] = rate >> 8;
42979f920fbSDaniel Mack 	data[2] = rate >> 16;
430f25ecf8fSTakashi Iwai 	err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
43179f920fbSDaniel Mack 			      USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
43279f920fbSDaniel Mack 			      UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
433f25ecf8fSTakashi Iwai 			      data, sizeof(data));
434f25ecf8fSTakashi Iwai 	if (err < 0) {
4350ba41d91STakashi Iwai 		dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n",
4360ba41d91STakashi Iwai 			iface, fmt->altsetting, rate, ep);
43779f920fbSDaniel Mack 		return err;
43879f920fbSDaniel Mack 	}
43979f920fbSDaniel Mack 
440b62b9980SJoe Turner 	/* Don't check the sample rate for devices which we know don't
441b62b9980SJoe Turner 	 * support reading */
442b62b9980SJoe Turner 	if (snd_usb_get_sample_rate_quirk(chip))
443b62b9980SJoe Turner 		return 0;
44457dd5414STakashi Iwai 	/* the firmware is likely buggy, don't repeat to fail too many times */
44557dd5414STakashi Iwai 	if (chip->sample_rate_read_error > 2)
44657dd5414STakashi Iwai 		return 0;
447b62b9980SJoe Turner 
448f25ecf8fSTakashi Iwai 	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
44979f920fbSDaniel Mack 			      USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
45079f920fbSDaniel Mack 			      UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
451f25ecf8fSTakashi Iwai 			      data, sizeof(data));
452f25ecf8fSTakashi Iwai 	if (err < 0) {
4530ba41d91STakashi Iwai 		dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n",
4540ba41d91STakashi Iwai 			iface, fmt->altsetting, ep);
45557dd5414STakashi Iwai 		chip->sample_rate_read_error++;
45679f920fbSDaniel Mack 		return 0; /* some devices don't support reading */
45779f920fbSDaniel Mack 	}
45879f920fbSDaniel Mack 
45979f920fbSDaniel Mack 	crate = data[0] | (data[1] << 8) | (data[2] << 16);
46079f920fbSDaniel Mack 	if (crate != rate) {
4610ba41d91STakashi Iwai 		dev_warn(&dev->dev, "current rate %d is different from the runtime rate %d\n", crate, rate);
46279f920fbSDaniel Mack 		// runtime->rate = crate;
46379f920fbSDaniel Mack 	}
46479f920fbSDaniel Mack 
46579f920fbSDaniel Mack 	return 0;
46679f920fbSDaniel Mack }
46779f920fbSDaniel Mack 
4689a2fe9b8SRuslan Bilovol static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
4697c517465STakashi Iwai 			      int altsetting, int clock)
4707c517465STakashi Iwai {
4717c517465STakashi Iwai 	struct usb_device *dev = chip->dev;
472f6a8bc70SEldad Zack 	__le32 data;
4737c517465STakashi Iwai 	int err;
4747c517465STakashi Iwai 
4757c517465STakashi Iwai 	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
4767c517465STakashi Iwai 			      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
4777c517465STakashi Iwai 			      UAC2_CS_CONTROL_SAM_FREQ << 8,
4787c517465STakashi Iwai 			      snd_usb_ctrl_intf(chip) | (clock << 8),
479f6a8bc70SEldad Zack 			      &data, sizeof(data));
4807c517465STakashi Iwai 	if (err < 0) {
4819a2fe9b8SRuslan Bilovol 		dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
4820ba41d91STakashi Iwai 			 iface, altsetting, err);
4837c517465STakashi Iwai 		return 0;
4847c517465STakashi Iwai 	}
4857c517465STakashi Iwai 
486f6a8bc70SEldad Zack 	return le32_to_cpu(data);
4877c517465STakashi Iwai }
4887c517465STakashi Iwai 
4899a2fe9b8SRuslan Bilovol static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
49079f920fbSDaniel Mack 			      struct usb_host_interface *alts,
49179f920fbSDaniel Mack 			      struct audioformat *fmt, int rate)
49279f920fbSDaniel Mack {
49379f920fbSDaniel Mack 	struct usb_device *dev = chip->dev;
494f6a8bc70SEldad Zack 	__le32 data;
495690a863fSTorstein Hegge 	int err, cur_rate, prev_rate;
4968c55af3fSEldad Zack 	int clock;
4971dc669feSEldad Zack 	bool writeable;
4989a2fe9b8SRuslan Bilovol 	u32 bmControls;
49979f920fbSDaniel Mack 
50058cabe87SAdam Goode 	/* First, try to find a valid clock. This may trigger
50158cabe87SAdam Goode 	 * automatic clock selection if the current clock is not
50258cabe87SAdam Goode 	 * valid.
50358cabe87SAdam Goode 	 */
5049a2fe9b8SRuslan Bilovol 	clock = snd_usb_clock_find_source(chip, fmt->protocol,
5059a2fe9b8SRuslan Bilovol 					  fmt->clock, true);
50658cabe87SAdam Goode 	if (clock < 0) {
50758cabe87SAdam Goode 		/* We did not find a valid clock, but that might be
50858cabe87SAdam Goode 		 * because the current sample rate does not match an
50958cabe87SAdam Goode 		 * external clock source. Try again without validation
51058cabe87SAdam Goode 		 * and we will do another validation after setting the
51158cabe87SAdam Goode 		 * rate.
51258cabe87SAdam Goode 		 */
51358cabe87SAdam Goode 		clock = snd_usb_clock_find_source(chip, fmt->protocol,
51458cabe87SAdam Goode 						  fmt->clock, false);
51579f920fbSDaniel Mack 		if (clock < 0)
51679f920fbSDaniel Mack 			return clock;
51758cabe87SAdam Goode 	}
51879f920fbSDaniel Mack 
5199a2fe9b8SRuslan Bilovol 	prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock);
520fa92dd77SDavid Henningsson 	if (prev_rate == rate)
52158cabe87SAdam Goode 		goto validation;
522690a863fSTorstein Hegge 
5239a2fe9b8SRuslan Bilovol 	if (fmt->protocol == UAC_VERSION_3) {
5249a2fe9b8SRuslan Bilovol 		struct uac3_clock_source_descriptor *cs_desc;
5259a2fe9b8SRuslan Bilovol 
5269a2fe9b8SRuslan Bilovol 		cs_desc = snd_usb_find_clock_source_v3(chip->ctrl_intf, clock);
5279a2fe9b8SRuslan Bilovol 		bmControls = le32_to_cpu(cs_desc->bmControls);
5289a2fe9b8SRuslan Bilovol 	} else {
5299a2fe9b8SRuslan Bilovol 		struct uac_clock_source_descriptor *cs_desc;
5309a2fe9b8SRuslan Bilovol 
5311dc669feSEldad Zack 		cs_desc = snd_usb_find_clock_source(chip->ctrl_intf, clock);
5329a2fe9b8SRuslan Bilovol 		bmControls = cs_desc->bmControls;
5339a2fe9b8SRuslan Bilovol 	}
5349a2fe9b8SRuslan Bilovol 
53521e9b3e9SAndrew Chant 	writeable = uac_v2v3_control_is_writeable(bmControls,
53621e9b3e9SAndrew Chant 						  UAC2_CS_CONTROL_SAM_FREQ);
5371dc669feSEldad Zack 	if (writeable) {
538f6a8bc70SEldad Zack 		data = cpu_to_le32(rate);
5391dc669feSEldad Zack 		err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
54079f920fbSDaniel Mack 				      USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
54111bcbc44SDaniel Mack 				      UAC2_CS_CONTROL_SAM_FREQ << 8,
54211bcbc44SDaniel Mack 				      snd_usb_ctrl_intf(chip) | (clock << 8),
5431dc669feSEldad Zack 				      &data, sizeof(data));
5441dc669feSEldad Zack 		if (err < 0) {
5450ba41d91STakashi Iwai 			usb_audio_err(chip,
5469a2fe9b8SRuslan Bilovol 				"%d:%d: cannot set freq %d (v2/v3): err %d\n",
5470ba41d91STakashi Iwai 				iface, fmt->altsetting, rate, err);
54879f920fbSDaniel Mack 			return err;
54979f920fbSDaniel Mack 		}
55079f920fbSDaniel Mack 
5519a2fe9b8SRuslan Bilovol 		cur_rate = get_sample_rate_v2v3(chip, iface,
5529a2fe9b8SRuslan Bilovol 						fmt->altsetting, clock);
5531dc669feSEldad Zack 	} else {
5541dc669feSEldad Zack 		cur_rate = prev_rate;
5551dc669feSEldad Zack 	}
55679f920fbSDaniel Mack 
557690a863fSTorstein Hegge 	if (cur_rate != rate) {
5581dc669feSEldad Zack 		if (!writeable) {
5590ba41d91STakashi Iwai 			usb_audio_warn(chip,
5600ba41d91STakashi Iwai 				 "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n",
5610ba41d91STakashi Iwai 				 iface, fmt->altsetting, rate, cur_rate);
5621dc669feSEldad Zack 			return -ENXIO;
5631dc669feSEldad Zack 		}
5640ba41d91STakashi Iwai 		usb_audio_dbg(chip,
565690a863fSTorstein Hegge 			"current rate %d is different from the runtime rate %d\n",
566690a863fSTorstein Hegge 			cur_rate, rate);
567690a863fSTorstein Hegge 	}
568690a863fSTorstein Hegge 
569690a863fSTorstein Hegge 	/* Some devices doesn't respond to sample rate changes while the
570690a863fSTorstein Hegge 	 * interface is active. */
571690a863fSTorstein Hegge 	if (rate != prev_rate) {
572690a863fSTorstein Hegge 		usb_set_interface(dev, iface, 0);
57321bb5aafSDaniel Mack 		snd_usb_set_interface_quirk(dev);
574690a863fSTorstein Hegge 		usb_set_interface(dev, iface, fmt->altsetting);
57521bb5aafSDaniel Mack 		snd_usb_set_interface_quirk(dev);
576690a863fSTorstein Hegge 	}
57779f920fbSDaniel Mack 
57858cabe87SAdam Goode validation:
57958cabe87SAdam Goode 	/* validate clock after rate change */
58058cabe87SAdam Goode 	if (!uac_clock_source_is_valid(chip, fmt->protocol, clock))
58158cabe87SAdam Goode 		return -ENXIO;
58279f920fbSDaniel Mack 	return 0;
58379f920fbSDaniel Mack }
58479f920fbSDaniel Mack 
58579f920fbSDaniel Mack int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
58679f920fbSDaniel Mack 			     struct usb_host_interface *alts,
58779f920fbSDaniel Mack 			     struct audioformat *fmt, int rate)
58879f920fbSDaniel Mack {
5898f898e92SClemens Ladisch 	switch (fmt->protocol) {
59079f920fbSDaniel Mack 	case UAC_VERSION_1:
591a2acad82SClemens Ladisch 	default:
59279f920fbSDaniel Mack 		return set_sample_rate_v1(chip, iface, alts, fmt, rate);
59379f920fbSDaniel Mack 
5949a2fe9b8SRuslan Bilovol 	case UAC_VERSION_3:
59517156f23SRuslan Bilovol 		if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
59617156f23SRuslan Bilovol 			if (rate != UAC3_BADD_SAMPLING_RATE)
59717156f23SRuslan Bilovol 				return -ENXIO;
59817156f23SRuslan Bilovol 			else
59917156f23SRuslan Bilovol 				return 0;
60017156f23SRuslan Bilovol 		}
60117156f23SRuslan Bilovol 	/* fall through */
60217156f23SRuslan Bilovol 	case UAC_VERSION_2:
6039a2fe9b8SRuslan Bilovol 		return set_sample_rate_v2v3(chip, iface, alts, fmt, rate);
60479f920fbSDaniel Mack 	}
60579f920fbSDaniel Mack }
60679f920fbSDaniel Mack 
607