File Index
Files and directories
Sign in
FILE

lola_clock.c

File preview with syntax highlighting.

linux-6.19.14/sound/pci/lola/lola_clock.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Support for Digigram Lola PCI-e boards
  4 *
  5 *  Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
  6 */
  7
  8#include <linux/kernel.h>
  9#include <linux/init.h>
 10#include <linux/delay.h>
 11#include <sound/core.h>
 12#include <sound/pcm.h>
 13#include "lola.h"
 14
 15unsigned int lola_sample_rate_convert(unsigned int coded)
 16{
 17	unsigned int freq;
 18
 19	/* base frequency */
 20	switch (coded & 0x3) {
 21	case 0:     freq = 48000; break;
 22	case 1:     freq = 44100; break;
 23	case 2:     freq = 32000; break;
 24	default:    return 0;   /* error */
 25	}
 26
 27	/* multiplier / devisor */
 28	switch (coded & 0x1c) {
 29	case (0 << 2):    break;
 30	case (4 << 2):    break;
 31	case (1 << 2):    freq *= 2; break;
 32	case (2 << 2):    freq *= 4; break;
 33	case (5 << 2):    freq /= 2; break;
 34	case (6 << 2):    freq /= 4; break;
 35	default:        return 0;   /* error */
 36	}
 37
 38	/* adjustement */
 39	switch (coded & 0x60) {
 40	case (0 << 5):    break;
 41	case (1 << 5):    freq = (freq * 999) / 1000; break;
 42	case (2 << 5):    freq = (freq * 1001) / 1000; break;
 43	default:        return 0;   /* error */
 44	}
 45	return freq;
 46}
 47
 48/*
 49 * Granualrity
 50 */
 51
 52#define LOLA_MAXFREQ_AT_GRANULARITY_MIN         48000
 53#define LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX   96000
 54
 55static bool check_gran_clock_compatibility(struct lola *chip,
 56					   unsigned int val,
 57					   unsigned int freq)
 58{
 59	if (!chip->granularity)
 60		return true;
 61
 62	if (val < LOLA_GRANULARITY_MIN || val > LOLA_GRANULARITY_MAX ||
 63	    (val % LOLA_GRANULARITY_STEP) != 0)
 64		return false;
 65
 66	if (val == LOLA_GRANULARITY_MIN) {
 67		if (freq > LOLA_MAXFREQ_AT_GRANULARITY_MIN)
 68			return false;
 69	} else if (val < LOLA_GRANULARITY_MAX) {
 70		if (freq > LOLA_MAXFREQ_AT_GRANULARITY_BELOW_MAX)
 71			return false;
 72	}
 73	return true;
 74}
 75
 76int lola_set_granularity(struct lola *chip, unsigned int val, bool force)
 77{
 78	int err;
 79
 80	if (!force) {
 81		if (val == chip->granularity)
 82			return 0;
 83#if 0
 84		/* change Gran only if there are no streams allocated ! */
 85		if (chip->audio_in_alloc_mask || chip->audio_out_alloc_mask)
 86			return -EBUSY;
 87#endif
 88		if (!check_gran_clock_compatibility(chip, val,
 89						    chip->clock.cur_freq))
 90			return -EINVAL;
 91	}
 92
 93	chip->granularity = val;
 94	val /= LOLA_GRANULARITY_STEP;
 95
 96	/* audio function group */
 97	err = lola_codec_write(chip, 1, LOLA_VERB_SET_GRANULARITY_STEPS,
 98			       val, 0);
 99	if (err < 0)
100		return err;
101	/* this can be a very slow function !!! */
102	usleep_range(400 * val, 20000);
103	return lola_codec_flush(chip);
104}
105
106/*
107 * Clock widget handling
108 */
109
110int lola_init_clock_widget(struct lola *chip, int nid)
111{
112	unsigned int val;
113	int i, j, nitems, nb_verbs, idx, idx_list;
114	int err;
115
116	err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val);
117	if (err < 0) {
118		dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid);
119		return err;
120	}
121
122	if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */
123		dev_dbg(chip->card->dev, "No valid clock widget\n");
124		return 0;
125	}
126
127	chip->clock.nid = nid;
128	chip->clock.items = val & 0xff;
129	dev_dbg(chip->card->dev, "clock_list nid=%x, entries=%d\n", nid,
130		    chip->clock.items);
131	if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) {
132		dev_err(chip->card->dev, "CLOCK_LIST too big: %d\n",
133		       chip->clock.items);
134		return -EINVAL;
135	}
136
137	nitems = chip->clock.items;
138	nb_verbs = DIV_ROUND_UP(nitems, 4);
139	idx = 0;
140	idx_list = 0;
141	for (i = 0; i < nb_verbs; i++) {
142		unsigned int res_ex;
143		unsigned short items[4];
144
145		err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST,
146				      idx, 0, &val, &res_ex);
147		if (err < 0) {
148			dev_err(chip->card->dev, "Can't read CLOCK_LIST\n");
149			return -EINVAL;
150		}
151
152		items[0] = val & 0xfff;
153		items[1] = (val >> 16) & 0xfff;
154		items[2] = res_ex & 0xfff;
155		items[3] = (res_ex >> 16) & 0xfff;
156
157		for (j = 0; j < 4; j++) {
158			unsigned char type = items[j] >> 8;
159			unsigned int freq = items[j] & 0xff;
160			int format = LOLA_CLOCK_FORMAT_NONE;
161			bool add_clock = true;
162			if (type == LOLA_CLOCK_TYPE_INTERNAL) {
163				freq = lola_sample_rate_convert(freq);
164				if (freq < chip->sample_rate_min)
165					add_clock = false;
166				else if (freq == 48000) {
167					chip->clock.cur_index = idx_list;
168					chip->clock.cur_freq = 48000;
169					chip->clock.cur_valid = true;
170				}
171			} else if (type == LOLA_CLOCK_TYPE_VIDEO) {
172				freq = lola_sample_rate_convert(freq);
173				if (freq < chip->sample_rate_min)
174					add_clock = false;
175				/* video clock has a format (0:NTSC, 1:PAL)*/
176				if (items[j] & 0x80)
177					format = LOLA_CLOCK_FORMAT_NTSC;
178				else
179					format = LOLA_CLOCK_FORMAT_PAL;
180			}
181			if (add_clock) {
182				struct lola_sample_clock *sc;
183				sc = &chip->clock.sample_clock[idx_list];
184				sc->type = type;
185				sc->format = format;
186				sc->freq = freq;
187				/* keep the index used with the board */
188				chip->clock.idx_lookup[idx_list] = idx;
189				idx_list++;
190			} else {
191				chip->clock.items--;
192			}
193			if (++idx >= nitems)
194				break;
195		}
196	}
197	return 0;
198}
199
200/* enable unsolicited events of the clock widget */
201int lola_enable_clock_events(struct lola *chip)
202{
203	unsigned int res;
204	int err;
205
206	err = lola_codec_read(chip, chip->clock.nid,
207			      LOLA_VERB_SET_UNSOLICITED_ENABLE,
208			      LOLA_UNSOLICITED_ENABLE | LOLA_UNSOLICITED_TAG,
209			      0, &res, NULL);
210	if (err < 0)
211		return err;
212	if (res) {
213		dev_warn(chip->card->dev, "error in enable_clock_events %d\n",
214		       res);
215		return -EINVAL;
216	}
217	return 0;
218}
219
220int lola_set_clock_index(struct lola *chip, unsigned int idx)
221{
222	unsigned int res;
223	int err;
224
225	err = lola_codec_read(chip, chip->clock.nid,
226			      LOLA_VERB_SET_CLOCK_SELECT,
227			      chip->clock.idx_lookup[idx],
228			      0, &res, NULL);
229	if (err < 0)
230		return err;
231	if (res) {
232		dev_warn(chip->card->dev, "error in set_clock %d\n", res);
233		return -EINVAL;
234	}
235	return 0;
236}
237
238bool lola_update_ext_clock_freq(struct lola *chip, unsigned int val)
239{
240	unsigned int tag;
241
242	/* the current EXTERNAL clock information gets updated by interrupt
243	 * with an unsolicited response
244	 */
245	if (!val)
246		return false;
247	tag = (val >> LOLA_UNSOL_RESP_TAG_OFFSET) & LOLA_UNSOLICITED_TAG_MASK;
248	if (tag != LOLA_UNSOLICITED_TAG)
249		return false;
250
251	/* only for current = external clocks */
252	if (chip->clock.sample_clock[chip->clock.cur_index].type !=
253	    LOLA_CLOCK_TYPE_INTERNAL) {
254		chip->clock.cur_freq = lola_sample_rate_convert(val & 0x7f);
255		chip->clock.cur_valid = (val & 0x100) != 0;
256	}
257	return true;
258}
259
260int lola_set_clock(struct lola *chip, int idx)
261{
262	int freq = 0;
263	bool valid = false;
264
265	if (idx == chip->clock.cur_index) {
266		/* current clock is allowed */
267		freq = chip->clock.cur_freq;
268		valid = chip->clock.cur_valid;
269	} else if (chip->clock.sample_clock[idx].type ==
270		   LOLA_CLOCK_TYPE_INTERNAL) {
271		/* internal clocks allowed */
272		freq = chip->clock.sample_clock[idx].freq;
273		valid = true;
274	}
275
276	if (!freq || !valid)
277		return -EINVAL;
278
279	if (!check_gran_clock_compatibility(chip, chip->granularity, freq))
280		return -EINVAL;
281
282	if (idx != chip->clock.cur_index) {
283		int err = lola_set_clock_index(chip, idx);
284		if (err < 0)
285			return err;
286		/* update new settings */
287		chip->clock.cur_index = idx;
288		chip->clock.cur_freq = freq;
289		chip->clock.cur_valid = true;
290	}
291	return 0;
292}
293
294int lola_set_sample_rate(struct lola *chip, int rate)
295{
296	int i;
297
298	if (chip->clock.cur_freq == rate && chip->clock.cur_valid)
299		return 0;
300	/* search for new dwClockIndex */
301	for (i = 0; i < chip->clock.items; i++) {
302		if (chip->clock.sample_clock[i].type == LOLA_CLOCK_TYPE_INTERNAL &&
303		    chip->clock.sample_clock[i].freq == rate)
304			break;
305	}
306	if (i >= chip->clock.items)
307		return -EINVAL;
308	return lola_set_clock(chip, i);
309}
310
~/ Read-only file preview.