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