18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <asm/div64.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "clk.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define div_mask(w) ((1 << (w)) - 1) 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ciint div_frac_get(unsigned long rate, unsigned parent_rate, u8 width, 138c2ecf20Sopenharmony_ci u8 frac_width, u8 flags) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci u64 divider_ux1 = parent_rate; 168c2ecf20Sopenharmony_ci int mul; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci if (!rate) 198c2ecf20Sopenharmony_ci return 0; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci mul = 1 << frac_width; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci if (!(flags & TEGRA_DIVIDER_INT)) 248c2ecf20Sopenharmony_ci divider_ux1 *= mul; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (flags & TEGRA_DIVIDER_ROUND_UP) 278c2ecf20Sopenharmony_ci divider_ux1 += rate - 1; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci do_div(divider_ux1, rate); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (flags & TEGRA_DIVIDER_INT) 328c2ecf20Sopenharmony_ci divider_ux1 *= mul; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (divider_ux1 < mul) 358c2ecf20Sopenharmony_ci return 0; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci divider_ux1 -= mul; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (divider_ux1 > div_mask(width)) 408c2ecf20Sopenharmony_ci return div_mask(width); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return divider_ux1; 438c2ecf20Sopenharmony_ci} 44