162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Shared helper functions for devices from the ADAU family 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2016 Analog Devices Inc. 662306a36Sopenharmony_ci * Author: Lars-Peter Clausen <lars@metafoo.de> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/gcd.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "adau-utils.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciint adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out, 1662306a36Sopenharmony_ci uint8_t regs[5]) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci unsigned int r, n, m, i, j; 1962306a36Sopenharmony_ci unsigned int div; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci if (!freq_out) { 2262306a36Sopenharmony_ci r = 0; 2362306a36Sopenharmony_ci n = 0; 2462306a36Sopenharmony_ci m = 0; 2562306a36Sopenharmony_ci div = 0; 2662306a36Sopenharmony_ci } else { 2762306a36Sopenharmony_ci if (freq_out % freq_in != 0) { 2862306a36Sopenharmony_ci div = DIV_ROUND_UP(freq_in, 13500000); 2962306a36Sopenharmony_ci freq_in /= div; 3062306a36Sopenharmony_ci r = freq_out / freq_in; 3162306a36Sopenharmony_ci i = freq_out % freq_in; 3262306a36Sopenharmony_ci j = gcd(i, freq_in); 3362306a36Sopenharmony_ci n = i / j; 3462306a36Sopenharmony_ci m = freq_in / j; 3562306a36Sopenharmony_ci div--; 3662306a36Sopenharmony_ci } else { 3762306a36Sopenharmony_ci r = freq_out / freq_in; 3862306a36Sopenharmony_ci n = 0; 3962306a36Sopenharmony_ci m = 0; 4062306a36Sopenharmony_ci div = 0; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2) 4362306a36Sopenharmony_ci return -EINVAL; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci regs[0] = m >> 8; 4762306a36Sopenharmony_ci regs[1] = m & 0xff; 4862306a36Sopenharmony_ci regs[2] = n >> 8; 4962306a36Sopenharmony_ci regs[3] = n & 0xff; 5062306a36Sopenharmony_ci regs[4] = (r << 3) | (div << 1); 5162306a36Sopenharmony_ci if (m != 0) 5262306a36Sopenharmony_ci regs[4] |= 1; /* Fractional mode */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(adau_calc_pll_cfg); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC ADAU audio CODECs shared helper functions"); 5962306a36Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 6062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 61