// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2016 Free Electrons
 * Copyright (C) 2016 NextThing Co
 *
 * Maxime Ripard <maxime.ripard@free-electrons.com>
 */

#include <linux/clk-provider.h>
#include <linux/regmap.h>

#include "sun4i_hdmi.h"

struct sun4i_ddc {
	struct clk_hw		hw;
	struct sun4i_hdmi	*hdmi;
	struct regmap_field	*reg;
	u8			pre_div;
	u8			m_offset;
};

static inline struct sun4i_ddc *hw_to_ddc(struct clk_hw *hw)
{
	return container_of(hw, struct sun4i_ddc, hw);
}

static unsigned long sun4i_ddc_calc_divider(unsigned long rate,
					    unsigned long parent_rate,
					    const u8 pre_div,
					    const u8 m_offset,
					    u8 *m, u8 *n)
{
	unsigned long best_rate = 0;
	u8 best_m = 0, best_n = 0, _m, _n;

	for (_m = 0; _m < 16; _m++) {
		for (_n = 0; _n < 8; _n++) {
			unsigned long tmp_rate;

			tmp_rate = (((parent_rate / pre_div) / 10) >> _n) /
				(_m + m_offset);

			if (tmp_rate > rate)
				continue;

			if (abs(rate - tmp_rate) < abs(rate - best_rate)) {
				best_rate = tmp_rate;
				best_m = _m;
				best_n = _n;
			}
		}
	}

	if (m && n) {
		*m = best_m;
		*n = best_n;
	}

	return best_rate;
}

static long sun4i_ddc_round_rate(struct clk_hw *hw, unsigned long rate,
				 unsigned long *prate)
{
	struct sun4i_ddc *ddc = hw_to_ddc(hw);

	return sun4i_ddc_calc_divider(rate, *prate, ddc->pre_div,
				      ddc->m_offset, NULL, NULL);
}

static unsigned long sun4i_ddc_recalc_rate(struct clk_hw *hw,
					    unsigned long parent_rate)
{
	struct sun4i_ddc *ddc = hw_to_ddc(hw);
	unsigned int reg;
	u8 m, n;

	regmap_field_read(ddc->reg, &reg);
	m = (reg >> 3) & 0xf;
	n = reg & 0x7;

	return (((parent_rate / ddc->pre_div) / 10) >> n) /
	       (m + ddc->m_offset);
}

static int sun4i_ddc_set_rate(struct clk_hw *hw, unsigned long rate,
			      unsigned long parent_rate)
{
	struct sun4i_ddc *ddc = hw_to_ddc(hw);
	u8 div_m, div_n;

	sun4i_ddc_calc_divider(rate, parent_rate, ddc->pre_div,
			       ddc->m_offset, &div_m, &div_n);

	regmap_field_write(ddc->reg,
			   SUN4I_HDMI_DDC_CLK_M(div_m) |
			   SUN4I_HDMI_DDC_CLK_N(div_n));

	return 0;
}

static const struct clk_ops sun4i_ddc_ops = {
	.recalc_rate	= sun4i_ddc_recalc_rate,
	.round_rate	= sun4i_ddc_round_rate,
	.set_rate	= sun4i_ddc_set_rate,
};

int sun4i_ddc_create(struct sun4i_hdmi *hdmi, struct clk *parent)
{
	struct clk_init_data init;
	struct sun4i_ddc *ddc;
	const char *parent_name;

	parent_name = __clk_get_name(parent);
	if (!parent_name)
		return -ENODEV;

	ddc = devm_kzalloc(hdmi->dev, sizeof(*ddc), GFP_KERNEL);
	if (!ddc)
		return -ENOMEM;

	ddc->reg = devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
					   hdmi->variant->ddc_clk_reg);
	if (IS_ERR(ddc->reg))
		return PTR_ERR(ddc->reg);

	init.name = "hdmi-ddc";
	init.ops = &sun4i_ddc_ops;
	init.parent_names = &parent_name;
	init.num_parents = 1;

	ddc->hdmi = hdmi;
	ddc->hw.init = &init;
	ddc->pre_div = hdmi->variant->ddc_clk_pre_divider;
	ddc->m_offset = hdmi->variant->ddc_clk_m_offset;

	hdmi->ddc_clk = devm_clk_register(hdmi->dev, &ddc->hw);
	if (IS_ERR(hdmi->ddc_clk))
		return PTR_ERR(hdmi->ddc_clk);

	return 0;
}
