xref: /openbmc/linux/drivers/clk/clk-versaclock7.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
148c5e98fSAlex Helms // SPDX-License-Identifier: GPL-2.0
248c5e98fSAlex Helms /*
348c5e98fSAlex Helms  * Common clock framework driver for the Versaclock7 family of timing devices.
448c5e98fSAlex Helms  *
548c5e98fSAlex Helms  * Copyright (c) 2022 Renesas Electronics Corporation
648c5e98fSAlex Helms  */
748c5e98fSAlex Helms 
848c5e98fSAlex Helms #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
948c5e98fSAlex Helms 
1048c5e98fSAlex Helms #include <linux/bitfield.h>
1148c5e98fSAlex Helms #include <linux/clk.h>
1248c5e98fSAlex Helms #include <linux/clk-provider.h>
1348c5e98fSAlex Helms #include <linux/i2c.h>
1448c5e98fSAlex Helms #include <linux/math64.h>
1548c5e98fSAlex Helms #include <linux/module.h>
1648c5e98fSAlex Helms #include <linux/of.h>
17893911e6SMarek Vasut #include <linux/property.h>
1848c5e98fSAlex Helms #include <linux/regmap.h>
1948c5e98fSAlex Helms #include <linux/swab.h>
2048c5e98fSAlex Helms 
2148c5e98fSAlex Helms /*
2248c5e98fSAlex Helms  * 16-bit register address: the lower 8 bits of the register address come
2348c5e98fSAlex Helms  * from the offset addr byte and the upper 8 bits come from the page register.
2448c5e98fSAlex Helms  */
2548c5e98fSAlex Helms #define VC7_PAGE_ADDR			0xFD
2648c5e98fSAlex Helms #define VC7_PAGE_WINDOW			256
2748c5e98fSAlex Helms #define VC7_MAX_REG			0x364
2848c5e98fSAlex Helms 
2948c5e98fSAlex Helms /* Maximum number of banks supported by VC7 */
3048c5e98fSAlex Helms #define VC7_NUM_BANKS			7
3148c5e98fSAlex Helms 
3248c5e98fSAlex Helms /* Maximum number of FODs supported by VC7 */
3348c5e98fSAlex Helms #define VC7_NUM_FOD			3
3448c5e98fSAlex Helms 
3548c5e98fSAlex Helms /* Maximum number of IODs supported by VC7 */
3648c5e98fSAlex Helms #define VC7_NUM_IOD			4
3748c5e98fSAlex Helms 
3848c5e98fSAlex Helms /* Maximum number of outputs supported by VC7 */
3948c5e98fSAlex Helms #define VC7_NUM_OUT			12
4048c5e98fSAlex Helms 
4148c5e98fSAlex Helms /* VCO valid range is 9.5 GHz to 10.7 GHz */
4248c5e98fSAlex Helms #define VC7_APLL_VCO_MIN		9500000000UL
4348c5e98fSAlex Helms #define VC7_APLL_VCO_MAX		10700000000UL
4448c5e98fSAlex Helms 
4548c5e98fSAlex Helms /* APLL denominator is fixed at 2^27 */
4648c5e98fSAlex Helms #define VC7_APLL_DENOMINATOR_BITS	27
4748c5e98fSAlex Helms 
4848c5e98fSAlex Helms /* FOD 1st stage denominator is fixed 2^34 */
4948c5e98fSAlex Helms #define VC7_FOD_DENOMINATOR_BITS	34
5048c5e98fSAlex Helms 
5148c5e98fSAlex Helms /* IOD can operate between 1kHz and 650MHz */
5248c5e98fSAlex Helms #define VC7_IOD_RATE_MIN		1000UL
5348c5e98fSAlex Helms #define VC7_IOD_RATE_MAX		650000000UL
5448c5e98fSAlex Helms #define VC7_IOD_MIN_DIVISOR		14
5548c5e98fSAlex Helms #define VC7_IOD_MAX_DIVISOR		0x1ffffff /* 25-bit */
5648c5e98fSAlex Helms 
5748c5e98fSAlex Helms #define VC7_FOD_RATE_MIN		1000UL
5848c5e98fSAlex Helms #define VC7_FOD_RATE_MAX		650000000UL
5948c5e98fSAlex Helms #define VC7_FOD_1ST_STAGE_RATE_MIN	33000000UL /* 33 MHz */
6048c5e98fSAlex Helms #define VC7_FOD_1ST_STAGE_RATE_MAX	650000000UL /* 650 MHz */
6148c5e98fSAlex Helms #define VC7_FOD_1ST_INT_MAX		324
6248c5e98fSAlex Helms #define VC7_FOD_2ND_INT_MIN		2
6348c5e98fSAlex Helms #define VC7_FOD_2ND_INT_MAX		0x1ffff /* 17-bit */
6448c5e98fSAlex Helms 
6548c5e98fSAlex Helms /* VC7 Registers */
6648c5e98fSAlex Helms 
6748c5e98fSAlex Helms #define VC7_REG_XO_CNFG			0x2C
6848c5e98fSAlex Helms #define VC7_REG_XO_CNFG_COUNT		4
6948c5e98fSAlex Helms #define VC7_REG_XO_IB_H_DIV_SHIFT	24
7048c5e98fSAlex Helms #define VC7_REG_XO_IB_H_DIV_MASK	GENMASK(28, VC7_REG_XO_IB_H_DIV_SHIFT)
7148c5e98fSAlex Helms 
7248c5e98fSAlex Helms #define VC7_REG_APLL_FB_DIV_FRAC	0x120
7348c5e98fSAlex Helms #define VC7_REG_APLL_FB_DIV_FRAC_COUNT	4
7448c5e98fSAlex Helms #define VC7_REG_APLL_FB_DIV_FRAC_MASK	GENMASK(26, 0)
7548c5e98fSAlex Helms 
7648c5e98fSAlex Helms #define VC7_REG_APLL_FB_DIV_INT		0x124
7748c5e98fSAlex Helms #define VC7_REG_APLL_FB_DIV_INT_COUNT	2
7848c5e98fSAlex Helms #define VC7_REG_APLL_FB_DIV_INT_MASK	GENMASK(9, 0)
7948c5e98fSAlex Helms 
8048c5e98fSAlex Helms #define VC7_REG_APLL_CNFG		0x127
8148c5e98fSAlex Helms #define VC7_REG_APLL_EN_DOUBLER		BIT(0)
8248c5e98fSAlex Helms 
8348c5e98fSAlex Helms #define VC7_REG_OUT_BANK_CNFG(idx)	(0x280 + (0x4 * (idx)))
8448c5e98fSAlex Helms #define VC7_REG_OUTPUT_BANK_SRC_MASK	GENMASK(2, 0)
8548c5e98fSAlex Helms 
8648c5e98fSAlex Helms #define VC7_REG_FOD_INT_CNFG(idx)	(0x1E0 + (0x10 * (idx)))
8748c5e98fSAlex Helms #define VC7_REG_FOD_INT_CNFG_COUNT	8
8848c5e98fSAlex Helms #define VC7_REG_FOD_1ST_INT_MASK	GENMASK(8, 0)
8948c5e98fSAlex Helms #define VC7_REG_FOD_2ND_INT_SHIFT	9
9048c5e98fSAlex Helms #define VC7_REG_FOD_2ND_INT_MASK	GENMASK(25, VC7_REG_FOD_2ND_INT_SHIFT)
9148c5e98fSAlex Helms #define VC7_REG_FOD_FRAC_SHIFT		26
9248c5e98fSAlex Helms #define VC7_REG_FOD_FRAC_MASK		GENMASK_ULL(59, VC7_REG_FOD_FRAC_SHIFT)
9348c5e98fSAlex Helms 
9448c5e98fSAlex Helms #define VC7_REG_IOD_INT_CNFG(idx)	(0x1C0 + (0x8 * (idx)))
9548c5e98fSAlex Helms #define VC7_REG_IOD_INT_CNFG_COUNT	4
9648c5e98fSAlex Helms #define VC7_REG_IOD_INT_MASK		GENMASK(24, 0)
9748c5e98fSAlex Helms 
9848c5e98fSAlex Helms #define VC7_REG_ODRV_EN(idx)		(0x240 + (0x4 * (idx)))
9948c5e98fSAlex Helms #define VC7_REG_OUT_DIS			BIT(0)
10048c5e98fSAlex Helms 
10148c5e98fSAlex Helms struct vc7_driver_data;
10248c5e98fSAlex Helms static const struct regmap_config vc7_regmap_config;
10348c5e98fSAlex Helms 
10448c5e98fSAlex Helms /* Supported Renesas VC7 models */
10548c5e98fSAlex Helms enum vc7_model {
10648c5e98fSAlex Helms 	VC7_RC21008A,
10748c5e98fSAlex Helms };
10848c5e98fSAlex Helms 
10948c5e98fSAlex Helms struct vc7_chip_info {
11048c5e98fSAlex Helms 	const enum vc7_model model;
11148c5e98fSAlex Helms 	const unsigned int banks[VC7_NUM_BANKS];
11248c5e98fSAlex Helms 	const unsigned int num_banks;
11348c5e98fSAlex Helms 	const unsigned int outputs[VC7_NUM_OUT];
11448c5e98fSAlex Helms 	const unsigned int num_outputs;
11548c5e98fSAlex Helms };
11648c5e98fSAlex Helms 
11748c5e98fSAlex Helms /*
11848c5e98fSAlex Helms  * Changing the APLL frequency is currently not supported.
11948c5e98fSAlex Helms  * The APLL will consist of an opaque block between the XO and FOD/IODs and
12048c5e98fSAlex Helms  * its frequency will be computed based on the current state of the device.
12148c5e98fSAlex Helms  */
12248c5e98fSAlex Helms struct vc7_apll_data {
12348c5e98fSAlex Helms 	struct clk *clk;
12448c5e98fSAlex Helms 	struct vc7_driver_data *vc7;
12548c5e98fSAlex Helms 	u8 xo_ib_h_div;
12648c5e98fSAlex Helms 	u8 en_doubler;
12748c5e98fSAlex Helms 	u16 apll_fb_div_int;
12848c5e98fSAlex Helms 	u32 apll_fb_div_frac;
12948c5e98fSAlex Helms };
13048c5e98fSAlex Helms 
13148c5e98fSAlex Helms struct vc7_fod_data {
13248c5e98fSAlex Helms 	struct clk_hw hw;
13348c5e98fSAlex Helms 	struct vc7_driver_data *vc7;
13448c5e98fSAlex Helms 	unsigned int num;
13548c5e98fSAlex Helms 	u32 fod_1st_int;
13648c5e98fSAlex Helms 	u32 fod_2nd_int;
13748c5e98fSAlex Helms 	u64 fod_frac;
13848c5e98fSAlex Helms };
13948c5e98fSAlex Helms 
14048c5e98fSAlex Helms struct vc7_iod_data {
14148c5e98fSAlex Helms 	struct clk_hw hw;
14248c5e98fSAlex Helms 	struct vc7_driver_data *vc7;
14348c5e98fSAlex Helms 	unsigned int num;
14448c5e98fSAlex Helms 	u32 iod_int;
14548c5e98fSAlex Helms };
14648c5e98fSAlex Helms 
14748c5e98fSAlex Helms struct vc7_out_data {
14848c5e98fSAlex Helms 	struct clk_hw hw;
14948c5e98fSAlex Helms 	struct vc7_driver_data *vc7;
15048c5e98fSAlex Helms 	unsigned int num;
15148c5e98fSAlex Helms 	unsigned int out_dis;
15248c5e98fSAlex Helms };
15348c5e98fSAlex Helms 
15448c5e98fSAlex Helms struct vc7_driver_data {
15548c5e98fSAlex Helms 	struct i2c_client *client;
15648c5e98fSAlex Helms 	struct regmap *regmap;
15748c5e98fSAlex Helms 	const struct vc7_chip_info *chip_info;
15848c5e98fSAlex Helms 
15948c5e98fSAlex Helms 	struct clk *pin_xin;
16048c5e98fSAlex Helms 	struct vc7_apll_data clk_apll;
16148c5e98fSAlex Helms 	struct vc7_fod_data clk_fod[VC7_NUM_FOD];
16248c5e98fSAlex Helms 	struct vc7_iod_data clk_iod[VC7_NUM_IOD];
16348c5e98fSAlex Helms 	struct vc7_out_data clk_out[VC7_NUM_OUT];
16448c5e98fSAlex Helms };
16548c5e98fSAlex Helms 
16648c5e98fSAlex Helms struct vc7_bank_src_map {
16748c5e98fSAlex Helms 	enum vc7_bank_src_type {
16848c5e98fSAlex Helms 		VC7_FOD,
16948c5e98fSAlex Helms 		VC7_IOD,
17048c5e98fSAlex Helms 	} type;
17148c5e98fSAlex Helms 	union _divider {
17248c5e98fSAlex Helms 		struct vc7_iod_data *iod;
17348c5e98fSAlex Helms 		struct vc7_fod_data *fod;
17448c5e98fSAlex Helms 	} src;
17548c5e98fSAlex Helms };
17648c5e98fSAlex Helms 
vc7_of_clk_get(struct of_phandle_args * clkspec,void * data)17748c5e98fSAlex Helms static struct clk_hw *vc7_of_clk_get(struct of_phandle_args *clkspec,
17848c5e98fSAlex Helms 				     void *data)
17948c5e98fSAlex Helms {
18048c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = data;
18148c5e98fSAlex Helms 	unsigned int idx = clkspec->args[0];
18248c5e98fSAlex Helms 
18348c5e98fSAlex Helms 	if (idx >= vc7->chip_info->num_outputs)
18448c5e98fSAlex Helms 		return ERR_PTR(-EINVAL);
18548c5e98fSAlex Helms 
18648c5e98fSAlex Helms 	return &vc7->clk_out[idx].hw;
18748c5e98fSAlex Helms }
18848c5e98fSAlex Helms 
18948c5e98fSAlex Helms static const unsigned int RC21008A_index_to_output_mapping[] = {
19048c5e98fSAlex Helms 	1, 2, 3, 6, 7, 8, 10, 11
19148c5e98fSAlex Helms };
19248c5e98fSAlex Helms 
vc7_map_index_to_output(const enum vc7_model model,const unsigned int i)19348c5e98fSAlex Helms static int vc7_map_index_to_output(const enum vc7_model model, const unsigned int i)
19448c5e98fSAlex Helms {
19548c5e98fSAlex Helms 	switch (model) {
19648c5e98fSAlex Helms 	case VC7_RC21008A:
19748c5e98fSAlex Helms 		return RC21008A_index_to_output_mapping[i];
19848c5e98fSAlex Helms 	default:
19948c5e98fSAlex Helms 		return i;
20048c5e98fSAlex Helms 	}
20148c5e98fSAlex Helms }
20248c5e98fSAlex Helms 
20348c5e98fSAlex Helms /* bank to output mapping, same across all variants */
20448c5e98fSAlex Helms static const unsigned int output_bank_mapping[] = {
20548c5e98fSAlex Helms 	0, /* Output 0 */
20648c5e98fSAlex Helms 	1, /* Output 1 */
20748c5e98fSAlex Helms 	2, /* Output 2 */
20848c5e98fSAlex Helms 	2, /* Output 3 */
20948c5e98fSAlex Helms 	3, /* Output 4 */
21048c5e98fSAlex Helms 	3, /* Output 5 */
21148c5e98fSAlex Helms 	3, /* Output 6 */
21248c5e98fSAlex Helms 	3, /* Output 7 */
21348c5e98fSAlex Helms 	4, /* Output 8 */
21448c5e98fSAlex Helms 	4, /* Output 9 */
21548c5e98fSAlex Helms 	5, /* Output 10 */
21648c5e98fSAlex Helms 	6  /* Output 11 */
21748c5e98fSAlex Helms };
21848c5e98fSAlex Helms 
21948c5e98fSAlex Helms /**
22048c5e98fSAlex Helms  * vc7_64_mul_64_to_128() - Multiply two u64 and return an unsigned 128-bit integer
22148c5e98fSAlex Helms  * as an upper and lower part.
22248c5e98fSAlex Helms  *
22348c5e98fSAlex Helms  * @left: The left argument.
22448c5e98fSAlex Helms  * @right: The right argument.
22548c5e98fSAlex Helms  * @hi: The upper 64-bits of the 128-bit product.
22648c5e98fSAlex Helms  * @lo: The lower 64-bits of the 128-bit product.
22748c5e98fSAlex Helms  *
22848c5e98fSAlex Helms  * From mul_64_64 in crypto/ecc.c:350 in the linux kernel, accessed in v5.17.2.
22948c5e98fSAlex Helms  */
vc7_64_mul_64_to_128(u64 left,u64 right,u64 * hi,u64 * lo)23048c5e98fSAlex Helms static void vc7_64_mul_64_to_128(u64 left, u64 right, u64 *hi, u64 *lo)
23148c5e98fSAlex Helms {
23248c5e98fSAlex Helms 	u64 a0 = left & 0xffffffffull;
23348c5e98fSAlex Helms 	u64 a1 = left >> 32;
23448c5e98fSAlex Helms 	u64 b0 = right & 0xffffffffull;
23548c5e98fSAlex Helms 	u64 b1 = right >> 32;
23648c5e98fSAlex Helms 	u64 m0 = a0 * b0;
23748c5e98fSAlex Helms 	u64 m1 = a0 * b1;
23848c5e98fSAlex Helms 	u64 m2 = a1 * b0;
23948c5e98fSAlex Helms 	u64 m3 = a1 * b1;
24048c5e98fSAlex Helms 
24148c5e98fSAlex Helms 	m2 += (m0 >> 32);
24248c5e98fSAlex Helms 	m2 += m1;
24348c5e98fSAlex Helms 
24448c5e98fSAlex Helms 	/* Overflow */
24548c5e98fSAlex Helms 	if (m2 < m1)
24648c5e98fSAlex Helms 		m3 += 0x100000000ull;
24748c5e98fSAlex Helms 
24848c5e98fSAlex Helms 	*lo = (m0 & 0xffffffffull) | (m2 << 32);
24948c5e98fSAlex Helms 	*hi = m3 + (m2 >> 32);
25048c5e98fSAlex Helms }
25148c5e98fSAlex Helms 
25248c5e98fSAlex Helms /**
25348c5e98fSAlex Helms  * vc7_128_div_64_to_64() - Divides a 128-bit uint by a 64-bit divisor, return a 64-bit quotient.
25448c5e98fSAlex Helms  *
25548c5e98fSAlex Helms  * @numhi: The uppper 64-bits of the dividend.
25648c5e98fSAlex Helms  * @numlo: The lower 64-bits of the dividend.
25748c5e98fSAlex Helms  * @den: The denominator (divisor).
25848c5e98fSAlex Helms  * @r: The remainder, pass NULL if the remainder is not needed.
25948c5e98fSAlex Helms  *
26048c5e98fSAlex Helms  * Originally from libdivide, modified to use kernel u64/u32 types.
26148c5e98fSAlex Helms  *
26248c5e98fSAlex Helms  * See https://github.com/ridiculousfish/libdivide/blob/master/libdivide.h#L471.
26348c5e98fSAlex Helms  *
26448c5e98fSAlex Helms  * Return: The 64-bit quotient of the division.
26548c5e98fSAlex Helms  *
26648c5e98fSAlex Helms  * In case of overflow of division by zero, max(u64) is returned.
26748c5e98fSAlex Helms  */
vc7_128_div_64_to_64(u64 numhi,u64 numlo,u64 den,u64 * r)26848c5e98fSAlex Helms static u64 vc7_128_div_64_to_64(u64 numhi, u64 numlo, u64 den, u64 *r)
26948c5e98fSAlex Helms {
27048c5e98fSAlex Helms 	/*
27148c5e98fSAlex Helms 	 * We work in base 2**32.
27248c5e98fSAlex Helms 	 * A uint32 holds a single digit. A uint64 holds two digits.
27348c5e98fSAlex Helms 	 * Our numerator is conceptually [num3, num2, num1, num0].
27448c5e98fSAlex Helms 	 * Our denominator is [den1, den0].
27548c5e98fSAlex Helms 	 */
27648c5e98fSAlex Helms 	const u64 b = ((u64)1 << 32);
27748c5e98fSAlex Helms 
27848c5e98fSAlex Helms 	/* The high and low digits of our computed quotient. */
27948c5e98fSAlex Helms 	u32 q1, q0;
28048c5e98fSAlex Helms 
28148c5e98fSAlex Helms 	/* The normalization shift factor */
28248c5e98fSAlex Helms 	int shift;
28348c5e98fSAlex Helms 
28448c5e98fSAlex Helms 	/*
28548c5e98fSAlex Helms 	 * The high and low digits of our denominator (after normalizing).
28648c5e98fSAlex Helms 	 * Also the low 2 digits of our numerator (after normalizing).
28748c5e98fSAlex Helms 	 */
28848c5e98fSAlex Helms 	u32 den1, den0, num1, num0;
28948c5e98fSAlex Helms 
29048c5e98fSAlex Helms 	/* A partial remainder; */
29148c5e98fSAlex Helms 	u64 rem;
29248c5e98fSAlex Helms 
29348c5e98fSAlex Helms 	/*
29448c5e98fSAlex Helms 	 * The estimated quotient, and its corresponding remainder (unrelated
29548c5e98fSAlex Helms 	 * to true remainder).
29648c5e98fSAlex Helms 	 */
29748c5e98fSAlex Helms 	u64 qhat, rhat;
29848c5e98fSAlex Helms 
29948c5e98fSAlex Helms 	/* Variables used to correct the estimated quotient. */
30048c5e98fSAlex Helms 	u64 c1, c2;
30148c5e98fSAlex Helms 
30248c5e98fSAlex Helms 	/* Check for overflow and divide by 0. */
30348c5e98fSAlex Helms 	if (numhi >= den) {
30448c5e98fSAlex Helms 		if (r)
30548c5e98fSAlex Helms 			*r = ~0ull;
30648c5e98fSAlex Helms 		return ~0ull;
30748c5e98fSAlex Helms 	}
30848c5e98fSAlex Helms 
30948c5e98fSAlex Helms 	/*
31048c5e98fSAlex Helms 	 * Determine the normalization factor. We multiply den by this, so that
31148c5e98fSAlex Helms 	 * its leading digit is at least half b. In binary this means just
31248c5e98fSAlex Helms 	 * shifting left by the number of leading zeros, so that there's a 1 in
31348c5e98fSAlex Helms 	 * the MSB.
31448c5e98fSAlex Helms 	 *
31548c5e98fSAlex Helms 	 * We also shift numer by the same amount. This cannot overflow because
31648c5e98fSAlex Helms 	 * numhi < den.  The expression (-shift & 63) is the same as (64 -
31748c5e98fSAlex Helms 	 * shift), except it avoids the UB of shifting by 64. The funny bitwise
31848c5e98fSAlex Helms 	 * 'and' ensures that numlo does not get shifted into numhi if shift is
31948c5e98fSAlex Helms 	 * 0. clang 11 has an x86 codegen bug here: see LLVM bug 50118. The
32048c5e98fSAlex Helms 	 * sequence below avoids it.
32148c5e98fSAlex Helms 	 */
32248c5e98fSAlex Helms 	shift = __builtin_clzll(den);
32348c5e98fSAlex Helms 	den <<= shift;
32448c5e98fSAlex Helms 	numhi <<= shift;
32548c5e98fSAlex Helms 	numhi |= (numlo >> (-shift & 63)) & (-(s64)shift >> 63);
32648c5e98fSAlex Helms 	numlo <<= shift;
32748c5e98fSAlex Helms 
32848c5e98fSAlex Helms 	/*
32948c5e98fSAlex Helms 	 * Extract the low digits of the numerator and both digits of the
33048c5e98fSAlex Helms 	 * denominator.
33148c5e98fSAlex Helms 	 */
33248c5e98fSAlex Helms 	num1 = (u32)(numlo >> 32);
33348c5e98fSAlex Helms 	num0 = (u32)(numlo & 0xFFFFFFFFu);
33448c5e98fSAlex Helms 	den1 = (u32)(den >> 32);
33548c5e98fSAlex Helms 	den0 = (u32)(den & 0xFFFFFFFFu);
33648c5e98fSAlex Helms 
33748c5e98fSAlex Helms 	/*
33848c5e98fSAlex Helms 	 * We wish to compute q1 = [n3 n2 n1] / [d1 d0].
33948c5e98fSAlex Helms 	 * Estimate q1 as [n3 n2] / [d1], and then correct it.
34048c5e98fSAlex Helms 	 * Note while qhat may be 2 digits, q1 is always 1 digit.
34148c5e98fSAlex Helms 	 */
34248c5e98fSAlex Helms 	qhat = div64_u64_rem(numhi, den1, &rhat);
34348c5e98fSAlex Helms 	c1 = qhat * den0;
34448c5e98fSAlex Helms 	c2 = rhat * b + num1;
34548c5e98fSAlex Helms 	if (c1 > c2)
34648c5e98fSAlex Helms 		qhat -= (c1 - c2 > den) ? 2 : 1;
34748c5e98fSAlex Helms 	q1 = (u32)qhat;
34848c5e98fSAlex Helms 
34948c5e98fSAlex Helms 	/* Compute the true (partial) remainder. */
35048c5e98fSAlex Helms 	rem = numhi * b + num1 - q1 * den;
35148c5e98fSAlex Helms 
35248c5e98fSAlex Helms 	/*
35348c5e98fSAlex Helms 	 * We wish to compute q0 = [rem1 rem0 n0] / [d1 d0].
35448c5e98fSAlex Helms 	 * Estimate q0 as [rem1 rem0] / [d1] and correct it.
35548c5e98fSAlex Helms 	 */
35648c5e98fSAlex Helms 	qhat = div64_u64_rem(rem, den1, &rhat);
35748c5e98fSAlex Helms 	c1 = qhat * den0;
35848c5e98fSAlex Helms 	c2 = rhat * b + num0;
35948c5e98fSAlex Helms 	if (c1 > c2)
36048c5e98fSAlex Helms 		qhat -= (c1 - c2 > den) ? 2 : 1;
36148c5e98fSAlex Helms 	q0 = (u32)qhat;
36248c5e98fSAlex Helms 
36348c5e98fSAlex Helms 	/* Return remainder if requested. */
36448c5e98fSAlex Helms 	if (r)
36548c5e98fSAlex Helms 		*r = (rem * b + num0 - q0 * den) >> shift;
36648c5e98fSAlex Helms 	return ((u64)q1 << 32) | q0;
36748c5e98fSAlex Helms }
36848c5e98fSAlex Helms 
vc7_get_bank_clk(struct vc7_driver_data * vc7,unsigned int bank_idx,unsigned int output_bank_src,struct vc7_bank_src_map * map)36948c5e98fSAlex Helms static int vc7_get_bank_clk(struct vc7_driver_data *vc7,
37048c5e98fSAlex Helms 			    unsigned int bank_idx,
37148c5e98fSAlex Helms 			    unsigned int output_bank_src,
37248c5e98fSAlex Helms 			    struct vc7_bank_src_map *map)
37348c5e98fSAlex Helms {
37448c5e98fSAlex Helms 	/* Mapping from Table 38 in datasheet */
37548c5e98fSAlex Helms 	if (bank_idx == 0 || bank_idx == 1) {
37648c5e98fSAlex Helms 		switch (output_bank_src) {
37748c5e98fSAlex Helms 		case 0:
37848c5e98fSAlex Helms 			map->type = VC7_IOD,
37948c5e98fSAlex Helms 			map->src.iod = &vc7->clk_iod[0];
38048c5e98fSAlex Helms 			return 0;
38148c5e98fSAlex Helms 		case 1:
38248c5e98fSAlex Helms 			map->type = VC7_IOD,
38348c5e98fSAlex Helms 			map->src.iod = &vc7->clk_iod[1];
38448c5e98fSAlex Helms 			return 0;
38548c5e98fSAlex Helms 		case 4:
38648c5e98fSAlex Helms 			map->type = VC7_FOD,
38748c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[0];
38848c5e98fSAlex Helms 			return 0;
38948c5e98fSAlex Helms 		case 5:
39048c5e98fSAlex Helms 			map->type = VC7_FOD,
39148c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[1];
39248c5e98fSAlex Helms 			return 0;
39348c5e98fSAlex Helms 		default:
39448c5e98fSAlex Helms 			break;
39548c5e98fSAlex Helms 		}
39648c5e98fSAlex Helms 	} else if (bank_idx == 2) {
39748c5e98fSAlex Helms 		switch (output_bank_src) {
39848c5e98fSAlex Helms 		case 1:
39948c5e98fSAlex Helms 			map->type = VC7_IOD,
40048c5e98fSAlex Helms 			map->src.iod = &vc7->clk_iod[1];
40148c5e98fSAlex Helms 			return 0;
40248c5e98fSAlex Helms 		case 4:
40348c5e98fSAlex Helms 			map->type = VC7_FOD,
40448c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[0];
40548c5e98fSAlex Helms 			return 0;
40648c5e98fSAlex Helms 		case 5:
40748c5e98fSAlex Helms 			map->type = VC7_FOD,
40848c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[1];
40948c5e98fSAlex Helms 			return 0;
41048c5e98fSAlex Helms 		default:
41148c5e98fSAlex Helms 			break;
41248c5e98fSAlex Helms 		}
41348c5e98fSAlex Helms 	} else if (bank_idx == 3) {
41448c5e98fSAlex Helms 		switch (output_bank_src) {
41548c5e98fSAlex Helms 		case 4:
41648c5e98fSAlex Helms 			map->type = VC7_FOD,
41748c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[0];
41848c5e98fSAlex Helms 			return 0;
41948c5e98fSAlex Helms 		case 5:
42048c5e98fSAlex Helms 			map->type = VC7_FOD,
42148c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[1];
42248c5e98fSAlex Helms 			return 0;
42348c5e98fSAlex Helms 		case 6:
42448c5e98fSAlex Helms 			map->type = VC7_FOD,
42548c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[2];
42648c5e98fSAlex Helms 			return 0;
42748c5e98fSAlex Helms 		default:
42848c5e98fSAlex Helms 			break;
42948c5e98fSAlex Helms 		}
43048c5e98fSAlex Helms 	} else if (bank_idx == 4) {
43148c5e98fSAlex Helms 		switch (output_bank_src) {
43248c5e98fSAlex Helms 		case 0:
43348c5e98fSAlex Helms 			/* CLKIN1 not supported in this driver */
43448c5e98fSAlex Helms 			break;
43548c5e98fSAlex Helms 		case 2:
43648c5e98fSAlex Helms 			map->type = VC7_IOD,
43748c5e98fSAlex Helms 			map->src.iod = &vc7->clk_iod[2];
43848c5e98fSAlex Helms 			return 0;
43948c5e98fSAlex Helms 		case 5:
44048c5e98fSAlex Helms 			map->type = VC7_FOD,
44148c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[1];
44248c5e98fSAlex Helms 			return 0;
44348c5e98fSAlex Helms 		case 6:
44448c5e98fSAlex Helms 			map->type = VC7_FOD,
44548c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[2];
44648c5e98fSAlex Helms 			return 0;
44748c5e98fSAlex Helms 		case 7:
44848c5e98fSAlex Helms 			/* CLKIN0 not supported in this driver */
44948c5e98fSAlex Helms 			break;
45048c5e98fSAlex Helms 		default:
45148c5e98fSAlex Helms 			break;
45248c5e98fSAlex Helms 		}
45348c5e98fSAlex Helms 	} else if (bank_idx == 5) {
45448c5e98fSAlex Helms 		switch (output_bank_src) {
45548c5e98fSAlex Helms 		case 0:
45648c5e98fSAlex Helms 			/* CLKIN1 not supported in this driver */
45748c5e98fSAlex Helms 			break;
45848c5e98fSAlex Helms 		case 1:
45948c5e98fSAlex Helms 			/* XIN_REFIN not supported in this driver */
46048c5e98fSAlex Helms 			break;
46148c5e98fSAlex Helms 		case 2:
46248c5e98fSAlex Helms 			map->type = VC7_IOD,
46348c5e98fSAlex Helms 			map->src.iod = &vc7->clk_iod[2];
46448c5e98fSAlex Helms 			return 0;
46548c5e98fSAlex Helms 		case 3:
46648c5e98fSAlex Helms 			map->type = VC7_IOD,
46748c5e98fSAlex Helms 			map->src.iod = &vc7->clk_iod[3];
46848c5e98fSAlex Helms 			return 0;
46948c5e98fSAlex Helms 		case 5:
47048c5e98fSAlex Helms 			map->type = VC7_FOD,
47148c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[1];
47248c5e98fSAlex Helms 			return 0;
47348c5e98fSAlex Helms 		case 6:
47448c5e98fSAlex Helms 			map->type = VC7_FOD,
47548c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[2];
47648c5e98fSAlex Helms 			return 0;
47748c5e98fSAlex Helms 		case 7:
47848c5e98fSAlex Helms 			/* CLKIN0 not supported in this driver */
47948c5e98fSAlex Helms 			break;
48048c5e98fSAlex Helms 		default:
48148c5e98fSAlex Helms 			break;
48248c5e98fSAlex Helms 		}
48348c5e98fSAlex Helms 	} else if (bank_idx == 6) {
48448c5e98fSAlex Helms 		switch (output_bank_src) {
48548c5e98fSAlex Helms 		case 0:
48648c5e98fSAlex Helms 			/* CLKIN1 not supported in this driver */
48748c5e98fSAlex Helms 			break;
48848c5e98fSAlex Helms 		case 2:
48948c5e98fSAlex Helms 			map->type = VC7_IOD,
49048c5e98fSAlex Helms 			map->src.iod = &vc7->clk_iod[2];
49148c5e98fSAlex Helms 			return 0;
49248c5e98fSAlex Helms 		case 3:
49348c5e98fSAlex Helms 			map->type = VC7_IOD,
49448c5e98fSAlex Helms 			map->src.iod = &vc7->clk_iod[3];
49548c5e98fSAlex Helms 			return 0;
49648c5e98fSAlex Helms 		case 5:
49748c5e98fSAlex Helms 			map->type = VC7_FOD,
49848c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[1];
49948c5e98fSAlex Helms 			return 0;
50048c5e98fSAlex Helms 		case 6:
50148c5e98fSAlex Helms 			map->type = VC7_FOD,
50248c5e98fSAlex Helms 			map->src.fod = &vc7->clk_fod[2];
50348c5e98fSAlex Helms 			return 0;
50448c5e98fSAlex Helms 		case 7:
50548c5e98fSAlex Helms 			/* CLKIN0 not supported in this driver */
50648c5e98fSAlex Helms 			break;
50748c5e98fSAlex Helms 		default:
50848c5e98fSAlex Helms 			break;
50948c5e98fSAlex Helms 		}
51048c5e98fSAlex Helms 	}
51148c5e98fSAlex Helms 
51248c5e98fSAlex Helms 	pr_warn("bank_src%d = %d is not supported\n", bank_idx, output_bank_src);
51348c5e98fSAlex Helms 	return -1;
51448c5e98fSAlex Helms }
51548c5e98fSAlex Helms 
vc7_read_apll(struct vc7_driver_data * vc7)51648c5e98fSAlex Helms static int vc7_read_apll(struct vc7_driver_data *vc7)
51748c5e98fSAlex Helms {
51848c5e98fSAlex Helms 	int err;
51948c5e98fSAlex Helms 	u32 val32;
52048c5e98fSAlex Helms 	u16 val16;
52148c5e98fSAlex Helms 
52248c5e98fSAlex Helms 	err = regmap_bulk_read(vc7->regmap,
52348c5e98fSAlex Helms 			       VC7_REG_XO_CNFG,
52448c5e98fSAlex Helms 			       (u32 *)&val32,
52548c5e98fSAlex Helms 			       VC7_REG_XO_CNFG_COUNT);
52648c5e98fSAlex Helms 	if (err) {
52748c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read XO_CNFG\n");
52848c5e98fSAlex Helms 		return err;
52948c5e98fSAlex Helms 	}
53048c5e98fSAlex Helms 
53148c5e98fSAlex Helms 	vc7->clk_apll.xo_ib_h_div = (val32 & VC7_REG_XO_IB_H_DIV_MASK)
53248c5e98fSAlex Helms 		>> VC7_REG_XO_IB_H_DIV_SHIFT;
53348c5e98fSAlex Helms 
53448c5e98fSAlex Helms 	err = regmap_read(vc7->regmap,
53548c5e98fSAlex Helms 			  VC7_REG_APLL_CNFG,
53648c5e98fSAlex Helms 			  &val32);
53748c5e98fSAlex Helms 	if (err) {
53848c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read APLL_CNFG\n");
53948c5e98fSAlex Helms 		return err;
54048c5e98fSAlex Helms 	}
54148c5e98fSAlex Helms 
54248c5e98fSAlex Helms 	vc7->clk_apll.en_doubler = val32 & VC7_REG_APLL_EN_DOUBLER;
54348c5e98fSAlex Helms 
54448c5e98fSAlex Helms 	err = regmap_bulk_read(vc7->regmap,
54548c5e98fSAlex Helms 			       VC7_REG_APLL_FB_DIV_FRAC,
54648c5e98fSAlex Helms 			       (u32 *)&val32,
54748c5e98fSAlex Helms 			       VC7_REG_APLL_FB_DIV_FRAC_COUNT);
54848c5e98fSAlex Helms 	if (err) {
54948c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read APLL_FB_DIV_FRAC\n");
55048c5e98fSAlex Helms 		return err;
55148c5e98fSAlex Helms 	}
55248c5e98fSAlex Helms 
55348c5e98fSAlex Helms 	vc7->clk_apll.apll_fb_div_frac = val32 & VC7_REG_APLL_FB_DIV_FRAC_MASK;
55448c5e98fSAlex Helms 
55548c5e98fSAlex Helms 	err = regmap_bulk_read(vc7->regmap,
55648c5e98fSAlex Helms 			       VC7_REG_APLL_FB_DIV_INT,
55748c5e98fSAlex Helms 			       (u16 *)&val16,
55848c5e98fSAlex Helms 			       VC7_REG_APLL_FB_DIV_INT_COUNT);
55948c5e98fSAlex Helms 	if (err) {
56048c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read APLL_FB_DIV_INT\n");
56148c5e98fSAlex Helms 		return err;
56248c5e98fSAlex Helms 	}
56348c5e98fSAlex Helms 
56448c5e98fSAlex Helms 	vc7->clk_apll.apll_fb_div_int = val16 & VC7_REG_APLL_FB_DIV_INT_MASK;
56548c5e98fSAlex Helms 
56648c5e98fSAlex Helms 	return 0;
56748c5e98fSAlex Helms }
56848c5e98fSAlex Helms 
vc7_read_fod(struct vc7_driver_data * vc7,unsigned int idx)56948c5e98fSAlex Helms static int vc7_read_fod(struct vc7_driver_data *vc7, unsigned int idx)
57048c5e98fSAlex Helms {
57148c5e98fSAlex Helms 	int err;
57248c5e98fSAlex Helms 	u64 val;
57348c5e98fSAlex Helms 
57448c5e98fSAlex Helms 	err = regmap_bulk_read(vc7->regmap,
57548c5e98fSAlex Helms 			       VC7_REG_FOD_INT_CNFG(idx),
57648c5e98fSAlex Helms 			       (u64 *)&val,
57748c5e98fSAlex Helms 			       VC7_REG_FOD_INT_CNFG_COUNT);
57848c5e98fSAlex Helms 	if (err) {
57948c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read FOD%d\n", idx);
58048c5e98fSAlex Helms 		return err;
58148c5e98fSAlex Helms 	}
58248c5e98fSAlex Helms 
58348c5e98fSAlex Helms 	vc7->clk_fod[idx].fod_1st_int = (val & VC7_REG_FOD_1ST_INT_MASK);
58448c5e98fSAlex Helms 	vc7->clk_fod[idx].fod_2nd_int =
58548c5e98fSAlex Helms 	    (val & VC7_REG_FOD_2ND_INT_MASK) >> VC7_REG_FOD_2ND_INT_SHIFT;
58648c5e98fSAlex Helms 	vc7->clk_fod[idx].fod_frac = (val & VC7_REG_FOD_FRAC_MASK)
58748c5e98fSAlex Helms 		>> VC7_REG_FOD_FRAC_SHIFT;
58848c5e98fSAlex Helms 
58948c5e98fSAlex Helms 	return 0;
59048c5e98fSAlex Helms }
59148c5e98fSAlex Helms 
vc7_write_fod(struct vc7_driver_data * vc7,unsigned int idx)59248c5e98fSAlex Helms static int vc7_write_fod(struct vc7_driver_data *vc7, unsigned int idx)
59348c5e98fSAlex Helms {
59448c5e98fSAlex Helms 	int err;
59548c5e98fSAlex Helms 	u64 val;
59648c5e98fSAlex Helms 
59748c5e98fSAlex Helms 	/*
59848c5e98fSAlex Helms 	 * FOD dividers are part of an atomic group where fod_1st_int,
59948c5e98fSAlex Helms 	 * fod_2nd_int, and fod_frac must be written together. The new divider
60048c5e98fSAlex Helms 	 * is applied when the MSB of fod_frac is written.
60148c5e98fSAlex Helms 	 */
60248c5e98fSAlex Helms 
60348c5e98fSAlex Helms 	err = regmap_bulk_read(vc7->regmap,
60448c5e98fSAlex Helms 			       VC7_REG_FOD_INT_CNFG(idx),
60548c5e98fSAlex Helms 			       (u64 *)&val,
60648c5e98fSAlex Helms 			       VC7_REG_FOD_INT_CNFG_COUNT);
60748c5e98fSAlex Helms 	if (err) {
60848c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read FOD%d\n", idx);
60948c5e98fSAlex Helms 		return err;
61048c5e98fSAlex Helms 	}
61148c5e98fSAlex Helms 
61248c5e98fSAlex Helms 	val = u64_replace_bits(val,
61348c5e98fSAlex Helms 			       vc7->clk_fod[idx].fod_1st_int,
61448c5e98fSAlex Helms 			       VC7_REG_FOD_1ST_INT_MASK);
61548c5e98fSAlex Helms 	val = u64_replace_bits(val,
61648c5e98fSAlex Helms 			       vc7->clk_fod[idx].fod_2nd_int,
61748c5e98fSAlex Helms 			       VC7_REG_FOD_2ND_INT_MASK);
61848c5e98fSAlex Helms 	val = u64_replace_bits(val,
61948c5e98fSAlex Helms 			       vc7->clk_fod[idx].fod_frac,
62048c5e98fSAlex Helms 			       VC7_REG_FOD_FRAC_MASK);
62148c5e98fSAlex Helms 
62248c5e98fSAlex Helms 	err = regmap_bulk_write(vc7->regmap,
62348c5e98fSAlex Helms 				VC7_REG_FOD_INT_CNFG(idx),
62448c5e98fSAlex Helms 				(u64 *)&val,
62548c5e98fSAlex Helms 				sizeof(u64));
62648c5e98fSAlex Helms 	if (err) {
62748c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to write FOD%d\n", idx);
62848c5e98fSAlex Helms 		return err;
62948c5e98fSAlex Helms 	}
63048c5e98fSAlex Helms 
63148c5e98fSAlex Helms 	return 0;
63248c5e98fSAlex Helms }
63348c5e98fSAlex Helms 
vc7_read_iod(struct vc7_driver_data * vc7,unsigned int idx)63448c5e98fSAlex Helms static int vc7_read_iod(struct vc7_driver_data *vc7, unsigned int idx)
63548c5e98fSAlex Helms {
63648c5e98fSAlex Helms 	int err;
63748c5e98fSAlex Helms 	u32 val;
63848c5e98fSAlex Helms 
63948c5e98fSAlex Helms 	err = regmap_bulk_read(vc7->regmap,
64048c5e98fSAlex Helms 			       VC7_REG_IOD_INT_CNFG(idx),
64148c5e98fSAlex Helms 			       (u32 *)&val,
64248c5e98fSAlex Helms 			       VC7_REG_IOD_INT_CNFG_COUNT);
64348c5e98fSAlex Helms 	if (err) {
64448c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read IOD%d\n", idx);
64548c5e98fSAlex Helms 		return err;
64648c5e98fSAlex Helms 	}
64748c5e98fSAlex Helms 
64848c5e98fSAlex Helms 	vc7->clk_iod[idx].iod_int = (val & VC7_REG_IOD_INT_MASK);
64948c5e98fSAlex Helms 
65048c5e98fSAlex Helms 	return 0;
65148c5e98fSAlex Helms }
65248c5e98fSAlex Helms 
vc7_write_iod(struct vc7_driver_data * vc7,unsigned int idx)65348c5e98fSAlex Helms static int vc7_write_iod(struct vc7_driver_data *vc7, unsigned int idx)
65448c5e98fSAlex Helms {
65548c5e98fSAlex Helms 	int err;
65648c5e98fSAlex Helms 	u32 val;
65748c5e98fSAlex Helms 
65848c5e98fSAlex Helms 	/*
65948c5e98fSAlex Helms 	 * IOD divider field is atomic and all bits must be written.
66048c5e98fSAlex Helms 	 * The new divider is applied when the MSB of iod_int is written.
66148c5e98fSAlex Helms 	 */
66248c5e98fSAlex Helms 
66348c5e98fSAlex Helms 	err = regmap_bulk_read(vc7->regmap,
66448c5e98fSAlex Helms 			       VC7_REG_IOD_INT_CNFG(idx),
66548c5e98fSAlex Helms 			       (u32 *)&val,
66648c5e98fSAlex Helms 			       VC7_REG_IOD_INT_CNFG_COUNT);
66748c5e98fSAlex Helms 	if (err) {
66848c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read IOD%d\n", idx);
66948c5e98fSAlex Helms 		return err;
67048c5e98fSAlex Helms 	}
67148c5e98fSAlex Helms 
67248c5e98fSAlex Helms 	val = u32_replace_bits(val,
67348c5e98fSAlex Helms 			       vc7->clk_iod[idx].iod_int,
67448c5e98fSAlex Helms 			       VC7_REG_IOD_INT_MASK);
67548c5e98fSAlex Helms 
67648c5e98fSAlex Helms 	err = regmap_bulk_write(vc7->regmap,
67748c5e98fSAlex Helms 				VC7_REG_IOD_INT_CNFG(idx),
67848c5e98fSAlex Helms 				(u32 *)&val,
67948c5e98fSAlex Helms 				sizeof(u32));
68048c5e98fSAlex Helms 	if (err) {
68148c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to write IOD%d\n", idx);
68248c5e98fSAlex Helms 		return err;
68348c5e98fSAlex Helms 	}
68448c5e98fSAlex Helms 
68548c5e98fSAlex Helms 	return 0;
68648c5e98fSAlex Helms }
68748c5e98fSAlex Helms 
vc7_read_output(struct vc7_driver_data * vc7,unsigned int idx)68848c5e98fSAlex Helms static int vc7_read_output(struct vc7_driver_data *vc7, unsigned int idx)
68948c5e98fSAlex Helms {
69048c5e98fSAlex Helms 	int err;
69148c5e98fSAlex Helms 	unsigned int val, out_num;
69248c5e98fSAlex Helms 
69348c5e98fSAlex Helms 	out_num = vc7_map_index_to_output(vc7->chip_info->model, idx);
69448c5e98fSAlex Helms 	err = regmap_read(vc7->regmap,
69548c5e98fSAlex Helms 			  VC7_REG_ODRV_EN(out_num),
69648c5e98fSAlex Helms 			  &val);
69748c5e98fSAlex Helms 	if (err) {
69848c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to read ODRV_EN[%d]\n", idx);
69948c5e98fSAlex Helms 		return err;
70048c5e98fSAlex Helms 	}
70148c5e98fSAlex Helms 
70248c5e98fSAlex Helms 	vc7->clk_out[idx].out_dis = val & VC7_REG_OUT_DIS;
70348c5e98fSAlex Helms 
70448c5e98fSAlex Helms 	return 0;
70548c5e98fSAlex Helms }
70648c5e98fSAlex Helms 
vc7_write_output(struct vc7_driver_data * vc7,unsigned int idx)70748c5e98fSAlex Helms static int vc7_write_output(struct vc7_driver_data *vc7, unsigned int idx)
70848c5e98fSAlex Helms {
70948c5e98fSAlex Helms 	int err;
71048c5e98fSAlex Helms 	unsigned int out_num;
71148c5e98fSAlex Helms 
71248c5e98fSAlex Helms 	out_num = vc7_map_index_to_output(vc7->chip_info->model, idx);
71348c5e98fSAlex Helms 	err = regmap_write_bits(vc7->regmap,
71448c5e98fSAlex Helms 				VC7_REG_ODRV_EN(out_num),
71548c5e98fSAlex Helms 				VC7_REG_OUT_DIS,
71648c5e98fSAlex Helms 				vc7->clk_out[idx].out_dis);
71748c5e98fSAlex Helms 
71848c5e98fSAlex Helms 	if (err) {
71948c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "failed to write ODRV_EN[%d]\n", idx);
72048c5e98fSAlex Helms 		return err;
72148c5e98fSAlex Helms 	}
72248c5e98fSAlex Helms 
72348c5e98fSAlex Helms 	return 0;
72448c5e98fSAlex Helms }
72548c5e98fSAlex Helms 
vc7_get_apll_rate(struct vc7_driver_data * vc7)72648c5e98fSAlex Helms static unsigned long vc7_get_apll_rate(struct vc7_driver_data *vc7)
72748c5e98fSAlex Helms {
72848c5e98fSAlex Helms 	int err;
72948c5e98fSAlex Helms 	unsigned long xtal_rate;
73048c5e98fSAlex Helms 	u64 refin_div, apll_rate;
73148c5e98fSAlex Helms 
73248c5e98fSAlex Helms 	xtal_rate = clk_get_rate(vc7->pin_xin);
73348c5e98fSAlex Helms 	err = vc7_read_apll(vc7);
73448c5e98fSAlex Helms 	if (err) {
73548c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "unable to read apll\n");
73648c5e98fSAlex Helms 		return err;
73748c5e98fSAlex Helms 	}
73848c5e98fSAlex Helms 
73948c5e98fSAlex Helms 	/* 0 is bypassed, 1 is reserved */
74048c5e98fSAlex Helms 	if (vc7->clk_apll.xo_ib_h_div < 2)
74148c5e98fSAlex Helms 		refin_div = xtal_rate;
74248c5e98fSAlex Helms 	else
74348c5e98fSAlex Helms 		refin_div = div64_u64(xtal_rate, vc7->clk_apll.xo_ib_h_div);
74448c5e98fSAlex Helms 
74548c5e98fSAlex Helms 	if (vc7->clk_apll.en_doubler)
74648c5e98fSAlex Helms 		refin_div *= 2;
74748c5e98fSAlex Helms 
74848c5e98fSAlex Helms 	/* divider = int + (frac / 2^27) */
74948c5e98fSAlex Helms 	apll_rate = (refin_div * vc7->clk_apll.apll_fb_div_int) +
75048c5e98fSAlex Helms 		    ((refin_div * vc7->clk_apll.apll_fb_div_frac) >> VC7_APLL_DENOMINATOR_BITS);
75148c5e98fSAlex Helms 
75248c5e98fSAlex Helms 	pr_debug("%s - xo_ib_h_div: %u, apll_fb_div_int: %u, apll_fb_div_frac: %u\n",
75348c5e98fSAlex Helms 		 __func__, vc7->clk_apll.xo_ib_h_div, vc7->clk_apll.apll_fb_div_int,
75448c5e98fSAlex Helms 		 vc7->clk_apll.apll_fb_div_frac);
75548c5e98fSAlex Helms 	pr_debug("%s - refin_div: %llu, apll rate: %llu\n",
75648c5e98fSAlex Helms 		 __func__, refin_div, apll_rate);
75748c5e98fSAlex Helms 
75848c5e98fSAlex Helms 	return apll_rate;
75948c5e98fSAlex Helms }
76048c5e98fSAlex Helms 
vc7_calc_iod_divider(unsigned long rate,unsigned long parent_rate,u32 * divider)76148c5e98fSAlex Helms static void vc7_calc_iod_divider(unsigned long rate, unsigned long parent_rate,
76248c5e98fSAlex Helms 				 u32 *divider)
76348c5e98fSAlex Helms {
76448c5e98fSAlex Helms 	*divider = DIV_ROUND_UP(parent_rate, rate);
76548c5e98fSAlex Helms 	if (*divider < VC7_IOD_MIN_DIVISOR)
76648c5e98fSAlex Helms 		*divider = VC7_IOD_MIN_DIVISOR;
76748c5e98fSAlex Helms 	if (*divider > VC7_IOD_MAX_DIVISOR)
76848c5e98fSAlex Helms 		*divider = VC7_IOD_MAX_DIVISOR;
76948c5e98fSAlex Helms }
77048c5e98fSAlex Helms 
vc7_calc_fod_1st_stage(unsigned long rate,unsigned long parent_rate,u32 * div_int,u64 * div_frac)77148c5e98fSAlex Helms static void vc7_calc_fod_1st_stage(unsigned long rate, unsigned long parent_rate,
77248c5e98fSAlex Helms 				   u32 *div_int, u64 *div_frac)
77348c5e98fSAlex Helms {
77448c5e98fSAlex Helms 	u64 rem;
77548c5e98fSAlex Helms 
77648c5e98fSAlex Helms 	*div_int = (u32)div64_u64_rem(parent_rate, rate, &rem);
77748c5e98fSAlex Helms 	*div_frac = div64_u64(rem << VC7_FOD_DENOMINATOR_BITS, rate);
77848c5e98fSAlex Helms }
77948c5e98fSAlex Helms 
vc7_calc_fod_1st_stage_rate(unsigned long parent_rate,u32 fod_1st_int,u64 fod_frac)78048c5e98fSAlex Helms static unsigned long vc7_calc_fod_1st_stage_rate(unsigned long parent_rate,
78148c5e98fSAlex Helms 						 u32 fod_1st_int, u64 fod_frac)
78248c5e98fSAlex Helms {
78348c5e98fSAlex Helms 	u64 numer, denom, hi, lo, divisor;
78448c5e98fSAlex Helms 
78548c5e98fSAlex Helms 	numer = fod_frac;
78648c5e98fSAlex Helms 	denom = BIT_ULL(VC7_FOD_DENOMINATOR_BITS);
78748c5e98fSAlex Helms 
78848c5e98fSAlex Helms 	if (fod_frac) {
78948c5e98fSAlex Helms 		vc7_64_mul_64_to_128(parent_rate, denom, &hi, &lo);
79048c5e98fSAlex Helms 		divisor = ((u64)fod_1st_int * denom) + numer;
79148c5e98fSAlex Helms 		return vc7_128_div_64_to_64(hi, lo, divisor, NULL);
79248c5e98fSAlex Helms 	}
79348c5e98fSAlex Helms 
79448c5e98fSAlex Helms 	return div64_u64(parent_rate, fod_1st_int);
79548c5e98fSAlex Helms }
79648c5e98fSAlex Helms 
vc7_calc_fod_2nd_stage_rate(unsigned long parent_rate,u32 fod_1st_int,u32 fod_2nd_int,u64 fod_frac)79748c5e98fSAlex Helms static unsigned long vc7_calc_fod_2nd_stage_rate(unsigned long parent_rate,
79848c5e98fSAlex Helms 						 u32 fod_1st_int, u32 fod_2nd_int, u64 fod_frac)
79948c5e98fSAlex Helms {
80048c5e98fSAlex Helms 	unsigned long fod_1st_stage_rate;
80148c5e98fSAlex Helms 
80248c5e98fSAlex Helms 	fod_1st_stage_rate = vc7_calc_fod_1st_stage_rate(parent_rate, fod_1st_int, fod_frac);
80348c5e98fSAlex Helms 
80448c5e98fSAlex Helms 	if (fod_2nd_int < 2)
80548c5e98fSAlex Helms 		return fod_1st_stage_rate;
80648c5e98fSAlex Helms 
80748c5e98fSAlex Helms 	/*
80848c5e98fSAlex Helms 	 * There is a div-by-2 preceding the 2nd stage integer divider
80948c5e98fSAlex Helms 	 * (not shown on block diagram) so the actual 2nd stage integer
81048c5e98fSAlex Helms 	 * divisor is 2 * N.
81148c5e98fSAlex Helms 	 */
81248c5e98fSAlex Helms 	return div64_u64(fod_1st_stage_rate >> 1, fod_2nd_int);
81348c5e98fSAlex Helms }
81448c5e98fSAlex Helms 
vc7_calc_fod_divider(unsigned long rate,unsigned long parent_rate,u32 * fod_1st_int,u32 * fod_2nd_int,u64 * fod_frac)81548c5e98fSAlex Helms static void vc7_calc_fod_divider(unsigned long rate, unsigned long parent_rate,
81648c5e98fSAlex Helms 				 u32 *fod_1st_int, u32 *fod_2nd_int, u64 *fod_frac)
81748c5e98fSAlex Helms {
81848c5e98fSAlex Helms 	unsigned int allow_frac, i, best_frac_i;
81948c5e98fSAlex Helms 	unsigned long first_stage_rate;
82048c5e98fSAlex Helms 
82148c5e98fSAlex Helms 	vc7_calc_fod_1st_stage(rate, parent_rate, fod_1st_int, fod_frac);
82248c5e98fSAlex Helms 	first_stage_rate = vc7_calc_fod_1st_stage_rate(parent_rate, *fod_1st_int, *fod_frac);
82348c5e98fSAlex Helms 
82448c5e98fSAlex Helms 	*fod_2nd_int = 0;
82548c5e98fSAlex Helms 
82648c5e98fSAlex Helms 	/* Do we need the second stage integer divider? */
82748c5e98fSAlex Helms 	if (first_stage_rate < VC7_FOD_1ST_STAGE_RATE_MIN) {
82848c5e98fSAlex Helms 		allow_frac = 0;
82948c5e98fSAlex Helms 		best_frac_i = VC7_FOD_2ND_INT_MIN;
83048c5e98fSAlex Helms 
83148c5e98fSAlex Helms 		for (i = VC7_FOD_2ND_INT_MIN; i <= VC7_FOD_2ND_INT_MAX; i++) {
83248c5e98fSAlex Helms 			/*
83348c5e98fSAlex Helms 			 * 1) There is a div-by-2 preceding the 2nd stage integer divider
83448c5e98fSAlex Helms 			 *    (not shown on block diagram) so the actual 2nd stage integer
83548c5e98fSAlex Helms 			 *    divisor is 2 * N.
83648c5e98fSAlex Helms 			 * 2) Attempt to find an integer solution first. This means stepping
83748c5e98fSAlex Helms 			 *    through each 2nd stage integer and recalculating the 1st stage
83848c5e98fSAlex Helms 			 *    until the 1st stage frequency is out of bounds. If no integer
83948c5e98fSAlex Helms 			 *    solution is found, use the best fractional solution.
84048c5e98fSAlex Helms 			 */
84148c5e98fSAlex Helms 			vc7_calc_fod_1st_stage(parent_rate, rate * 2 * i, fod_1st_int, fod_frac);
84248c5e98fSAlex Helms 			first_stage_rate = vc7_calc_fod_1st_stage_rate(parent_rate,
84348c5e98fSAlex Helms 								       *fod_1st_int,
84448c5e98fSAlex Helms 								       *fod_frac);
84548c5e98fSAlex Helms 
84648c5e98fSAlex Helms 			/* Remember the first viable fractional solution */
84748c5e98fSAlex Helms 			if (best_frac_i == VC7_FOD_2ND_INT_MIN &&
84848c5e98fSAlex Helms 			    first_stage_rate > VC7_FOD_1ST_STAGE_RATE_MIN) {
84948c5e98fSAlex Helms 				best_frac_i = i;
85048c5e98fSAlex Helms 			}
85148c5e98fSAlex Helms 
85248c5e98fSAlex Helms 			/* Is the divider viable? Prefer integer solutions over fractional. */
85348c5e98fSAlex Helms 			if (*fod_1st_int < VC7_FOD_1ST_INT_MAX &&
85448c5e98fSAlex Helms 			    first_stage_rate >= VC7_FOD_1ST_STAGE_RATE_MIN &&
85548c5e98fSAlex Helms 			    (allow_frac || *fod_frac == 0)) {
85648c5e98fSAlex Helms 				*fod_2nd_int = i;
85748c5e98fSAlex Helms 				break;
85848c5e98fSAlex Helms 			}
85948c5e98fSAlex Helms 
86048c5e98fSAlex Helms 			/* Ran out of divisors or the 1st stage frequency is out of range */
86148c5e98fSAlex Helms 			if (i >= VC7_FOD_2ND_INT_MAX ||
86248c5e98fSAlex Helms 			    first_stage_rate > VC7_FOD_1ST_STAGE_RATE_MAX) {
86348c5e98fSAlex Helms 				allow_frac = 1;
86448c5e98fSAlex Helms 				i = best_frac_i;
86548c5e98fSAlex Helms 
86648c5e98fSAlex Helms 				/* Restore the best frac and rerun the loop for the last time */
86748c5e98fSAlex Helms 				if (best_frac_i != VC7_FOD_2ND_INT_MIN)
86848c5e98fSAlex Helms 					i--;
86948c5e98fSAlex Helms 
87048c5e98fSAlex Helms 				continue;
87148c5e98fSAlex Helms 			}
87248c5e98fSAlex Helms 		}
87348c5e98fSAlex Helms 	}
87448c5e98fSAlex Helms }
87548c5e98fSAlex Helms 
vc7_fod_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)87648c5e98fSAlex Helms static unsigned long vc7_fod_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
87748c5e98fSAlex Helms {
87848c5e98fSAlex Helms 	struct vc7_fod_data *fod = container_of(hw, struct vc7_fod_data, hw);
87948c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = fod->vc7;
88048c5e98fSAlex Helms 	int err;
88148c5e98fSAlex Helms 	unsigned long fod_rate;
88248c5e98fSAlex Helms 
88348c5e98fSAlex Helms 	err = vc7_read_fod(vc7, fod->num);
88448c5e98fSAlex Helms 	if (err) {
88548c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "error reading registers for %s\n",
88648c5e98fSAlex Helms 			clk_hw_get_name(hw));
88748c5e98fSAlex Helms 		return err;
88848c5e98fSAlex Helms 	}
88948c5e98fSAlex Helms 
89048c5e98fSAlex Helms 	pr_debug("%s - %s: parent_rate: %lu\n", __func__, clk_hw_get_name(hw), parent_rate);
89148c5e98fSAlex Helms 
89248c5e98fSAlex Helms 	fod_rate = vc7_calc_fod_2nd_stage_rate(parent_rate, fod->fod_1st_int,
89348c5e98fSAlex Helms 					       fod->fod_2nd_int, fod->fod_frac);
89448c5e98fSAlex Helms 
89548c5e98fSAlex Helms 	pr_debug("%s - %s: fod_1st_int: %u, fod_2nd_int: %u, fod_frac: %llu\n",
89648c5e98fSAlex Helms 		 __func__, clk_hw_get_name(hw),
89748c5e98fSAlex Helms 		 fod->fod_1st_int, fod->fod_2nd_int, fod->fod_frac);
89848c5e98fSAlex Helms 	pr_debug("%s - %s rate: %lu\n", __func__, clk_hw_get_name(hw), fod_rate);
89948c5e98fSAlex Helms 
90048c5e98fSAlex Helms 	return fod_rate;
90148c5e98fSAlex Helms }
90248c5e98fSAlex Helms 
vc7_fod_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)90348c5e98fSAlex Helms static long vc7_fod_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate)
90448c5e98fSAlex Helms {
90548c5e98fSAlex Helms 	struct vc7_fod_data *fod = container_of(hw, struct vc7_fod_data, hw);
90648c5e98fSAlex Helms 	unsigned long fod_rate;
90748c5e98fSAlex Helms 
90848c5e98fSAlex Helms 	pr_debug("%s - %s: requested rate: %lu, parent_rate: %lu\n",
90948c5e98fSAlex Helms 		 __func__, clk_hw_get_name(hw), rate, *parent_rate);
91048c5e98fSAlex Helms 
91148c5e98fSAlex Helms 	vc7_calc_fod_divider(rate, *parent_rate,
91248c5e98fSAlex Helms 			     &fod->fod_1st_int, &fod->fod_2nd_int, &fod->fod_frac);
91348c5e98fSAlex Helms 	fod_rate = vc7_calc_fod_2nd_stage_rate(*parent_rate, fod->fod_1st_int,
91448c5e98fSAlex Helms 					       fod->fod_2nd_int, fod->fod_frac);
91548c5e98fSAlex Helms 
91648c5e98fSAlex Helms 	pr_debug("%s - %s: fod_1st_int: %u, fod_2nd_int: %u, fod_frac: %llu\n",
91748c5e98fSAlex Helms 		 __func__, clk_hw_get_name(hw),
91848c5e98fSAlex Helms 		 fod->fod_1st_int, fod->fod_2nd_int, fod->fod_frac);
91948c5e98fSAlex Helms 	pr_debug("%s - %s rate: %lu\n", __func__, clk_hw_get_name(hw), fod_rate);
92048c5e98fSAlex Helms 
92148c5e98fSAlex Helms 	return fod_rate;
92248c5e98fSAlex Helms }
92348c5e98fSAlex Helms 
vc7_fod_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)92448c5e98fSAlex Helms static int vc7_fod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
92548c5e98fSAlex Helms {
92648c5e98fSAlex Helms 	struct vc7_fod_data *fod = container_of(hw, struct vc7_fod_data, hw);
92748c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = fod->vc7;
92848c5e98fSAlex Helms 	unsigned long fod_rate;
92948c5e98fSAlex Helms 
93048c5e98fSAlex Helms 	pr_debug("%s - %s: rate: %lu, parent_rate: %lu\n",
93148c5e98fSAlex Helms 		 __func__, clk_hw_get_name(hw), rate, parent_rate);
93248c5e98fSAlex Helms 
93348c5e98fSAlex Helms 	if (rate < VC7_FOD_RATE_MIN || rate > VC7_FOD_RATE_MAX) {
93448c5e98fSAlex Helms 		dev_err(&vc7->client->dev,
93548c5e98fSAlex Helms 			"requested frequency %lu Hz for %s is out of range\n",
93648c5e98fSAlex Helms 			rate, clk_hw_get_name(hw));
93748c5e98fSAlex Helms 		return -EINVAL;
93848c5e98fSAlex Helms 	}
93948c5e98fSAlex Helms 
94048c5e98fSAlex Helms 	vc7_write_fod(vc7, fod->num);
94148c5e98fSAlex Helms 
94248c5e98fSAlex Helms 	fod_rate = vc7_calc_fod_2nd_stage_rate(parent_rate, fod->fod_1st_int,
94348c5e98fSAlex Helms 					       fod->fod_2nd_int, fod->fod_frac);
94448c5e98fSAlex Helms 
94548c5e98fSAlex Helms 	pr_debug("%s - %s: fod_1st_int: %u, fod_2nd_int: %u, fod_frac: %llu\n",
94648c5e98fSAlex Helms 		 __func__, clk_hw_get_name(hw),
94748c5e98fSAlex Helms 		 fod->fod_1st_int, fod->fod_2nd_int, fod->fod_frac);
94848c5e98fSAlex Helms 	pr_debug("%s - %s rate: %lu\n", __func__, clk_hw_get_name(hw), fod_rate);
94948c5e98fSAlex Helms 
95048c5e98fSAlex Helms 	return 0;
95148c5e98fSAlex Helms }
95248c5e98fSAlex Helms 
95348c5e98fSAlex Helms static const struct clk_ops vc7_fod_ops = {
95448c5e98fSAlex Helms 	.recalc_rate = vc7_fod_recalc_rate,
95548c5e98fSAlex Helms 	.round_rate = vc7_fod_round_rate,
95648c5e98fSAlex Helms 	.set_rate = vc7_fod_set_rate,
95748c5e98fSAlex Helms };
95848c5e98fSAlex Helms 
vc7_iod_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)95948c5e98fSAlex Helms static unsigned long vc7_iod_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
96048c5e98fSAlex Helms {
96148c5e98fSAlex Helms 	struct vc7_iod_data *iod = container_of(hw, struct vc7_iod_data, hw);
96248c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = iod->vc7;
96348c5e98fSAlex Helms 	int err;
96448c5e98fSAlex Helms 	unsigned long iod_rate;
96548c5e98fSAlex Helms 
96648c5e98fSAlex Helms 	err = vc7_read_iod(vc7, iod->num);
96748c5e98fSAlex Helms 	if (err) {
96848c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "error reading registers for %s\n",
96948c5e98fSAlex Helms 			clk_hw_get_name(hw));
97048c5e98fSAlex Helms 		return err;
97148c5e98fSAlex Helms 	}
97248c5e98fSAlex Helms 
97348c5e98fSAlex Helms 	iod_rate = div64_u64(parent_rate, iod->iod_int);
97448c5e98fSAlex Helms 
97548c5e98fSAlex Helms 	pr_debug("%s - %s: iod_int: %u\n", __func__, clk_hw_get_name(hw), iod->iod_int);
97648c5e98fSAlex Helms 	pr_debug("%s - %s rate: %lu\n", __func__, clk_hw_get_name(hw), iod_rate);
97748c5e98fSAlex Helms 
97848c5e98fSAlex Helms 	return iod_rate;
97948c5e98fSAlex Helms }
98048c5e98fSAlex Helms 
vc7_iod_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)98148c5e98fSAlex Helms static long vc7_iod_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate)
98248c5e98fSAlex Helms {
98348c5e98fSAlex Helms 	struct vc7_iod_data *iod = container_of(hw, struct vc7_iod_data, hw);
98448c5e98fSAlex Helms 	unsigned long iod_rate;
98548c5e98fSAlex Helms 
98648c5e98fSAlex Helms 	pr_debug("%s - %s: requested rate: %lu, parent_rate: %lu\n",
98748c5e98fSAlex Helms 		 __func__, clk_hw_get_name(hw), rate, *parent_rate);
98848c5e98fSAlex Helms 
98948c5e98fSAlex Helms 	vc7_calc_iod_divider(rate, *parent_rate, &iod->iod_int);
99048c5e98fSAlex Helms 	iod_rate = div64_u64(*parent_rate, iod->iod_int);
99148c5e98fSAlex Helms 
99248c5e98fSAlex Helms 	pr_debug("%s - %s: iod_int: %u\n", __func__, clk_hw_get_name(hw), iod->iod_int);
99348c5e98fSAlex Helms 	pr_debug("%s - %s rate: %ld\n", __func__, clk_hw_get_name(hw), iod_rate);
99448c5e98fSAlex Helms 
99548c5e98fSAlex Helms 	return iod_rate;
99648c5e98fSAlex Helms }
99748c5e98fSAlex Helms 
vc7_iod_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)99848c5e98fSAlex Helms static int vc7_iod_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
99948c5e98fSAlex Helms {
100048c5e98fSAlex Helms 	struct vc7_iod_data *iod = container_of(hw, struct vc7_iod_data, hw);
100148c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = iod->vc7;
100248c5e98fSAlex Helms 	unsigned long iod_rate;
100348c5e98fSAlex Helms 
100448c5e98fSAlex Helms 	pr_debug("%s - %s: rate: %lu, parent_rate: %lu\n",
100548c5e98fSAlex Helms 		 __func__, clk_hw_get_name(hw), rate, parent_rate);
100648c5e98fSAlex Helms 
100748c5e98fSAlex Helms 	if (rate < VC7_IOD_RATE_MIN || rate > VC7_IOD_RATE_MAX) {
100848c5e98fSAlex Helms 		dev_err(&vc7->client->dev,
100948c5e98fSAlex Helms 			"requested frequency %lu Hz for %s is out of range\n",
101048c5e98fSAlex Helms 			rate, clk_hw_get_name(hw));
101148c5e98fSAlex Helms 		return -EINVAL;
101248c5e98fSAlex Helms 	}
101348c5e98fSAlex Helms 
101448c5e98fSAlex Helms 	vc7_write_iod(vc7, iod->num);
101548c5e98fSAlex Helms 
101648c5e98fSAlex Helms 	iod_rate = div64_u64(parent_rate, iod->iod_int);
101748c5e98fSAlex Helms 
101848c5e98fSAlex Helms 	pr_debug("%s - %s: iod_int: %u\n", __func__, clk_hw_get_name(hw), iod->iod_int);
101948c5e98fSAlex Helms 	pr_debug("%s - %s rate: %ld\n", __func__, clk_hw_get_name(hw), iod_rate);
102048c5e98fSAlex Helms 
102148c5e98fSAlex Helms 	return 0;
102248c5e98fSAlex Helms }
102348c5e98fSAlex Helms 
102448c5e98fSAlex Helms static const struct clk_ops vc7_iod_ops = {
102548c5e98fSAlex Helms 	.recalc_rate = vc7_iod_recalc_rate,
102648c5e98fSAlex Helms 	.round_rate = vc7_iod_round_rate,
102748c5e98fSAlex Helms 	.set_rate = vc7_iod_set_rate,
102848c5e98fSAlex Helms };
102948c5e98fSAlex Helms 
vc7_clk_out_prepare(struct clk_hw * hw)103048c5e98fSAlex Helms static int vc7_clk_out_prepare(struct clk_hw *hw)
103148c5e98fSAlex Helms {
103248c5e98fSAlex Helms 	struct vc7_out_data *out = container_of(hw, struct vc7_out_data, hw);
103348c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = out->vc7;
103448c5e98fSAlex Helms 	int err;
103548c5e98fSAlex Helms 
103648c5e98fSAlex Helms 	out->out_dis = 0;
103748c5e98fSAlex Helms 
103848c5e98fSAlex Helms 	err = vc7_write_output(vc7, out->num);
103948c5e98fSAlex Helms 	if (err) {
104048c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "error writing registers for %s\n",
104148c5e98fSAlex Helms 			clk_hw_get_name(hw));
104248c5e98fSAlex Helms 		return err;
104348c5e98fSAlex Helms 	}
104448c5e98fSAlex Helms 
104548c5e98fSAlex Helms 	pr_debug("%s - %s: clk prepared\n", __func__, clk_hw_get_name(hw));
104648c5e98fSAlex Helms 
104748c5e98fSAlex Helms 	return 0;
104848c5e98fSAlex Helms }
104948c5e98fSAlex Helms 
vc7_clk_out_unprepare(struct clk_hw * hw)105048c5e98fSAlex Helms static void vc7_clk_out_unprepare(struct clk_hw *hw)
105148c5e98fSAlex Helms {
105248c5e98fSAlex Helms 	struct vc7_out_data *out = container_of(hw, struct vc7_out_data, hw);
105348c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = out->vc7;
105448c5e98fSAlex Helms 	int err;
105548c5e98fSAlex Helms 
105648c5e98fSAlex Helms 	out->out_dis = 1;
105748c5e98fSAlex Helms 
105848c5e98fSAlex Helms 	err = vc7_write_output(vc7, out->num);
105948c5e98fSAlex Helms 	if (err) {
106048c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "error writing registers for %s\n",
106148c5e98fSAlex Helms 			clk_hw_get_name(hw));
106248c5e98fSAlex Helms 		return;
106348c5e98fSAlex Helms 	}
106448c5e98fSAlex Helms 
106548c5e98fSAlex Helms 	pr_debug("%s - %s: clk unprepared\n", __func__, clk_hw_get_name(hw));
106648c5e98fSAlex Helms }
106748c5e98fSAlex Helms 
vc7_clk_out_is_enabled(struct clk_hw * hw)106848c5e98fSAlex Helms static int vc7_clk_out_is_enabled(struct clk_hw *hw)
106948c5e98fSAlex Helms {
107048c5e98fSAlex Helms 	struct vc7_out_data *out = container_of(hw, struct vc7_out_data, hw);
107148c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = out->vc7;
107248c5e98fSAlex Helms 	int err, is_enabled;
107348c5e98fSAlex Helms 
107448c5e98fSAlex Helms 	err = vc7_read_output(vc7, out->num);
107548c5e98fSAlex Helms 	if (err) {
107648c5e98fSAlex Helms 		dev_err(&vc7->client->dev, "error reading registers for %s\n",
107748c5e98fSAlex Helms 			clk_hw_get_name(hw));
107848c5e98fSAlex Helms 		return err;
107948c5e98fSAlex Helms 	}
108048c5e98fSAlex Helms 
108148c5e98fSAlex Helms 	is_enabled = !out->out_dis;
108248c5e98fSAlex Helms 
108348c5e98fSAlex Helms 	pr_debug("%s - %s: is_enabled=%d\n", __func__, clk_hw_get_name(hw), is_enabled);
108448c5e98fSAlex Helms 
108548c5e98fSAlex Helms 	return is_enabled;
108648c5e98fSAlex Helms }
108748c5e98fSAlex Helms 
108848c5e98fSAlex Helms static const struct clk_ops vc7_clk_out_ops = {
108948c5e98fSAlex Helms 	.prepare = vc7_clk_out_prepare,
109048c5e98fSAlex Helms 	.unprepare = vc7_clk_out_unprepare,
109148c5e98fSAlex Helms 	.is_enabled = vc7_clk_out_is_enabled,
109248c5e98fSAlex Helms };
109348c5e98fSAlex Helms 
vc7_probe(struct i2c_client * client)109448c5e98fSAlex Helms static int vc7_probe(struct i2c_client *client)
109548c5e98fSAlex Helms {
109648c5e98fSAlex Helms 	struct vc7_driver_data *vc7;
109748c5e98fSAlex Helms 	struct clk_init_data clk_init;
109848c5e98fSAlex Helms 	struct vc7_bank_src_map bank_src_map;
109948c5e98fSAlex Helms 	const char *node_name, *apll_name;
110048c5e98fSAlex Helms 	const char *parent_names[1];
110148c5e98fSAlex Helms 	unsigned int i, val, bank_idx, out_num;
110248c5e98fSAlex Helms 	unsigned long apll_rate;
110348c5e98fSAlex Helms 	int ret;
110448c5e98fSAlex Helms 
110548c5e98fSAlex Helms 	vc7 = devm_kzalloc(&client->dev, sizeof(*vc7), GFP_KERNEL);
110648c5e98fSAlex Helms 	if (!vc7)
110748c5e98fSAlex Helms 		return -ENOMEM;
110848c5e98fSAlex Helms 
110948c5e98fSAlex Helms 	i2c_set_clientdata(client, vc7);
111048c5e98fSAlex Helms 	vc7->client = client;
1111*fccd617fSBiju Das 	vc7->chip_info = i2c_get_match_data(client);
111248c5e98fSAlex Helms 
111348c5e98fSAlex Helms 	vc7->pin_xin = devm_clk_get(&client->dev, "xin");
111448c5e98fSAlex Helms 	if (PTR_ERR(vc7->pin_xin) == -EPROBE_DEFER) {
111548c5e98fSAlex Helms 		return dev_err_probe(&client->dev, -EPROBE_DEFER,
111648c5e98fSAlex Helms 				     "xin not specified\n");
111748c5e98fSAlex Helms 	}
111848c5e98fSAlex Helms 
111948c5e98fSAlex Helms 	vc7->regmap = devm_regmap_init_i2c(client, &vc7_regmap_config);
112048c5e98fSAlex Helms 	if (IS_ERR(vc7->regmap)) {
112148c5e98fSAlex Helms 		return dev_err_probe(&client->dev, PTR_ERR(vc7->regmap),
112248c5e98fSAlex Helms 				     "failed to allocate register map\n");
112348c5e98fSAlex Helms 	}
112448c5e98fSAlex Helms 
112548c5e98fSAlex Helms 	if (of_property_read_string(client->dev.of_node, "clock-output-names",
112648c5e98fSAlex Helms 				    &node_name))
112748c5e98fSAlex Helms 		node_name = client->dev.of_node->name;
112848c5e98fSAlex Helms 
112948c5e98fSAlex Helms 	/* Register APLL */
113048c5e98fSAlex Helms 	apll_rate = vc7_get_apll_rate(vc7);
113148c5e98fSAlex Helms 	apll_name = kasprintf(GFP_KERNEL, "%s_apll", node_name);
113248c5e98fSAlex Helms 	vc7->clk_apll.clk = clk_register_fixed_rate(&client->dev, apll_name,
113348c5e98fSAlex Helms 						    __clk_get_name(vc7->pin_xin),
113448c5e98fSAlex Helms 						    0, apll_rate);
113548c5e98fSAlex Helms 	kfree(apll_name); /* ccf made a copy of the name */
113648c5e98fSAlex Helms 	if (IS_ERR(vc7->clk_apll.clk)) {
113748c5e98fSAlex Helms 		return dev_err_probe(&client->dev, PTR_ERR(vc7->clk_apll.clk),
113848c5e98fSAlex Helms 				     "failed to register apll\n");
113948c5e98fSAlex Helms 	}
114048c5e98fSAlex Helms 
114148c5e98fSAlex Helms 	/* Register FODs */
114248c5e98fSAlex Helms 	for (i = 0; i < VC7_NUM_FOD; i++) {
114348c5e98fSAlex Helms 		memset(&clk_init, 0, sizeof(clk_init));
114448c5e98fSAlex Helms 		clk_init.name = kasprintf(GFP_KERNEL, "%s_fod%d", node_name, i);
114548c5e98fSAlex Helms 		clk_init.ops = &vc7_fod_ops;
114648c5e98fSAlex Helms 		clk_init.parent_names = parent_names;
114748c5e98fSAlex Helms 		parent_names[0] = __clk_get_name(vc7->clk_apll.clk);
114848c5e98fSAlex Helms 		clk_init.num_parents = 1;
114948c5e98fSAlex Helms 		vc7->clk_fod[i].num = i;
115048c5e98fSAlex Helms 		vc7->clk_fod[i].vc7 = vc7;
115148c5e98fSAlex Helms 		vc7->clk_fod[i].hw.init = &clk_init;
115248c5e98fSAlex Helms 		ret = devm_clk_hw_register(&client->dev, &vc7->clk_fod[i].hw);
115348c5e98fSAlex Helms 		if (ret)
115448c5e98fSAlex Helms 			goto err_clk_register;
115548c5e98fSAlex Helms 		kfree(clk_init.name); /* ccf made a copy of the name */
115648c5e98fSAlex Helms 	}
115748c5e98fSAlex Helms 
115848c5e98fSAlex Helms 	/* Register IODs */
115948c5e98fSAlex Helms 	for (i = 0; i < VC7_NUM_IOD; i++) {
116048c5e98fSAlex Helms 		memset(&clk_init, 0, sizeof(clk_init));
116148c5e98fSAlex Helms 		clk_init.name = kasprintf(GFP_KERNEL, "%s_iod%d", node_name, i);
116248c5e98fSAlex Helms 		clk_init.ops = &vc7_iod_ops;
116348c5e98fSAlex Helms 		clk_init.parent_names = parent_names;
116448c5e98fSAlex Helms 		parent_names[0] = __clk_get_name(vc7->clk_apll.clk);
116548c5e98fSAlex Helms 		clk_init.num_parents = 1;
116648c5e98fSAlex Helms 		vc7->clk_iod[i].num = i;
116748c5e98fSAlex Helms 		vc7->clk_iod[i].vc7 = vc7;
116848c5e98fSAlex Helms 		vc7->clk_iod[i].hw.init = &clk_init;
116948c5e98fSAlex Helms 		ret = devm_clk_hw_register(&client->dev, &vc7->clk_iod[i].hw);
117048c5e98fSAlex Helms 		if (ret)
117148c5e98fSAlex Helms 			goto err_clk_register;
117248c5e98fSAlex Helms 		kfree(clk_init.name); /* ccf made a copy of the name */
117348c5e98fSAlex Helms 	}
117448c5e98fSAlex Helms 
117548c5e98fSAlex Helms 	/* Register outputs */
117648c5e98fSAlex Helms 	for (i = 0; i < vc7->chip_info->num_outputs; i++) {
117748c5e98fSAlex Helms 		out_num = vc7_map_index_to_output(vc7->chip_info->model, i);
117848c5e98fSAlex Helms 
117948c5e98fSAlex Helms 		/*
118048c5e98fSAlex Helms 		 * This driver does not support remapping FOD/IOD to banks.
118148c5e98fSAlex Helms 		 * The device state is read and the driver is setup to match
118248c5e98fSAlex Helms 		 * the device's existing mapping.
118348c5e98fSAlex Helms 		 */
118448c5e98fSAlex Helms 		bank_idx = output_bank_mapping[out_num];
118548c5e98fSAlex Helms 
118648c5e98fSAlex Helms 		regmap_read(vc7->regmap, VC7_REG_OUT_BANK_CNFG(bank_idx), &val);
118748c5e98fSAlex Helms 		val &= VC7_REG_OUTPUT_BANK_SRC_MASK;
118848c5e98fSAlex Helms 
118948c5e98fSAlex Helms 		memset(&bank_src_map, 0, sizeof(bank_src_map));
119048c5e98fSAlex Helms 		ret = vc7_get_bank_clk(vc7, bank_idx, val, &bank_src_map);
119148c5e98fSAlex Helms 		if (ret) {
119248c5e98fSAlex Helms 			dev_err_probe(&client->dev, ret,
119348c5e98fSAlex Helms 				      "unable to register output %d\n", i);
119448c5e98fSAlex Helms 			return ret;
119548c5e98fSAlex Helms 		}
119648c5e98fSAlex Helms 
119748c5e98fSAlex Helms 		switch (bank_src_map.type) {
119848c5e98fSAlex Helms 		case VC7_FOD:
119948c5e98fSAlex Helms 			parent_names[0] = clk_hw_get_name(&bank_src_map.src.fod->hw);
120048c5e98fSAlex Helms 			break;
120148c5e98fSAlex Helms 		case VC7_IOD:
120248c5e98fSAlex Helms 			parent_names[0] = clk_hw_get_name(&bank_src_map.src.iod->hw);
120348c5e98fSAlex Helms 			break;
120448c5e98fSAlex Helms 		}
120548c5e98fSAlex Helms 
120648c5e98fSAlex Helms 		memset(&clk_init, 0, sizeof(clk_init));
120748c5e98fSAlex Helms 		clk_init.name = kasprintf(GFP_KERNEL, "%s_out%d", node_name, i);
120848c5e98fSAlex Helms 		clk_init.ops = &vc7_clk_out_ops;
120948c5e98fSAlex Helms 		clk_init.flags = CLK_SET_RATE_PARENT;
121048c5e98fSAlex Helms 		clk_init.parent_names = parent_names;
121148c5e98fSAlex Helms 		clk_init.num_parents = 1;
121248c5e98fSAlex Helms 		vc7->clk_out[i].num = i;
121348c5e98fSAlex Helms 		vc7->clk_out[i].vc7 = vc7;
121448c5e98fSAlex Helms 		vc7->clk_out[i].hw.init = &clk_init;
121548c5e98fSAlex Helms 		ret = devm_clk_hw_register(&client->dev, &vc7->clk_out[i].hw);
121648c5e98fSAlex Helms 		if (ret)
121748c5e98fSAlex Helms 			goto err_clk_register;
121848c5e98fSAlex Helms 		kfree(clk_init.name); /* ccf made a copy of the name */
121948c5e98fSAlex Helms 	}
122048c5e98fSAlex Helms 
122148c5e98fSAlex Helms 	ret = of_clk_add_hw_provider(client->dev.of_node, vc7_of_clk_get, vc7);
122248c5e98fSAlex Helms 	if (ret) {
122348c5e98fSAlex Helms 		dev_err_probe(&client->dev, ret, "unable to add clk provider\n");
122448c5e98fSAlex Helms 		goto err_clk;
122548c5e98fSAlex Helms 	}
122648c5e98fSAlex Helms 
122748c5e98fSAlex Helms 	return ret;
122848c5e98fSAlex Helms 
122948c5e98fSAlex Helms err_clk_register:
123048c5e98fSAlex Helms 	dev_err_probe(&client->dev, ret,
123148c5e98fSAlex Helms 		      "unable to register %s\n", clk_init.name);
123248c5e98fSAlex Helms 	kfree(clk_init.name); /* ccf made a copy of the name */
123348c5e98fSAlex Helms err_clk:
123448c5e98fSAlex Helms 	clk_unregister_fixed_rate(vc7->clk_apll.clk);
123548c5e98fSAlex Helms 	return ret;
123648c5e98fSAlex Helms }
123748c5e98fSAlex Helms 
vc7_remove(struct i2c_client * client)1238bdc753c7SLinus Torvalds static void vc7_remove(struct i2c_client *client)
123948c5e98fSAlex Helms {
124048c5e98fSAlex Helms 	struct vc7_driver_data *vc7 = i2c_get_clientdata(client);
124148c5e98fSAlex Helms 
124248c5e98fSAlex Helms 	of_clk_del_provider(client->dev.of_node);
124348c5e98fSAlex Helms 	clk_unregister_fixed_rate(vc7->clk_apll.clk);
124448c5e98fSAlex Helms }
124548c5e98fSAlex Helms 
vc7_volatile_reg(struct device * dev,unsigned int reg)124648c5e98fSAlex Helms static bool vc7_volatile_reg(struct device *dev, unsigned int reg)
124748c5e98fSAlex Helms {
124848c5e98fSAlex Helms 	if (reg == VC7_PAGE_ADDR)
124948c5e98fSAlex Helms 		return false;
125048c5e98fSAlex Helms 
125148c5e98fSAlex Helms 	return true;
125248c5e98fSAlex Helms }
125348c5e98fSAlex Helms 
125448c5e98fSAlex Helms static const struct vc7_chip_info vc7_rc21008a_info = {
125548c5e98fSAlex Helms 	.model = VC7_RC21008A,
125648c5e98fSAlex Helms 	.num_banks = 6,
125748c5e98fSAlex Helms 	.num_outputs = 8,
125848c5e98fSAlex Helms };
125948c5e98fSAlex Helms 
126048c5e98fSAlex Helms static struct regmap_range_cfg vc7_range_cfg[] = {
126148c5e98fSAlex Helms {
126248c5e98fSAlex Helms 	.range_min = 0,
126348c5e98fSAlex Helms 	.range_max = VC7_MAX_REG,
126448c5e98fSAlex Helms 	.selector_reg = VC7_PAGE_ADDR,
126548c5e98fSAlex Helms 	.selector_mask = 0xFF,
126648c5e98fSAlex Helms 	.selector_shift = 0,
126748c5e98fSAlex Helms 	.window_start = 0,
126848c5e98fSAlex Helms 	.window_len = VC7_PAGE_WINDOW,
126948c5e98fSAlex Helms }};
127048c5e98fSAlex Helms 
127148c5e98fSAlex Helms static const struct regmap_config vc7_regmap_config = {
127248c5e98fSAlex Helms 	.reg_bits = 8,
127348c5e98fSAlex Helms 	.val_bits = 8,
127448c5e98fSAlex Helms 	.max_register = VC7_MAX_REG,
127548c5e98fSAlex Helms 	.ranges = vc7_range_cfg,
127648c5e98fSAlex Helms 	.num_ranges = ARRAY_SIZE(vc7_range_cfg),
127748c5e98fSAlex Helms 	.volatile_reg = vc7_volatile_reg,
127848c5e98fSAlex Helms 	.cache_type = REGCACHE_RBTREE,
127948c5e98fSAlex Helms 	.can_multi_write = true,
128048c5e98fSAlex Helms 	.reg_format_endian = REGMAP_ENDIAN_LITTLE,
128148c5e98fSAlex Helms 	.val_format_endian = REGMAP_ENDIAN_LITTLE,
128248c5e98fSAlex Helms };
128348c5e98fSAlex Helms 
128448c5e98fSAlex Helms static const struct i2c_device_id vc7_i2c_id[] = {
1285b5e10beeSMarek Vasut 	{ "rc21008a", .driver_data = (kernel_ulong_t)&vc7_rc21008a_info },
128648c5e98fSAlex Helms 	{}
128748c5e98fSAlex Helms };
128848c5e98fSAlex Helms MODULE_DEVICE_TABLE(i2c, vc7_i2c_id);
128948c5e98fSAlex Helms 
129048c5e98fSAlex Helms static const struct of_device_id vc7_of_match[] = {
129148c5e98fSAlex Helms 	{ .compatible = "renesas,rc21008a", .data = &vc7_rc21008a_info },
129248c5e98fSAlex Helms 	{}
129348c5e98fSAlex Helms };
129448c5e98fSAlex Helms MODULE_DEVICE_TABLE(of, vc7_of_match);
129548c5e98fSAlex Helms 
129648c5e98fSAlex Helms static struct i2c_driver vc7_i2c_driver = {
129748c5e98fSAlex Helms 	.driver = {
129848c5e98fSAlex Helms 		.name = "vc7",
129948c5e98fSAlex Helms 		.of_match_table = vc7_of_match,
130048c5e98fSAlex Helms 	},
130162279db5SUwe Kleine-König 	.probe = vc7_probe,
130248c5e98fSAlex Helms 	.remove = vc7_remove,
130348c5e98fSAlex Helms 	.id_table = vc7_i2c_id,
130448c5e98fSAlex Helms };
130548c5e98fSAlex Helms module_i2c_driver(vc7_i2c_driver);
130648c5e98fSAlex Helms 
130748c5e98fSAlex Helms MODULE_LICENSE("GPL");
130848c5e98fSAlex Helms MODULE_AUTHOR("Alex Helms <alexander.helms.jy@renesas.com");
130948c5e98fSAlex Helms MODULE_DESCRIPTION("Renesas Versaclock7 common clock framework driver");
1310