// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2014 STMicroelectronics R&D Ltd
*/
/*
* Authors:
* Stephen Gallimore <stephen.gallimore@st.com>,
* Pankaj Dev <pankaj.dev@st.com>.
*/
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include "clkgen.h"
/*
* Maximum input clock to the PLL before we divide it down by 2
* although in reality in actual systems this has never been seen to
* be used.
*/
#define QUADFS_NDIV_THRESHOLD 30000000
#define PLL_BW_GOODREF (0L)
#define PLL_BW_VBADREF (1L)
#define PLL_BW_BADREF (2L)
#define PLL_BW_VGOODREF (3L)
#define QUADFS_MAX_CHAN 4
struct stm_fs {
unsigned long ndiv;
unsigned long mdiv;
unsigned long pe;
unsigned long sdiv;
unsigned long nsdiv;
};
struct clkgen_quadfs_data {
bool reset_present;
bool bwfilter_present;
bool lockstatus_present;
bool powerup_polarity;
bool standby_polarity;
bool nsdiv_present;
bool nrst_present;
struct clkgen_field ndiv;
struct clkgen_field ref_bw;
struct clkgen_field nreset;
struct clkgen_field npda;
struct clkgen_field lock_status;
struct clkgen_field nrst[QUADFS_MAX_CHAN];
struct clkgen_field nsb[QUADFS_MAX_CHAN];
struct clkgen_field en[QUADFS_MAX_CHAN];
struct clkgen_field mdiv[QUADFS_MAX_CHAN];
struct clkgen_field pe[QUADFS_MAX_CHAN];
struct clkgen_field sdiv[QUADFS_MAX_CHAN];
struct clkgen_field nsdiv[QUADFS_MAX_CHAN];
const struct clk_ops *pll_ops;
int (*get_params)(unsigned long, unsigned long, struct stm_fs *);
int (*get_rate)(unsigned long , const struct stm_fs *,
unsigned long *);
};
struct clkgen_clk_out {
const char *name;
unsigned long flags;
};
struct clkgen_quadfs_data_clks {
struct clkgen_quadfs_data *data;
const struct clkgen_clk_out *outputs;
};
static const struct clk_ops st_quadfs_pll_c32_ops;
static int clk_fs660c32_dig_get_params(unsigned long input,
unsigned long output, struct stm_fs *fs);
static int clk_fs660c32_dig_get_rate(unsigned long, const struct stm_fs *,
unsigned long *);
static const struct clkgen_quadfs_data st_fs660c32_C = {
.nrst_present = true,
.nrst = { CLKGEN_FIELD(0x2f0, 0x1, 0),
CLKGEN_FIELD(0x2f0, 0x1, 1),
CLKGEN_FIELD(0x2f0, 0x1, 2),
CLKGEN_FIELD(0x2f0, 0x1, 3) },
.npda = CLKGEN_FIELD(0x2f0, 0x1, 12),
.nsb = { CLKGEN_FIELD(0x2f0, 0x1, 8),
CLKGEN_FIELD(0x2f0, 0x1, 9),
CLKGEN_FIELD(0x2f0, 0x1, 10),
CLKGEN_FIELD(0x2f0, 0x1, 11) },
.nsdiv_present = true,
.nsdiv = { CLKGEN_FIELD(0x304, 0x1, 24),
CLKGEN_FIELD(0x308, 0x1, 24),
CLKGEN_FIELD(0x30c, 0x1, 24),
CLKGEN_FIELD(0x310, 0x1, 24) },
.mdiv = { CLKGEN_FIELD(0x304, 0x1f, 15),
CLKGEN_FIELD(0x308, 0x1f, 15),
CLKGEN_FIELD(0x30c, 0x1f, 15),
CLKGEN_FIELD(0x310, 0x1f, 15) },
.en = { CLKGEN_FIELD(0x2fc, 0x1, 0),
CLKGEN_FIELD(0x2fc, 0x1, 1),
CLKGEN_FIELD(0x2fc, 0x1, 2),
CLKGEN_FIELD(0x2fc, 0x1, 3) },
.ndiv = CLKGEN_FIELD(0x2f4, 0x7, 16),
.pe = { CLKGEN_FIELD(0x304, 0x7fff, 0),
CLKGEN_FIELD(0x308, 0x7fff, 0),
CLKGEN_FIELD(0x30c, 0x7fff, 0),
CLKGEN_FIELD(0x310, 0x7fff, 0) },
.sdiv = { CLKGEN_FIELD(0x304, 0xf, 20),
CLKGEN_FIELD(0x308, 0xf, 20),
CLKGEN_FIELD(0x30c, 0xf, 20),
CLKGEN_FIELD(0x310, 0xf, 20) },
.lockstatus_present = true,
.lock_status = CLKGEN_FIELD(0x2f0, 0x1, 24),
.powerup_polarity = 1,
.standby_polarity = 1,
.pll_ops = &st_quadfs_pll_c32_ops,
.get_params = clk_fs660c32_dig_get_params,
.get_rate = clk_fs660c32_dig_get_rate,
};
static const struct clkgen_clk_out st_fs660c32_C_clks[] = {
{ .name = "clk-s-c0-fs0-ch0", },
{ .name = "clk-s-c0-fs0-ch1", },
{ .name = "clk-s-c0-fs0-ch2", },
{ .name = "clk-s-c0-fs0-ch3", },
};
static const struct clkgen_quadfs_data_clks st_fs660c32_C_data = {
.data = (struct clkgen_quadfs_data *)&st_fs660c32_C,
.outputs = st_fs660c32_C_clks,
};
static const struct clkgen_quadfs_data st_fs660c32_D = {
.nrst_present = true,
.nrst = { CLKGEN_FIELD(0x2a0, 0x1, 0