// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Renesas Versaclock 3
*
* Copyright (C) 2023 Renesas Electronics Corp.
*/
#include <linux/clk-provider.h>
#include <linux/i2c.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/regmap.h>
#define NUM_CONFIG_REGISTERS 37
#define VC3_GENERAL_CTR 0x0
#define VC3_GENERAL_CTR_DIV1_SRC_SEL BIT(3)
#define VC3_GENERAL_CTR_PLL3_REFIN_SEL BIT(2)
#define VC3_PLL3_M_DIVIDER 0x3
#define VC3_PLL3_M_DIV1 BIT(7)
#define VC3_PLL3_M_DIV2 BIT(6)
#define VC3_PLL3_M_DIV(n) ((n) & GENMASK(5, 0))
#define VC3_PLL3_N_DIVIDER 0x4
#define VC3_PLL3_LOOP_FILTER_N_DIV_MSB 0x5
#define VC3_PLL3_CHARGE_PUMP_CTRL 0x6
#define VC3_PLL3_CHARGE_PUMP_CTRL_OUTDIV3_SRC_SEL BIT(7)
#define VC3_PLL1_CTRL_OUTDIV5 0x7
#define VC3_PLL1_CTRL_OUTDIV5_PLL1_MDIV_DOUBLER BIT(7)
#define VC3_PLL1_M_DIVIDER 0x8
#define VC3_PLL1_M_DIV1 BIT(7)
#define VC3_PLL1_M_DIV2 BIT(6)
#define VC3_PLL1_M_DIV(n) ((n) & GENMASK(5, 0))
#define VC3_PLL1_VCO_N_DIVIDER 0x9
#define VC3_PLL1_LOOP_FILTER_N_DIV_MSB 0xa
#define VC3_OUT_DIV1_DIV2_CTRL 0xf
#define VC3_PLL2_FB_INT_DIV_MSB 0x10
#define VC3_PLL2_FB_INT_DIV_LSB 0x11
#define VC3_PLL2_FB_FRC_DIV_MSB 0x12
#define VC3_PLL2_FB_FRC_DIV_LSB 0x13
#define VC3_PLL2_M_DIVIDER 0x1a
#define VC3_PLL2_MDIV_DOUBLER BIT(7)
#define VC3_PLL2_M_DIV1 BIT(6)
#define VC3_PLL2_M_DIV2 BIT(5)
#define VC3_PLL2_M_DIV(n) ((n) & GENMASK(4, 0))
#define VC3_OUT_DIV3_DIV4_CTRL 0x1b
#define VC3_PLL_OP_CTRL 0x1c
#define VC3_PLL_OP_CTRL_PLL2_REFIN_SEL 6
#define VC3_OUTPUT_CTR 0x1d
#define VC3_OUTPUT_CTR_DIV4_SRC_SEL BIT(3)
#define VC3_SE2_CTRL_REG0 0x1f
#define VC3_SE2_CTRL_REG0_SE2_CLK_SEL BIT(6)
#define VC3_SE3_DIFF1_CTRL_REG 0x21
#define VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL BIT(6)
#define VC3_DIFF1_CTRL_REG 0x22
#define VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL BIT(7)
#define VC3_DIFF2_CTRL_REG 0x23
#define VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL BIT(7)
#define VC3_SE1_DIV4_CTRL 0x24
#define VC3_SE1_DIV4_CTRL_SE1_CLK_SEL BIT(3)
#define VC3_PLL1_VCO_MIN 300000000UL
#define VC3_PLL1_VCO_MAX 600000000UL
#define VC3_PLL2_VCO_MIN 400000000UL
#define VC3_PLL2_VCO_MAX 1200000000UL
#define VC3_PLL3_VCO_MIN 300000000UL
#define VC3_PLL3_VCO_MAX 800000000UL
#define VC3_2_POW_16 (U16_MAX + 1)
#define VC3_DIV_MASK(width) ((1 << (width)) - 1)
enum vc3_pfd_mux {
VC3_PFD2_MUX,
VC3_PFD3_MUX,
};
enum vc3_pfd {
VC3_PFD1,
VC3_PFD2,
VC3_PFD3,
};
enum vc3_pll {
VC3_PLL1,
VC3_PLL2,
VC3_PLL3,
};
enum vc3_div_mux {
VC3_DIV1_MUX,
VC3_DIV3_MUX,
VC3_DIV4_MUX,
};
enum vc3_div {
VC3_DIV1,
VC3_DIV2,
VC3_DIV3,
VC3_DIV4,
VC3_DIV5,
};
enum vc3_clk {
VC3_REF,
VC3_SE1,
VC3_SE2,
VC3_SE3,
VC3_DIFF1,
VC3_DIFF2,
};
enum vc3_clk_mux {
VC3_SE1_MUX = VC3_SE1 - 1,
VC3_SE2_MUX = VC3_SE2 - 1,
VC3_SE3_MUX = VC3_SE3 - 1,
VC3_DIFF1_MUX = VC3_DIFF1 - 1,
VC3_DIFF2_MUX = VC3_DIFF2 - 1,
};
struct vc3_clk_data {
u8 offs;
u8 bitmsk;
};
struct vc3_pfd_data {
u8 num;
u8 offs;
u8 mdiv1_bitmsk;
u8 mdiv2_bitmsk;
};
struct vc3_pll_data {
unsigned long vco_min;
unsigned long vco_max;
u8 num;
u8 int_div_msb_offs;
u8 int_div_lsb_offs;
};
struct vc3_div_data {
const struct clk_div_table *table;
u8 offs;
u8 shift;
u8 width;
u8 flags;
};
struct vc3_hw_data {
struct clk_hw hw;
struct regmap *regmap;
const void *data;
u32 div_int;
u32 div_frc;
};
static const struct clk_div_table div1_divs[] = {
{ .val = 0, .div = 1, }, { .val = 1, .div = 4, },
{ .val = 2, .div = 5, }, { .val = 3, .div = 6, },
{ .val = 4, .div = 2, }, { .val = 5, .div = 8, },
{ .val = 6, .div = 10, }, { .val = 7, .div = 12, },
{ .val = 8, .div = 4, }, { .val = 9, .div = 16, },
{ .val = 10, .div = 20, }, { .val = 11, .div = 24, },
{ .val = 12, .div = 8, }, { .val = 13, .div = 32, },
{ .val = 14, .div = 40, }, { .val = 15, .div = 48, },
{}
};
static const struct clk_div_table div245_divs[] = {
{ .val = 0, .div = 1, }, { .val = 1, .div = 3, },
{ .val = 2, .div = 5, }, { .val = 3, .div = 10, },
{ .val = 4, .div = 2, }, { .val = 5, .div = 6, },
{ .val = 6, .div = 10, }, { .val = 7, .div = 20, },
{ .val = 8, .div = 4, }, { .val = 9, .div = 12, },
{ .val = 10, .div = 20