18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Shared helper functions for devices from the ADAU family 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2011-2016 Analog Devices Inc. 68c2ecf20Sopenharmony_ci * Author: Lars-Peter Clausen <lars@metafoo.de> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/gcd.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "adau-utils.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ciint adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out, 168c2ecf20Sopenharmony_ci uint8_t regs[5]) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci unsigned int r, n, m, i, j; 198c2ecf20Sopenharmony_ci unsigned int div; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci if (!freq_out) { 228c2ecf20Sopenharmony_ci r = 0; 238c2ecf20Sopenharmony_ci n = 0; 248c2ecf20Sopenharmony_ci m = 0; 258c2ecf20Sopenharmony_ci div = 0; 268c2ecf20Sopenharmony_ci } else { 278c2ecf20Sopenharmony_ci if (freq_out % freq_in != 0) { 288c2ecf20Sopenharmony_ci div = DIV_ROUND_UP(freq_in, 13500000); 298c2ecf20Sopenharmony_ci freq_in /= div; 308c2ecf20Sopenharmony_ci r = freq_out / freq_in; 318c2ecf20Sopenharmony_ci i = freq_out % freq_in; 328c2ecf20Sopenharmony_ci j = gcd(i, freq_in); 338c2ecf20Sopenharmony_ci n = i / j; 348c2ecf20Sopenharmony_ci m = freq_in / j; 358c2ecf20Sopenharmony_ci div--; 368c2ecf20Sopenharmony_ci } else { 378c2ecf20Sopenharmony_ci r = freq_out / freq_in; 388c2ecf20Sopenharmony_ci n = 0; 398c2ecf20Sopenharmony_ci m = 0; 408c2ecf20Sopenharmony_ci div = 0; 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2) 438c2ecf20Sopenharmony_ci return -EINVAL; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci regs[0] = m >> 8; 478c2ecf20Sopenharmony_ci regs[1] = m & 0xff; 488c2ecf20Sopenharmony_ci regs[2] = n >> 8; 498c2ecf20Sopenharmony_ci regs[3] = n & 0xff; 508c2ecf20Sopenharmony_ci regs[4] = (r << 3) | (div << 1); 518c2ecf20Sopenharmony_ci if (m != 0) 528c2ecf20Sopenharmony_ci regs[4] |= 1; /* Fractional mode */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(adau_calc_pll_cfg); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC ADAU audio CODECs shared helper functions"); 598c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 608c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 61