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	/* ajustement */
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
311