blob: 8e066ebf1227c68730a79f054b67d2fea38998ae [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 Brown50017652012-07-04 19:07:09 +0100521 if (rates[i] >= snd_soc_params_to_bclk(params) &&
522 rates[i] % params_rate(params) == 0) {
Mark Brown07ed8732012-06-18 21:08:44 +0100523 bclk = i;
524 break;
525 }
526 }
Mark Brown949e6bc2012-07-04 18:58:04 +0100527 if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
Mark Brown07ed8732012-06-18 21:08:44 +0100528 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
529 params_rate(params));
530 return -EINVAL;
531 }
532
533 /*
534 * We will need to be more flexible than this in future,
535 * currently we use a single sample rate for the chip.
536 */
537 for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
538 if (arizona_sr_vals[i] == params_rate(params))
539 break;
540 if (i == ARRAY_SIZE(arizona_sr_vals)) {
541 arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
542 params_rate(params));
543 return -EINVAL;
544 }
545 sr_val = i;
546
547 lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
548
549 arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
550 rates[bclk], rates[bclk] / lrclk);
551
552 wl = snd_pcm_format_width(params_format(params));
553 frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
554
555 snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1,
556 ARIZONA_SAMPLE_RATE_1_MASK, sr_val);
557 snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
558 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
559 snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
560 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
561 snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
562 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
563 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
564 ARIZONA_AIF1TX_WL_MASK |
565 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
566 snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
567 ARIZONA_AIF1RX_WL_MASK |
568 ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
569
570 return 0;
571}
572
Mark Brown5b2eec32012-07-04 17:32:05 +0100573static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
574 int clk_id, unsigned int freq, int dir)
575{
576 struct snd_soc_codec *codec = dai->codec;
577 struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
578 struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
579
580 switch (clk_id) {
581 case ARIZONA_CLK_SYSCLK:
582 case ARIZONA_CLK_ASYNCCLK:
583 break;
584 default:
585 return -EINVAL;
586 }
587
588 if (clk_id != dai_priv->clk && dai->active) {
589 dev_err(codec->dev, "Can't change clock on active DAI %d\n",
590 dai->id);
591 return -EBUSY;
592 }
593
594 dai_priv->clk = clk_id;
595
596 return 0;
597}
598
Mark Brown07ed8732012-06-18 21:08:44 +0100599const struct snd_soc_dai_ops arizona_dai_ops = {
Mark Brown5b2eec32012-07-04 17:32:05 +0100600 .startup = arizona_startup,
Mark Brown07ed8732012-06-18 21:08:44 +0100601 .set_fmt = arizona_set_fmt,
602 .hw_params = arizona_hw_params,
Mark Brown5b2eec32012-07-04 17:32:05 +0100603 .set_sysclk = arizona_dai_set_sysclk,
Mark Brown07ed8732012-06-18 21:08:44 +0100604};
605
Mark Brown5b2eec32012-07-04 17:32:05 +0100606int arizona_init_dai(struct arizona_priv *priv, int id)
607{
608 struct arizona_dai_priv *dai_priv = &priv->dai[id];
609
610 dai_priv->clk = ARIZONA_CLK_SYSCLK;
611
612 return 0;
613}
614EXPORT_SYMBOL_GPL(arizona_init_dai);
615
Mark Brown07ed8732012-06-18 21:08:44 +0100616static irqreturn_t arizona_fll_lock(int irq, void *data)
617{
618 struct arizona_fll *fll = data;
619
620 arizona_fll_dbg(fll, "Locked\n");
621
622 complete(&fll->lock);
623
624 return IRQ_HANDLED;
625}
626
627static irqreturn_t arizona_fll_clock_ok(int irq, void *data)
628{
629 struct arizona_fll *fll = data;
630
631 arizona_fll_dbg(fll, "clock OK\n");
632
633 complete(&fll->ok);
634
635 return IRQ_HANDLED;
636}
637
638static struct {
639 unsigned int min;
640 unsigned int max;
641 u16 fratio;
642 int ratio;
643} fll_fratios[] = {
644 { 0, 64000, 4, 16 },
645 { 64000, 128000, 3, 8 },
646 { 128000, 256000, 2, 4 },
647 { 256000, 1000000, 1, 2 },
648 { 1000000, 13500000, 0, 1 },
649};
650
651struct arizona_fll_cfg {
652 int n;
653 int theta;
654 int lambda;
655 int refdiv;
656 int outdiv;
657 int fratio;
658};
659
660static int arizona_calc_fll(struct arizona_fll *fll,
661 struct arizona_fll_cfg *cfg,
662 unsigned int Fref,
663 unsigned int Fout)
664{
665 unsigned int target, div, gcd_fll;
666 int i, ratio;
667
668 arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout);
669
670 /* Fref must be <=13.5MHz */
671 div = 1;
672 cfg->refdiv = 0;
673 while ((Fref / div) > 13500000) {
674 div *= 2;
675 cfg->refdiv++;
676
677 if (div > 8) {
678 arizona_fll_err(fll,
679 "Can't scale %dMHz in to <=13.5MHz\n",
680 Fref);
681 return -EINVAL;
682 }
683 }
684
685 /* Apply the division for our remaining calculations */
686 Fref /= div;
687
688 /* Fvco should be 90-100MHz; don't check the upper bound */
689 div = 1;
690 while (Fout * div < 90000000) {
691 div++;
692 if (div > 7) {
693 arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
694 Fout);
695 return -EINVAL;
696 }
697 }
698 target = Fout * div;
699 cfg->outdiv = div;
700
701 arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
702
703 /* Find an appropraite FLL_FRATIO and factor it out of the target */
704 for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
705 if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
706 cfg->fratio = fll_fratios[i].fratio;
707 ratio = fll_fratios[i].ratio;
708 break;
709 }
710 }
711 if (i == ARRAY_SIZE(fll_fratios)) {
712 arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
713 Fref);
714 return -EINVAL;
715 }
716
717 cfg->n = target / (ratio * Fref);
718
719 if (target % Fref) {
720 gcd_fll = gcd(target, ratio * Fref);
721 arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
722
723 cfg->theta = (target - (cfg->n * ratio * Fref))
724 / gcd_fll;
725 cfg->lambda = (ratio * Fref) / gcd_fll;
726 } else {
727 cfg->theta = 0;
728 cfg->lambda = 0;
729 }
730
731 arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n",
732 cfg->n, cfg->theta, cfg->lambda);
733 arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
734 cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
735
736 return 0;
737
738}
739
740static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
741 struct arizona_fll_cfg *cfg, int source)
742{
743 regmap_update_bits(arizona->regmap, base + 3,
744 ARIZONA_FLL1_THETA_MASK, cfg->theta);
745 regmap_update_bits(arizona->regmap, base + 4,
746 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
747 regmap_update_bits(arizona->regmap, base + 5,
748 ARIZONA_FLL1_FRATIO_MASK,
749 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
750 regmap_update_bits(arizona->regmap, base + 6,
751 ARIZONA_FLL1_CLK_REF_DIV_MASK |
752 ARIZONA_FLL1_CLK_REF_SRC_MASK,
753 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
754 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
755
756 regmap_update_bits(arizona->regmap, base + 2,
757 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
758 ARIZONA_FLL1_CTRL_UPD | cfg->n);
759}
760
761int arizona_set_fll(struct arizona_fll *fll, int source,
762 unsigned int Fref, unsigned int Fout)
763{
764 struct arizona *arizona = fll->arizona;
765 struct arizona_fll_cfg cfg, sync;
766 unsigned int reg, val;
767 int syncsrc;
768 bool ena;
769 int ret;
770
771 ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
772 if (ret != 0) {
773 arizona_fll_err(fll, "Failed to read current state: %d\n",
774 ret);
775 return ret;
776 }
777 ena = reg & ARIZONA_FLL1_ENA;
778
779 if (Fout) {
780 /* Do we have a 32kHz reference? */
781 regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
782 switch (val & ARIZONA_CLK_32K_SRC_MASK) {
783 case ARIZONA_CLK_SRC_MCLK1:
784 case ARIZONA_CLK_SRC_MCLK2:
785 syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
786 break;
787 default:
788 syncsrc = -1;
789 }
790
791 if (source == syncsrc)
792 syncsrc = -1;
793
794 if (syncsrc >= 0) {
795 ret = arizona_calc_fll(fll, &sync, Fref, Fout);
796 if (ret != 0)
797 return ret;
798
799 ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
800 if (ret != 0)
801 return ret;
802 } else {
803 ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
804 if (ret != 0)
805 return ret;
806 }
807 } else {
808 regmap_update_bits(arizona->regmap, fll->base + 1,
809 ARIZONA_FLL1_ENA, 0);
810 regmap_update_bits(arizona->regmap, fll->base + 0x11,
811 ARIZONA_FLL1_SYNC_ENA, 0);
812
813 if (ena)
814 pm_runtime_put_autosuspend(arizona->dev);
815
816 return 0;
817 }
818
819 regmap_update_bits(arizona->regmap, fll->base + 5,
820 ARIZONA_FLL1_OUTDIV_MASK,
821 cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
822
823 if (syncsrc >= 0) {
824 arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
825 arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
826 } else {
827 arizona_apply_fll(arizona, fll->base, &cfg, source);
828 }
829
830 if (!ena)
831 pm_runtime_get(arizona->dev);
832
833 /* Clear any pending completions */
834 try_wait_for_completion(&fll->ok);
835
836 regmap_update_bits(arizona->regmap, fll->base + 1,
837 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
838 if (syncsrc >= 0)
839 regmap_update_bits(arizona->regmap, fll->base + 0x11,
840 ARIZONA_FLL1_SYNC_ENA,
841 ARIZONA_FLL1_SYNC_ENA);
842
843 ret = wait_for_completion_timeout(&fll->ok,
844 msecs_to_jiffies(25));
845 if (ret == 0)
846 arizona_fll_warn(fll, "Timed out waiting for lock\n");
847
848 return 0;
849}
850EXPORT_SYMBOL_GPL(arizona_set_fll);
851
852int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
853 int ok_irq, struct arizona_fll *fll)
854{
855 int ret;
856
857 init_completion(&fll->lock);
858 init_completion(&fll->ok);
859
860 fll->id = id;
861 fll->base = base;
862 fll->arizona = arizona;
863
864 snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
865 snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
866 "FLL%d clock OK", id);
867
868 ret = arizona_request_irq(arizona, lock_irq, fll->lock_name,
869 arizona_fll_lock, fll);
870 if (ret != 0) {
871 dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n",
872 id, ret);
873 }
874
875 ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name,
876 arizona_fll_clock_ok, fll);
877 if (ret != 0) {
878 dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n",
879 id, ret);
880 }
881
882 return 0;
883}
884EXPORT_SYMBOL_GPL(arizona_init_fll);
885
886MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
887MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
888MODULE_LICENSE("GPL");