blob: 8e5246ca555027ae51046c3022d3b63e5194dae3 [file] [log] [blame]
Mark Brown07ed8732012-06-18 21:08:44 +01001/*
2 * arizona.c - Wolfson Arizona class device shared support
3 *
4 * Copyright 2012 Wolfson Microelectronics plc
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/gcd.h>
14#include <linux/module.h>
15#include <linux/pm_runtime.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/tlv.h>
19
20#include <linux/mfd/arizona/core.h>
21#include <linux/mfd/arizona/registers.h>
22
23#include "arizona.h"
24
25#define ARIZONA_AIF_BCLK_CTRL 0x00
26#define ARIZONA_AIF_TX_PIN_CTRL 0x01
27#define ARIZONA_AIF_RX_PIN_CTRL 0x02
28#define ARIZONA_AIF_RATE_CTRL 0x03
29#define ARIZONA_AIF_FORMAT 0x04
30#define ARIZONA_AIF_TX_BCLK_RATE 0x05
31#define ARIZONA_AIF_RX_BCLK_RATE 0x06
32#define ARIZONA_AIF_FRAME_CTRL_1 0x07
33#define ARIZONA_AIF_FRAME_CTRL_2 0x08
34#define ARIZONA_AIF_FRAME_CTRL_3 0x09
35#define ARIZONA_AIF_FRAME_CTRL_4 0x0A
36#define ARIZONA_AIF_FRAME_CTRL_5 0x0B
37#define ARIZONA_AIF_FRAME_CTRL_6 0x0C
38#define ARIZONA_AIF_FRAME_CTRL_7 0x0D
39#define ARIZONA_AIF_FRAME_CTRL_8 0x0E
40#define ARIZONA_AIF_FRAME_CTRL_9 0x0F
41#define ARIZONA_AIF_FRAME_CTRL_10 0x10
42#define ARIZONA_AIF_FRAME_CTRL_11 0x11
43#define ARIZONA_AIF_FRAME_CTRL_12 0x12
44#define ARIZONA_AIF_FRAME_CTRL_13 0x13
45#define ARIZONA_AIF_FRAME_CTRL_14 0x14
46#define ARIZONA_AIF_FRAME_CTRL_15 0x15
47#define ARIZONA_AIF_FRAME_CTRL_16 0x16
48#define ARIZONA_AIF_FRAME_CTRL_17 0x17
49#define ARIZONA_AIF_FRAME_CTRL_18 0x18
50#define ARIZONA_AIF_TX_ENABLES 0x19
51#define ARIZONA_AIF_RX_ENABLES 0x1A
52#define ARIZONA_AIF_FORCE_WRITE 0x1B
53
54#define arizona_fll_err(_fll, fmt, ...) \
55 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
56#define arizona_fll_warn(_fll, fmt, ...) \
57 dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
58#define arizona_fll_dbg(_fll, fmt, ...) \
59 dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
60
61#define arizona_aif_err(_dai, fmt, ...) \
62 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
63#define arizona_aif_warn(_dai, fmt, ...) \
64 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
65#define arizona_aif_dbg(_dai, fmt, ...) \
66 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
67
68const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
69 "None",
70 "Tone Generator 1",
71 "Tone Generator 2",
72 "Haptics",
73 "AEC",
74 "Mic Mute Mixer",
75 "Noise Generator",
76 "IN1L",
77 "IN1R",
78 "IN2L",
79 "IN2R",
80 "IN3L",
81 "IN3R",
82 "AIF1RX1",
83 "AIF1RX2",
84 "AIF1RX3",
85 "AIF1RX4",
86 "AIF1RX5",
87 "AIF1RX6",
88 "AIF1RX7",
89 "AIF1RX8",
90 "AIF2RX1",
91 "AIF2RX2",
92 "AIF3RX1",
93 "AIF3RX2",
94 "SLIMRX1",
95 "SLIMRX2",
96 "SLIMRX3",
97 "SLIMRX4",
98 "SLIMRX5",
99 "SLIMRX6",
100 "SLIMRX7",
101 "SLIMRX8",
102 "EQ1",
103 "EQ2",
104 "EQ3",
105 "EQ4",
106 "DRC1L",
107 "DRC1R",
108 "DRC2L",
109 "DRC2R",
110 "LHPF1",
111 "LHPF2",
112 "LHPF3",
113 "LHPF4",
114 "DSP1.1",
115 "DSP1.2",
116 "DSP1.3",
117 "DSP1.4",
118 "DSP1.5",
119 "DSP1.6",
120 "ASRC1L",
121 "ASRC1R",
122 "ASRC2L",
123 "ASRC2R",
124};
125EXPORT_SYMBOL_GPL(arizona_mixer_texts);
126
127int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
128 0x00, /* None */
129 0x04, /* Tone */
130 0x05,
131 0x06, /* Haptics */
132 0x08, /* AEC */
133 0x0c, /* Noise mixer */
134 0x0d, /* Comfort noise */
135 0x10, /* IN1L */
136 0x11,
137 0x12,
138 0x13,
139 0x14,
140 0x15,
141 0x20, /* AIF1RX1 */
142 0x21,
143 0x22,
144 0x23,
145 0x24,
146 0x25,
147 0x26,
148 0x27,
149 0x28, /* AIF2RX1 */
150 0x29,
151 0x30, /* AIF3RX1 */
152 0x31,
153 0x38, /* SLIMRX1 */
154 0x39,
155 0x3a,
156 0x3b,
157 0x3c,
158 0x3d,
159 0x3e,
160 0x3f,
161 0x50, /* EQ1 */
162 0x51,
163 0x52,
164 0x53,
165 0x58, /* DRC1L */
166 0x59,
167 0x5a,
168 0x5b,
169 0x60, /* LHPF1 */
170 0x61,
171 0x62,
172 0x63,
173 0x68, /* DSP1.1 */
174 0x69,
175 0x6a,
176 0x6b,
177 0x6c,
178 0x6d,
179 0x90, /* ASRC1L */
180 0x91,
181 0x92,
182 0x93,
183};
184EXPORT_SYMBOL_GPL(arizona_mixer_values);
185
186const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
187EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
188
189static const char *arizona_lhpf_mode_text[] = {
190 "Low-pass", "High-pass"
191};
192
193const struct soc_enum arizona_lhpf1_mode =
194 SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2,
195 arizona_lhpf_mode_text);
196EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
197
198const struct soc_enum arizona_lhpf2_mode =
199 SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2,
200 arizona_lhpf_mode_text);
201EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
202
203const struct soc_enum arizona_lhpf3_mode =
204 SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2,
205 arizona_lhpf_mode_text);
206EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
207
208const struct soc_enum arizona_lhpf4_mode =
209 SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2,
210 arizona_lhpf_mode_text);
211EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
212
213int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
214 int event)
215{
216 return 0;
217}
218EXPORT_SYMBOL_GPL(arizona_in_ev);
219
220int arizona_out_ev(struct snd_soc_dapm_widget *w,
221 struct snd_kcontrol *kcontrol,
222 int event)
223{
224 return 0;
225}
226EXPORT_SYMBOL_GPL(arizona_out_ev);
227
228int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
229 int source, unsigned int freq, int dir)
230{
231 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
232 struct arizona *arizona = priv->arizona;
233 char *name;
234 unsigned int reg;
235 unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
236 unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
237 unsigned int *clk;
238
239 switch (clk_id) {
240 case ARIZONA_CLK_SYSCLK:
241 name = "SYSCLK";
242 reg = ARIZONA_SYSTEM_CLOCK_1;
243 clk = &priv->sysclk;
244 mask |= ARIZONA_SYSCLK_FRAC;
245 break;
246 case ARIZONA_CLK_ASYNCCLK:
247 name = "ASYNCCLK";
248 reg = ARIZONA_ASYNC_CLOCK_1;
249 clk = &priv->asyncclk;
250 break;
251 default:
252 return -EINVAL;
253 }
254
255 switch (freq) {
256 case 5644800:
257 case 6144000:
258 break;
259 case 11289600:
260 case 12288000:
261 val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
262 break;
263 case 22579200:
264 case 24576000:
265 val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
266 break;
267 case 45158400:
268 case 49152000:
269 val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
270 break;
271 default:
272 return -EINVAL;
273 }
274
275 *clk = freq;
276
277 if (freq % 6144000)
278 val |= ARIZONA_SYSCLK_FRAC;
279
280 dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
281
282 return regmap_update_bits(arizona->regmap, reg, mask, val);
283}
284EXPORT_SYMBOL_GPL(arizona_set_sysclk);
285
286static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
287{
288 struct snd_soc_codec *codec = dai->codec;
289 int lrclk, bclk, mode, base;
290
291 base = dai->driver->base;
292
293 lrclk = 0;
294 bclk = 0;
295
296 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
297 case SND_SOC_DAIFMT_DSP_A:
298 mode = 0;
299 break;
300 case SND_SOC_DAIFMT_DSP_B:
301 mode = 1;
302 break;
303 case SND_SOC_DAIFMT_I2S:
304 mode = 2;
305 break;
306 case SND_SOC_DAIFMT_LEFT_J:
307 mode = 3;
308 break;
309 default:
310 arizona_aif_err(dai, "Unsupported DAI format %d\n",
311 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
312 return -EINVAL;
313 }
314
315 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
316 case SND_SOC_DAIFMT_CBS_CFS:
317 break;
318 case SND_SOC_DAIFMT_CBS_CFM:
319 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
320 break;
321 case SND_SOC_DAIFMT_CBM_CFS:
322 bclk |= ARIZONA_AIF1_BCLK_MSTR;
323 break;
324 case SND_SOC_DAIFMT_CBM_CFM:
325 bclk |= ARIZONA_AIF1_BCLK_MSTR;
326 lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
327 break;
328 default:
329 arizona_aif_err(dai, "Unsupported master mode %d\n",
330 fmt & SND_SOC_DAIFMT_MASTER_MASK);
331 return -EINVAL;
332 }
333
334 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
335 case SND_SOC_DAIFMT_NB_NF:
336 break;
337 case SND_SOC_DAIFMT_IB_IF:
338 bclk |= ARIZONA_AIF1_BCLK_INV;
339 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
340 break;
341 case SND_SOC_DAIFMT_IB_NF:
342 bclk |= ARIZONA_AIF1_BCLK_INV;
343 break;
344 case SND_SOC_DAIFMT_NB_IF:
345 lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
346 break;
347 default:
348 return -EINVAL;
349 }
350
351 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
352 ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
353 bclk);
354 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
355 ARIZONA_AIF1TX_LRCLK_INV |
356 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
357 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
358 ARIZONA_AIF1RX_LRCLK_INV |
359 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
360 snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
361 ARIZONA_AIF1_FMT_MASK, mode);
362
363 return 0;
364}
365
Mark Brown949e6bc2012-07-04 18:58:04 +0100366static const int arizona_48k_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100367 -1,
368 48000,
369 64000,
370 96000,
371 128000,
372 192000,
373 256000,
374 384000,
375 512000,
376 768000,
377 1024000,
378 1536000,
379 2048000,
380 3072000,
381 4096000,
382 6144000,
383 8192000,
384 12288000,
385 24576000,
386};
387
Mark Brown5b2eec32012-07-04 17:32:05 +0100388static const unsigned int arizona_48k_rates[] = {
389 12000,
390 24000,
391 48000,
392 96000,
393 192000,
394 384000,
395 768000,
396 4000,
397 8000,
398 16000,
399 32000,
400 64000,
401 128000,
402 256000,
403 512000,
404};
405
406static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = {
407 .count = ARRAY_SIZE(arizona_48k_rates),
408 .list = arizona_48k_rates,
409};
410
Mark Brown949e6bc2012-07-04 18:58:04 +0100411static const int arizona_44k1_bclk_rates[] = {
Mark Brown07ed8732012-06-18 21:08:44 +0100412 -1,
413 44100,
414 58800,
415 88200,
416 117600,
417 177640,
418 235200,
419 352800,
420 470400,
421 705600,
422 940800,
423 1411200,
424 1881600,
425 2882400,
426 3763200,
427 5644800,
428 7526400,
429 11289600,
430 22579200,
431};
432
Mark Brown5b2eec32012-07-04 17:32:05 +0100433static const unsigned int arizona_44k1_rates[] = {
434 11025,
435 22050,
436 44100,
437 88200,
438 176400,
439 352800,
440 705600,
441};
442
443static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = {
444 .count = ARRAY_SIZE(arizona_44k1_rates),
445 .list = arizona_44k1_rates,
446};
447
Mark Brown07ed8732012-06-18 21:08:44 +0100448static int arizona_sr_vals[] = {
449 0,
450 12000,
451 24000,
452 48000,
453 96000,
454 192000,
455 384000,
456 768000,
457 0,
458 11025,
459 22050,
460 44100,
461 88200,
462 176400,
463 352800,
464 705600,
465 4000,
466 8000,
467 16000,
468 32000,
469 64000,
470 128000,
471 256000,
472 512000,
473};
474
Mark Brown5b2eec32012-07-04 17:32:05 +0100475static int arizona_startup(struct snd_pcm_substream *substream,
476 struct snd_soc_dai *dai)
477{
478 struct snd_soc_codec *codec = dai->codec;
479 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
480 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
481 const struct snd_pcm_hw_constraint_list *constraint;
482 unsigned int base_rate;
483
484 switch (dai_priv->clk) {
485 case ARIZONA_CLK_SYSCLK:
486 base_rate = priv->sysclk;
487 break;
488 case ARIZONA_CLK_ASYNCCLK:
489 base_rate = priv->asyncclk;
490 break;
491 default:
492 return 0;
493 }
494
495 if (base_rate % 8000)
496 constraint = &arizona_44k1_constraint;
497 else
498 constraint = &arizona_48k_constraint;
499
500 return snd_pcm_hw_constraint_list(substream->runtime, 0,
501 SNDRV_PCM_HW_PARAM_RATE,
502 constraint);
503}
504
Mark Brown07ed8732012-06-18 21:08:44 +0100505static int arizona_hw_params(struct snd_pcm_substream *substream,
506 struct snd_pcm_hw_params *params,
507 struct snd_soc_dai *dai)
508{
509 struct snd_soc_codec *codec = dai->codec;
510 int base = dai->driver->base;
511 const int *rates;
512 int i;
513 int bclk, lrclk, wl, frame, sr_val;
514
515 if (params_rate(params) % 8000)
Mark Brown949e6bc2012-07-04 18:58:04 +0100516 rates = &arizona_44k1_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100517 else
Mark Brown949e6bc2012-07-04 18:58:04 +0100518 rates = &arizona_48k_bclk_rates[0];
Mark Brown07ed8732012-06-18 21:08:44 +0100519
Mark Brown949e6bc2012-07-04 18:58:04 +0100520 for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
Mark Brown07ed8732012-06-18 21:08:44 +0100521 if (rates[i] == snd_soc_params_to_bclk(params)) {
522 bclk = i;
523 break;
524 }
525 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100526 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100527 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
528 params_rate(params));
529 return -EINVAL;
530 }
531
532 /*
533 * We will need to be more flexible than this in future,
534 * currently we use a single sample rate for the chip.
535 */
536 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
537 if (arizona_sr_vals[i] == params_rate(params))
538 break;
539 if (i == ARRAY_SIZE(arizona_sr_vals)) {
540 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
541 params_rate(params));
542 return -EINVAL;
543 }
544 sr_val = i;
545
546 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
547
548 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
549 rates[bclk], rates[bclk] / lrclk);
550
551 wl = snd_pcm_format_width(params_format(params));
552 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
553
554 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
555 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
556 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
557 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
558 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
559 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
560 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
561 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
562 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
563 ARIZONA_AIF1TX_WL_MASK |
564 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
565 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
566 ARIZONA_AIF1RX_WL_MASK |
567 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
568
569 return 0;
570}
571
Mark Brown5b2eec32012-07-04 17:32:05 +0100572static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
573 int clk_id, unsigned int freq, int dir)
574{
575 struct snd_soc_codec *codec = dai->codec;
576 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
577 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
578
579 switch (clk_id) {
580 case ARIZONA_CLK_SYSCLK:
581 case ARIZONA_CLK_ASYNCCLK:
582 break;
583 default:
584 return -EINVAL;
585 }
586
587 if (clk_id != dai_priv->clk && dai->active) {
588 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
589 dai->id);
590 return -EBUSY;
591 }
592
593 dai_priv->clk = clk_id;
594
595 return 0;
596}
597
Mark Brown07ed8732012-06-18 21:08:44 +0100598const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100599 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100600 .set_fmt = arizona_set_fmt,
601 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100602 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100603};
604
Mark Brown5b2eec32012-07-04 17:32:05 +0100605int arizona_init_dai(struct arizona_priv *priv, int id)
606{
607 struct arizona_dai_priv *dai_priv = &priv->dai[id];
608
609 dai_priv->clk = ARIZONA_CLK_SYSCLK;
610
611 return 0;
612}
613EXPORT_SYMBOL_GPL(arizona_init_dai);
614
Mark Brown07ed8732012-06-18 21:08:44 +0100615static irqreturn_t arizona_fll_lock(int irq, void *data)
616{
617 struct arizona_fll *fll = data;
618
619 arizona_fll_dbg(fll, "Locked\n");
620
621 complete(&fll->lock);
622
623 return IRQ_HANDLED;
624}
625
626static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
627{
628 struct arizona_fll *fll = data;
629
630 arizona_fll_dbg(fll, "clock OK\n");
631
632 complete(&fll->ok);
633
634 return IRQ_HANDLED;
635}
636
637static struct {
638 unsigned int min;
639 unsigned int max;
640 u16 fratio;
641 int ratio;
642} fll_fratios[] = {
643 { 0, 64000, 4, 16 },
644 { 64000, 128000, 3, 8 },
645 { 128000, 256000, 2, 4 },
646 { 256000, 1000000, 1, 2 },
647 { 1000000, 13500000, 0, 1 },
648};
649
650struct arizona_fll_cfg {
651 int n;
652 int theta;
653 int lambda;
654 int refdiv;
655 int outdiv;
656 int fratio;
657};
658
659static int arizona_calc_fll(struct arizona_fll *fll,
660 struct arizona_fll_cfg *cfg,
661 unsigned int Fref,
662 unsigned int Fout)
663{
664 unsigned int target, div, gcd_fll;
665 int i, ratio;
666
667 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
668
669 /* Fref must be <=13.5MHz */
670 div = 1;
671 cfg->refdiv = 0;
672 while ((Fref / div) > 13500000) {
673 div *= 2;
674 cfg->refdiv++;
675
676 if (div > 8) {
677 arizona_fll_err(fll,
678 "Can't scale %dMHz in to <=13.5MHz\n",
679 Fref);
680 return -EINVAL;
681 }
682 }
683
684 /* Apply the division for our remaining calculations */
685 Fref /= div;
686
687 /* Fvco should be 90-100MHz; don't check the upper bound */
688 div = 1;
689 while (Fout * div < 90000000) {
690 div++;
691 if (div > 7) {
692 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
693 Fout);
694 return -EINVAL;
695 }
696 }
697 target = Fout * div;
698 cfg->outdiv = div;
699
700 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
701
702 /* Find an appropraite FLL_FRATIO and factor it out of the target */
703 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
704 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
705 cfg->fratio = fll_fratios[i].fratio;
706 ratio = fll_fratios[i].ratio;
707 break;
708 }
709 }
710 if (i == ARRAY_SIZE(fll_fratios)) {
711 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
712 Fref);
713 return -EINVAL;
714 }
715
716 cfg->n = target / (ratio * Fref);
717
718 if (target % Fref) {
719 gcd_fll = gcd(target, ratio * Fref);
720 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
721
722 cfg->theta = (target - (cfg->n * ratio * Fref))
723 / gcd_fll;
724 cfg->lambda = (ratio * Fref) / gcd_fll;
725 } else {
726 cfg->theta = 0;
727 cfg->lambda = 0;
728 }
729
730 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
731 cfg->n, cfg->theta, cfg->lambda);
732 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
733 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
734
735 return 0;
736
737}
738
739static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
740 struct arizona_fll_cfg *cfg, int source)
741{
742 regmap_update_bits(arizona->regmap, base + 3,
743 ARIZONA_FLL1_THETA_MASK, cfg->theta);
744 regmap_update_bits(arizona->regmap, base + 4,
745 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
746 regmap_update_bits(arizona->regmap, base + 5,
747 ARIZONA_FLL1_FRATIO_MASK,
748 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
749 regmap_update_bits(arizona->regmap, base + 6,
750 ARIZONA_FLL1_CLK_REF_DIV_MASK |
751 ARIZONA_FLL1_CLK_REF_SRC_MASK,
752 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
753 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
754
755 regmap_update_bits(arizona->regmap, base + 2,
756 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
757 ARIZONA_FLL1_CTRL_UPD | cfg->n);
758}
759
760int arizona_set_fll(struct arizona_fll *fll, int source,
761 unsigned int Fref, unsigned int Fout)
762{
763 struct arizona *arizona = fll->arizona;
764 struct arizona_fll_cfg cfg, sync;
765 unsigned int reg, val;
766 int syncsrc;
767 bool ena;
768 int ret;
769
770 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
771 if (ret != 0) {
772 arizona_fll_err(fll, "Failed to read current state: %d\n",
773 ret);
774 return ret;
775 }
776 ena = reg & ARIZONA_FLL1_ENA;
777
778 if (Fout) {
779 /* Do we have a 32kHz reference? */
780 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
781 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
782 case ARIZONA_CLK_SRC_MCLK1:
783 case ARIZONA_CLK_SRC_MCLK2:
784 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
785 break;
786 default:
787 syncsrc = -1;
788 }
789
790 if (source == syncsrc)
791 syncsrc = -1;
792
793 if (syncsrc >= 0) {
794 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
795 if (ret != 0)
796 return ret;
797
798 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
799 if (ret != 0)
800 return ret;
801 } else {
802 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
803 if (ret != 0)
804 return ret;
805 }
806 } else {
807 regmap_update_bits(arizona->regmap, fll->base + 1,
808 ARIZONA_FLL1_ENA, 0);
809 regmap_update_bits(arizona->regmap, fll->base + 0x11,
810 ARIZONA_FLL1_SYNC_ENA, 0);
811
812 if (ena)
813 pm_runtime_put_autosuspend(arizona->dev);
814
815 return 0;
816 }
817
818 regmap_update_bits(arizona->regmap, fll->base + 5,
819 ARIZONA_FLL1_OUTDIV_MASK,
820 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
821
822 if (syncsrc >= 0) {
823 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
824 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
825 } else {
826 arizona_apply_fll(arizona, fll->base, &cfg, source);
827 }
828
829 if (!ena)
830 pm_runtime_get(arizona->dev);
831
832 /* Clear any pending completions */
833 try_wait_for_completion(&fll->ok);
834
835 regmap_update_bits(arizona->regmap, fll->base + 1,
836 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
837 if (syncsrc >= 0)
838 regmap_update_bits(arizona->regmap, fll->base + 0x11,
839 ARIZONA_FLL1_SYNC_ENA,
840 ARIZONA_FLL1_SYNC_ENA);
841
842 ret = wait_for_completion_timeout(&fll->ok,
843 msecs_to_jiffies(25));
844 if (ret == 0)
845 arizona_fll_warn(fll, "Timed out waiting for lock\n");
846
847 return 0;
848}
849EXPORT_SYMBOL_GPL(arizona_set_fll);
850
851int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
852 int ok_irq, struct arizona_fll *fll)
853{
854 int ret;
855
856 init_completion(&fll->lock);
857 init_completion(&fll->ok);
858
859 fll->id = id;
860 fll->base = base;
861 fll->arizona = arizona;
862
863 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
864 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
865 "FLL%d clock OK", id);
866
867 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
868 arizona_fll_lock, fll);
869 if (ret != 0) {
870 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
871 id, ret);
872 }
873
874 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
875 arizona_fll_clock_ok, fll);
876 if (ret != 0) {
877 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
878 id, ret);
879 }
880
881 return 0;
882}
883EXPORT_SYMBOL_GPL(arizona_init_fll);
884
885MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
886MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
887MODULE_LICENSE("GPL");