wm8974.c (33d81af4d12fc8863247abba1c1d706b462e89d0) | wm8974.c (91d0c3ecbaf6616c0723d7aad9b6dadad2dea43f) |
---|---|
1/* 2 * wm8974.c -- WM8974 ALSA Soc Audio driver 3 * 4 * Copyright 2006 Wolfson Microelectronics PLC. 5 * 6 * Author: Liam Girdwood <linux@wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify --- 311 unchanged lines hidden (view full) --- 320 321 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 322 323 snd_soc_dapm_new_widgets(codec); 324 return 0; 325} 326 327struct pll_ { | 1/* 2 * wm8974.c -- WM8974 ALSA Soc Audio driver 3 * 4 * Copyright 2006 Wolfson Microelectronics PLC. 5 * 6 * Author: Liam Girdwood <linux@wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify --- 311 unchanged lines hidden (view full) --- 320 321 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 322 323 snd_soc_dapm_new_widgets(codec); 324 return 0; 325} 326 327struct pll_ { |
328 unsigned int in_hz, out_hz; 329 unsigned int pre:4; /* prescale - 1 */ | 328 unsigned int pre_div:4; /* prescale - 1 */ |
330 unsigned int n:4; 331 unsigned int k; 332}; 333 | 329 unsigned int n:4; 330 unsigned int k; 331}; 332 |
334static struct pll_ pll[] = { 335 { 12000000, 11289600, 0, 7, 0x86c220 }, 336 { 12000000, 12288000, 0, 8, 0x3126e8 }, 337 { 13000000, 11289600, 0, 6, 0xf28bd4 }, 338 { 13000000, 12288000, 0, 7, 0x8fd525 }, 339 { 12288000, 11289600, 0, 7, 0x59999a }, 340 { 11289600, 12288000, 0, 8, 0x80dee9 }, 341 { 25000000, 11289600, 1, 7, 0x39B024 }, 342 { 25000000, 24576000, 1, 7, 0xdd4413 } 343}; | 333static struct pll_ pll_div; |
344 | 334 |
335/* The size in bits of the pll divide multiplied by 10 336 * to allow rounding later */ 337#define FIXED_PLL_SIZE ((1 << 24) * 10) 338 339static void pll_factors(unsigned int target, unsigned int source) 340{ 341 unsigned long long Kpart; 342 unsigned int K, Ndiv, Nmod; 343 344 Ndiv = target / source; 345 if (Ndiv < 6) { 346 source >>= 1; 347 pll_div.pre_div = 1; 348 Ndiv = target / source; 349 } else 350 pll_div.pre_div = 0; 351 352 if ((Ndiv < 6) || (Ndiv > 12)) 353 printk(KERN_WARNING 354 "WM8974 N value %u outwith recommended range!d\n", 355 Ndiv); 356 357 pll_div.n = Ndiv; 358 Nmod = target % source; 359 Kpart = FIXED_PLL_SIZE * (long long)Nmod; 360 361 do_div(Kpart, source); 362 363 K = Kpart & 0xFFFFFFFF; 364 365 /* Check if we need to round */ 366 if ((K % 10) >= 5) 367 K += 5; 368 369 /* Move down to proper range now rounding is done */ 370 K /= 10; 371 372 pll_div.k = K; 373} 374 |
|
345static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, 346 int pll_id, unsigned int freq_in, unsigned int freq_out) 347{ 348 struct snd_soc_codec *codec = codec_dai->codec; | 375static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, 376 int pll_id, unsigned int freq_in, unsigned int freq_out) 377{ 378 struct snd_soc_codec *codec = codec_dai->codec; |
349 int i; | |
350 u16 reg; 351 352 if (freq_in == 0 || freq_out == 0) { | 379 u16 reg; 380 381 if (freq_in == 0 || freq_out == 0) { |
382 /* Clock CODEC directly from MCLK */ 383 reg = wm8974_read_reg_cache(codec, WM8974_CLOCK); 384 wm8974_write(codec, WM8974_CLOCK, reg & 0x0ff); 385 386 /* Turn off PLL */ |
|
353 reg = wm8974_read_reg_cache(codec, WM8974_POWER1); 354 wm8974_write(codec, WM8974_POWER1, reg & 0x1df); 355 return 0; 356 } 357 | 387 reg = wm8974_read_reg_cache(codec, WM8974_POWER1); 388 wm8974_write(codec, WM8974_POWER1, reg & 0x1df); 389 return 0; 390 } 391 |
358 for (i = 0; i < ARRAY_SIZE(pll); i++) { 359 if (freq_in == pll[i].in_hz && freq_out == pll[i].out_hz) { 360 wm8974_write(codec, WM8974_PLLN, 361 (pll[i].pre << 4) | pll[i].n); 362 wm8974_write(codec, WM8974_PLLK1, pll[i].k >> 18); 363 wm8974_write(codec, WM8974_PLLK2, 364 (pll[i].k >> 9) & 0x1ff); 365 wm8974_write(codec, WM8974_PLLK3, pll[i].k & 0x1ff); 366 reg = wm8974_read_reg_cache(codec, WM8974_POWER1); 367 wm8974_write(codec, WM8974_POWER1, reg | 0x020); 368 return 0; 369 } 370 } | 392 pll_factors(freq_out*4, freq_in); |
371 | 393 |
372 return -EINVAL; | 394 wm8974_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n); 395 wm8974_write(codec, WM8974_PLLK1, pll_div.k >> 18); 396 wm8974_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff); 397 wm8974_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff); 398 reg = wm8974_read_reg_cache(codec, WM8974_POWER1); 399 wm8974_write(codec, WM8974_POWER1, reg | 0x020); 400 401 /* Run CODEC from PLL instead of MCLK */ 402 reg = wm8974_read_reg_cache(codec, WM8974_CLOCK); 403 wm8974_write(codec, WM8974_CLOCK, reg | 0x100); 404 405 return 0; |
373} 374 375/* 376 * Configure WM8974 clock dividers. 377 */ 378static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai, 379 int div_id, int div) 380{ --- 427 unchanged lines hidden --- | 406} 407 408/* 409 * Configure WM8974 clock dividers. 410 */ 411static int wm8974_set_dai_clkdiv(struct snd_soc_dai *codec_dai, 412 int div_id, int div) 413{ --- 427 unchanged lines hidden --- |