// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2019 DENX Software Engineering
 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
 *
 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
 * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
 *
 */

#define LOG_CATEGORY UCLASS_CLK

#include <asm/io.h>
#include <malloc.h>
#include <clk-uclass.h>
#include <log.h>
#include <dm/device.h>
#include <dm/devres.h>
#include <dm/uclass.h>
#include <dm/lists.h>
#include <dm/device_compat.h>
#include <dm/device-internal.h>
#include <linux/bug.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/log2.h>
#include <div64.h>
#include <clk.h>
#include <linux/printk.h>
#include "clk.h"

#define UBOOT_DM_CLK_CCF_DIVIDER "ccf_clk_divider"

unsigned int clk_divider_get_table_div(const struct clk_div_table *table,
				       unsigned int val)
{
	const struct clk_div_table *clkt;

	for (clkt = table; clkt->div; clkt++)
		if (clkt->val == val)
			return clkt->div;
	return 0;
}

static unsigned int _get_div(const struct clk_div_table *table,
			     unsigned int val, unsigned long flags, u8 width)
{
	if (flags & CLK_DIVIDER_ONE_BASED)
		return val;
	if (flags & CLK_DIVIDER_POWER_OF_TWO)
		return 1 << val;
	if (flags & CLK_DIVIDER_MAX_AT_ZERO)
		return val ? val : clk_div_mask(width) + 1;
	if (table)
		return clk_divider_get_table_div(table, val);
	return val + 1;
}

unsigned long divider_recalc_rate(struct clk *hw, unsigned long parent_rate,
				  unsigned int val,
				  const struct clk_div_table *table,
				  unsigned long flags, unsigned long width)
{
	unsigned int div;

	div = _get_div(table, val, flags, width);
	if (!div) {
		WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
		     "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
		     clk_hw_get_name(hw));
		return parent_rate;
	}

	return DIV_ROUND_UP_ULL((u64)parent_rate, div);
}

static ulong clk_divider_recalc_rate(struct clk *clk)
{
	struct clk_divider *divider = to_clk_divider(clk);
	unsigned long parent_rate = clk_get_parent_rate(clk);
	unsigned int val;

#if IS_ENABLED(CONFIG_SANDBOX_CLK_CCF)
	val = divider->io_divider_val;
#else
	val = readl(divider->reg);
#endif
	val >>= divider->shift;
	val &= clk_div_mask(divider->width);

	return divider_recalc_rate(clk, parent_rate, val, divider->table,
				   divider->flags, divider->width);
}

bool clk_divider_is_valid_table_div(const struct clk_div_table *table,
				    unsigned int div)
{
	const struct clk_div_table *clkt;

	for (clkt = table; clkt->div; clkt++)
		if (clkt->div == div)
			return true;
	return false;
}

bool clk_divider_is_valid_div(const struct clk_div_table *table,
			      unsigned int div, unsigned long flags)
{
	if (flags & CLK_DIVIDER_POWER_OF_TWO)
		return is_power_of_2(div);
	if (table)
		return clk_divider_is_valid_table_div(table, div);
	return true;
}

unsigned int clk_divider_get_table_val(const struct clk_div_table *table,
				       unsigned int div)
{
	const struct clk_div_table *clkt;

	for (clkt = table; clkt->div; clkt++)
		if (clkt->div == div)
			return clkt->val;
	return 0;
}

static unsigned int _get_val(const struct clk_div_table *table,
			     unsigned int div, unsigned long flags, u8 width)
{
	if (flags & CLK_DIVIDER_ONE_BASED)
		return div;
	if (flags & CLK_DIVIDER_POWER_OF_TWO)
		return __ffs(div);
	if (flags & CLK_DIVIDER_MAX_AT_ZERO)
		return (div == clk_div_mask(width) + 1) ? 0 : div;
	if (table)
		return clk_divider_get_table_val(table, div);
	return div - 1;
}
int divider_get_val(unsigned long rate, unsigned long parent_rate,
		    const struct clk_div_table *table, u8 width,
		    unsigned long flags)
{
	unsigned int div, value;

	div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);

	if (!clk_divider_is_valid_div(table, div, flags))
		return -EINVAL;

	value = _get_val(table, div, flags, width);

	return min_t(unsigned int, value, clk_div_mask(width));
}

static ulong clk_divider_set_rate(struct clk *clk, unsigned long rate)
{
	struct clk_divider *divider = to_clk_divider(clk);
	unsigned long parent_rate = clk_get_parent_rate(clk);
	int value;
	u32 val;

	value = divider_get_val(rate, parent_rate, divider->table,
				divider->width, divider->flags);
	if (value < 0)
		return value;

	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
		val = clk_div_mask(divider->width) << (divider->shift + 16);
	} else {
		val = readl(divider->reg);
		val &= ~(clk_div_mask(divider->width) << divider->shift);
	}
	val |= (u32)value << divider->shift;
	writel(val, divider->reg);

	return clk_get_rate(clk);
}

const struct clk_ops clk_divider_ops = {
	.get_rate = clk_divider_recalc_rate,
	.set_rate = clk_divider_set_rate,
};

static struct clk *_register_divider(struct device *dev, const char *name,
		const char *parent_name, unsigned long flags,
		void __iomem *reg, u8 shift, u8 width,
		u8 clk_divider_flags, const struct clk_div_table *table)
{
	struct clk_divider *div;
	struct clk *clk;
	int ret;

	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
		if (width + shift > 16) {
			dev_warn(dev, "divider value exceeds LOWORD field\n");
			return ERR_PTR(-EINVAL);
		}
	}

	/* allocate the divider */
	div = kzalloc(sizeof(*div), GFP_KERNEL);
	if (!div)
		return ERR_PTR(-ENOMEM);

	/* struct clk_divider assignments */
	div->reg = reg;
	div->shift = shift;
	div->width = width;
	div->flags = clk_divider_flags;
	div->table = table;
#if IS_ENABLED(CONFIG_SANDBOX_CLK_CCF)
	div->io_divider_val = *(u32 *)reg;
#endif

	/* register the clock */
	clk = &div->clk;
	clk->flags = flags;

	ret = clk_register(clk, UBOOT_DM_CLK_CCF_DIVIDER, name, parent_name);
	if (ret) {
		kfree(div);
		return ERR_PTR(ret);
	}

	return clk;
}

struct clk *clk_register_divider(struct device *dev, const char *name,
		const char *parent_name, unsigned long flags,
		void __iomem *reg, u8 shift, u8 width,
		u8 clk_divider_flags)
{
	struct clk *clk;

	clk =  _register_divider(dev, name, parent_name, flags, reg, shift,
				 width, clk_divider_flags, NULL);
	if (IS_ERR(clk))
		return ERR_CAST(clk);
	return clk;
}

U_BOOT_DRIVER(ccf_clk_divider) = {
	.name	= UBOOT_DM_CLK_CCF_DIVIDER,
	.id	= UCLASS_CLK,
	.ops	= &clk_divider_ops,
	.flags = DM_FLAG_PRE_RELOC,
};
