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