xref: /openbmc/linux/drivers/clk/st/clkgen-fsyn.c (revision cfd3ffb3)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25f7aa907SGabriel FERNANDEZ /*
35f7aa907SGabriel FERNANDEZ  * Copyright (C) 2014 STMicroelectronics R&D Ltd
45f7aa907SGabriel FERNANDEZ  */
55f7aa907SGabriel FERNANDEZ 
65f7aa907SGabriel FERNANDEZ /*
75f7aa907SGabriel FERNANDEZ  * Authors:
85f7aa907SGabriel FERNANDEZ  * Stephen Gallimore <stephen.gallimore@st.com>,
95f7aa907SGabriel FERNANDEZ  * Pankaj Dev <pankaj.dev@st.com>.
105f7aa907SGabriel FERNANDEZ  */
115f7aa907SGabriel FERNANDEZ 
125f7aa907SGabriel FERNANDEZ #include <linux/slab.h>
135f7aa907SGabriel FERNANDEZ #include <linux/of_address.h>
14d5f728acSStephen Boyd #include <linux/clk.h>
155f7aa907SGabriel FERNANDEZ #include <linux/clk-provider.h>
165f7aa907SGabriel FERNANDEZ 
175f7aa907SGabriel FERNANDEZ #include "clkgen.h"
185f7aa907SGabriel FERNANDEZ 
195f7aa907SGabriel FERNANDEZ /*
205f7aa907SGabriel FERNANDEZ  * Maximum input clock to the PLL before we divide it down by 2
215f7aa907SGabriel FERNANDEZ  * although in reality in actual systems this has never been seen to
225f7aa907SGabriel FERNANDEZ  * be used.
235f7aa907SGabriel FERNANDEZ  */
245f7aa907SGabriel FERNANDEZ #define QUADFS_NDIV_THRESHOLD 30000000
255f7aa907SGabriel FERNANDEZ 
265f7aa907SGabriel FERNANDEZ #define PLL_BW_GOODREF   (0L)
275f7aa907SGabriel FERNANDEZ #define PLL_BW_VBADREF   (1L)
285f7aa907SGabriel FERNANDEZ #define PLL_BW_BADREF    (2L)
295f7aa907SGabriel FERNANDEZ #define PLL_BW_VGOODREF  (3L)
305f7aa907SGabriel FERNANDEZ 
315f7aa907SGabriel FERNANDEZ #define QUADFS_MAX_CHAN 4
325f7aa907SGabriel FERNANDEZ 
335f7aa907SGabriel FERNANDEZ struct stm_fs {
345f7aa907SGabriel FERNANDEZ 	unsigned long ndiv;
355f7aa907SGabriel FERNANDEZ 	unsigned long mdiv;
365f7aa907SGabriel FERNANDEZ 	unsigned long pe;
375f7aa907SGabriel FERNANDEZ 	unsigned long sdiv;
385f7aa907SGabriel FERNANDEZ 	unsigned long nsdiv;
395f7aa907SGabriel FERNANDEZ };
405f7aa907SGabriel FERNANDEZ 
415f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data {
425f7aa907SGabriel FERNANDEZ 	bool reset_present;
435f7aa907SGabriel FERNANDEZ 	bool bwfilter_present;
445f7aa907SGabriel FERNANDEZ 	bool lockstatus_present;
458f26df84SGabriel FERNANDEZ 	bool powerup_polarity;
468f26df84SGabriel FERNANDEZ 	bool standby_polarity;
475f7aa907SGabriel FERNANDEZ 	bool nsdiv_present;
48fc755c8bSGabriel FERNANDEZ 	bool nrst_present;
495f7aa907SGabriel FERNANDEZ 	struct clkgen_field ndiv;
505f7aa907SGabriel FERNANDEZ 	struct clkgen_field ref_bw;
515f7aa907SGabriel FERNANDEZ 	struct clkgen_field nreset;
525f7aa907SGabriel FERNANDEZ 	struct clkgen_field npda;
535f7aa907SGabriel FERNANDEZ 	struct clkgen_field lock_status;
545f7aa907SGabriel FERNANDEZ 
55fc755c8bSGabriel FERNANDEZ 	struct clkgen_field nrst[QUADFS_MAX_CHAN];
565f7aa907SGabriel FERNANDEZ 	struct clkgen_field nsb[QUADFS_MAX_CHAN];
575f7aa907SGabriel FERNANDEZ 	struct clkgen_field en[QUADFS_MAX_CHAN];
585f7aa907SGabriel FERNANDEZ 	struct clkgen_field mdiv[QUADFS_MAX_CHAN];
595f7aa907SGabriel FERNANDEZ 	struct clkgen_field pe[QUADFS_MAX_CHAN];
605f7aa907SGabriel FERNANDEZ 	struct clkgen_field sdiv[QUADFS_MAX_CHAN];
615f7aa907SGabriel FERNANDEZ 	struct clkgen_field nsdiv[QUADFS_MAX_CHAN];
625f7aa907SGabriel FERNANDEZ 
635f7aa907SGabriel FERNANDEZ 	const struct clk_ops *pll_ops;
64b699f3e3SGabriel Fernandez 	int  (*get_params)(unsigned long, unsigned long, struct stm_fs *);
654abb1b40SGabriel FERNANDEZ 	int  (*get_rate)(unsigned long , const struct stm_fs *,
665f7aa907SGabriel FERNANDEZ 			unsigned long *);
675f7aa907SGabriel FERNANDEZ };
685f7aa907SGabriel FERNANDEZ 
695dc1a127SAlain Volmat struct clkgen_clk_out {
705dc1a127SAlain Volmat 	const char *name;
715dc1a127SAlain Volmat 	unsigned long flags;
725dc1a127SAlain Volmat };
735dc1a127SAlain Volmat 
745dc1a127SAlain Volmat struct clkgen_quadfs_data_clks {
755dc1a127SAlain Volmat 	struct clkgen_quadfs_data *data;
765dc1a127SAlain Volmat 	const struct clkgen_clk_out *outputs;
775dc1a127SAlain Volmat };
785dc1a127SAlain Volmat 
795f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c32_ops;
805f7aa907SGabriel FERNANDEZ 
81b699f3e3SGabriel Fernandez static int clk_fs660c32_dig_get_params(unsigned long input,
82b699f3e3SGabriel Fernandez 		unsigned long output, struct stm_fs *fs);
834abb1b40SGabriel FERNANDEZ static int clk_fs660c32_dig_get_rate(unsigned long, const struct stm_fs *,
845f7aa907SGabriel FERNANDEZ 		unsigned long *);
855f7aa907SGabriel FERNANDEZ 
86d34e210eSGabriel Fernandez static const struct clkgen_quadfs_data st_fs660c32_C = {
8751306d56SGabriel FERNANDEZ 	.nrst_present = true,
8851306d56SGabriel FERNANDEZ 	.nrst	= { CLKGEN_FIELD(0x2f0, 0x1, 0),
8951306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2f0, 0x1, 1),
9051306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2f0, 0x1, 2),
9151306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2f0, 0x1, 3) },
9251306d56SGabriel FERNANDEZ 	.npda	= CLKGEN_FIELD(0x2f0, 0x1, 12),
9351306d56SGabriel FERNANDEZ 	.nsb	= { CLKGEN_FIELD(0x2f0, 0x1, 8),
9451306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2f0, 0x1, 9),
9551306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2f0, 0x1, 10),
9651306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2f0, 0x1, 11) },
9751306d56SGabriel FERNANDEZ 	.nsdiv_present = true,
9851306d56SGabriel FERNANDEZ 	.nsdiv	= { CLKGEN_FIELD(0x304, 0x1, 24),
9951306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x308, 0x1, 24),
10051306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x30c, 0x1, 24),
10151306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x310, 0x1, 24) },
10251306d56SGabriel FERNANDEZ 	.mdiv	= { CLKGEN_FIELD(0x304, 0x1f, 15),
10351306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x308, 0x1f, 15),
10451306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x30c, 0x1f, 15),
10551306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x310, 0x1f, 15) },
10651306d56SGabriel FERNANDEZ 	.en	= { CLKGEN_FIELD(0x2fc, 0x1, 0),
10751306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2fc, 0x1, 1),
10851306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2fc, 0x1, 2),
10951306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2fc, 0x1, 3) },
11051306d56SGabriel FERNANDEZ 	.ndiv	= CLKGEN_FIELD(0x2f4, 0x7, 16),
11151306d56SGabriel FERNANDEZ 	.pe	= { CLKGEN_FIELD(0x304, 0x7fff, 0),
11251306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x308, 0x7fff, 0),
11351306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x30c, 0x7fff, 0),
11451306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x310, 0x7fff, 0) },
11551306d56SGabriel FERNANDEZ 	.sdiv	= { CLKGEN_FIELD(0x304, 0xf, 20),
11651306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x308, 0xf, 20),
11751306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x30c, 0xf, 20),
11851306d56SGabriel FERNANDEZ 		    CLKGEN_FIELD(0x310, 0xf, 20) },
11951306d56SGabriel FERNANDEZ 	.lockstatus_present = true,
12056551da9SPankaj Dev 	.lock_status = CLKGEN_FIELD(0x2f0, 0x1, 24),
12151306d56SGabriel FERNANDEZ 	.powerup_polarity = 1,
12251306d56SGabriel FERNANDEZ 	.standby_polarity = 1,
12351306d56SGabriel FERNANDEZ 	.pll_ops	= &st_quadfs_pll_c32_ops,
124b699f3e3SGabriel Fernandez 	.get_params	= clk_fs660c32_dig_get_params,
12551306d56SGabriel FERNANDEZ 	.get_rate	= clk_fs660c32_dig_get_rate,
12651306d56SGabriel FERNANDEZ };
12751306d56SGabriel FERNANDEZ 
1285dc1a127SAlain Volmat static const struct clkgen_clk_out st_fs660c32_C_clks[] = {
1295dc1a127SAlain Volmat 	{ .name = "clk-s-c0-fs0-ch0",	},
1305dc1a127SAlain Volmat 	{ .name = "clk-s-c0-fs0-ch1",	},
1315dc1a127SAlain Volmat 	{ .name = "clk-s-c0-fs0-ch2",	},
1325dc1a127SAlain Volmat 	{ .name = "clk-s-c0-fs0-ch3",	},
1335dc1a127SAlain Volmat };
1345dc1a127SAlain Volmat 
1355dc1a127SAlain Volmat static const struct clkgen_quadfs_data_clks st_fs660c32_C_data = {
1365dc1a127SAlain Volmat 	.data	= (struct clkgen_quadfs_data *)&st_fs660c32_C,
1375dc1a127SAlain Volmat 	.outputs	= st_fs660c32_C_clks,
1385dc1a127SAlain Volmat };
1395dc1a127SAlain Volmat 
140d34e210eSGabriel Fernandez static const struct clkgen_quadfs_data st_fs660c32_D = {
14158de9b8eSGabriel FERNANDEZ 	.nrst_present = true,
14258de9b8eSGabriel FERNANDEZ 	.nrst	= { CLKGEN_FIELD(0x2a0, 0x1, 0),
14358de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2a0, 0x1, 1),
14458de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2a0, 0x1, 2),
14558de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2a0, 0x1, 3) },
14658de9b8eSGabriel FERNANDEZ 	.ndiv	= CLKGEN_FIELD(0x2a4, 0x7, 16),
14758de9b8eSGabriel FERNANDEZ 	.pe	= { CLKGEN_FIELD(0x2b4, 0x7fff, 0),
14858de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2b8, 0x7fff, 0),
14958de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2bc, 0x7fff, 0),
15058de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2c0, 0x7fff, 0) },
15158de9b8eSGabriel FERNANDEZ 	.sdiv	= { CLKGEN_FIELD(0x2b4, 0xf, 20),
15258de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2b8, 0xf, 20),
15358de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2bc, 0xf, 20),
15458de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2c0, 0xf, 20) },
15558de9b8eSGabriel FERNANDEZ 	.npda	= CLKGEN_FIELD(0x2a0, 0x1, 12),
15658de9b8eSGabriel FERNANDEZ 	.nsb	= { CLKGEN_FIELD(0x2a0, 0x1, 8),
15758de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2a0, 0x1, 9),
15858de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2a0, 0x1, 10),
15958de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2a0, 0x1, 11) },
16058de9b8eSGabriel FERNANDEZ 	.nsdiv_present = true,
16158de9b8eSGabriel FERNANDEZ 	.nsdiv	= { CLKGEN_FIELD(0x2b4, 0x1, 24),
16258de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2b8, 0x1, 24),
16358de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2bc, 0x1, 24),
16458de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2c0, 0x1, 24) },
16558de9b8eSGabriel FERNANDEZ 	.mdiv	= { CLKGEN_FIELD(0x2b4, 0x1f, 15),
16658de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2b8, 0x1f, 15),
16758de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2bc, 0x1f, 15),
16858de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2c0, 0x1f, 15) },
16958de9b8eSGabriel FERNANDEZ 	.en	= { CLKGEN_FIELD(0x2ac, 0x1, 0),
17058de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2ac, 0x1, 1),
17158de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2ac, 0x1, 2),
17258de9b8eSGabriel FERNANDEZ 		    CLKGEN_FIELD(0x2ac, 0x1, 3) },
17358de9b8eSGabriel FERNANDEZ 	.lockstatus_present = true,
17458de9b8eSGabriel FERNANDEZ 	.lock_status = CLKGEN_FIELD(0x2A0, 0x1, 24),
17558de9b8eSGabriel FERNANDEZ 	.powerup_polarity = 1,
17658de9b8eSGabriel FERNANDEZ 	.standby_polarity = 1,
17758de9b8eSGabriel FERNANDEZ 	.pll_ops	= &st_quadfs_pll_c32_ops,
178b699f3e3SGabriel Fernandez 	.get_params	= clk_fs660c32_dig_get_params,
17958de9b8eSGabriel FERNANDEZ 	.get_rate	= clk_fs660c32_dig_get_rate,};
18058de9b8eSGabriel FERNANDEZ 
1815dc1a127SAlain Volmat static const struct clkgen_quadfs_data_clks st_fs660c32_D_data = {
1825dc1a127SAlain Volmat 	.data	= (struct clkgen_quadfs_data *)&st_fs660c32_D,
1835dc1a127SAlain Volmat };
1845dc1a127SAlain Volmat 
1855dc1a127SAlain Volmat static const struct clkgen_clk_out st_fs660c32_D0_clks[] = {
1865dc1a127SAlain Volmat 	{ .name = "clk-s-d0-fs0-ch0",	},
1875dc1a127SAlain Volmat 	{ .name = "clk-s-d0-fs0-ch1",	},
1885dc1a127SAlain Volmat 	{ .name = "clk-s-d0-fs0-ch2",	},
1895dc1a127SAlain Volmat 	{ .name = "clk-s-d0-fs0-ch3",	},
1905dc1a127SAlain Volmat };
1915dc1a127SAlain Volmat 
1925dc1a127SAlain Volmat static const struct clkgen_quadfs_data_clks st_fs660c32_D0_data = {
1935dc1a127SAlain Volmat 	.data	= (struct clkgen_quadfs_data *)&st_fs660c32_D,
1945dc1a127SAlain Volmat 	.outputs	= st_fs660c32_D0_clks,
1955dc1a127SAlain Volmat };
1965dc1a127SAlain Volmat 
1975dc1a127SAlain Volmat static const struct clkgen_clk_out st_fs660c32_D2_clks[] = {
1985dc1a127SAlain Volmat 	{ .name = "clk-s-d2-fs0-ch0",	},
1995dc1a127SAlain Volmat 	{ .name = "clk-s-d2-fs0-ch1",	},
2005dc1a127SAlain Volmat 	{ .name = "clk-s-d2-fs0-ch2",	},
2015dc1a127SAlain Volmat 	{ .name = "clk-s-d2-fs0-ch3",	},
2025dc1a127SAlain Volmat };
2035dc1a127SAlain Volmat 
2045dc1a127SAlain Volmat static const struct clkgen_quadfs_data_clks st_fs660c32_D2_data = {
2055dc1a127SAlain Volmat 	.data	= (struct clkgen_quadfs_data *)&st_fs660c32_D,
2065dc1a127SAlain Volmat 	.outputs	= st_fs660c32_D2_clks,
2075dc1a127SAlain Volmat };
2085dc1a127SAlain Volmat 
2095dc1a127SAlain Volmat static const struct clkgen_clk_out st_fs660c32_D3_clks[] = {
2105dc1a127SAlain Volmat 	{ .name = "clk-s-d3-fs0-ch0",	},
2115dc1a127SAlain Volmat 	{ .name = "clk-s-d3-fs0-ch1",	},
2125dc1a127SAlain Volmat 	{ .name = "clk-s-d3-fs0-ch2",	},
2135dc1a127SAlain Volmat 	{ .name = "clk-s-d3-fs0-ch3",	},
2145dc1a127SAlain Volmat };
2155dc1a127SAlain Volmat 
2165dc1a127SAlain Volmat static const struct clkgen_quadfs_data_clks st_fs660c32_D3_data = {
2175dc1a127SAlain Volmat 	.data	= (struct clkgen_quadfs_data *)&st_fs660c32_D,
2185dc1a127SAlain Volmat 	.outputs	= st_fs660c32_D3_clks,
2195dc1a127SAlain Volmat };
2205dc1a127SAlain Volmat 
2215f7aa907SGabriel FERNANDEZ /**
2225f7aa907SGabriel FERNANDEZ  * DOC: A Frequency Synthesizer that multiples its input clock by a fixed factor
2235f7aa907SGabriel FERNANDEZ  *
2245f7aa907SGabriel FERNANDEZ  * Traits of this clock:
2255f7aa907SGabriel FERNANDEZ  * prepare - clk_(un)prepare only ensures parent is (un)prepared
2265f7aa907SGabriel FERNANDEZ  * enable - clk_enable and clk_disable are functional & control the Fsyn
2275f7aa907SGabriel FERNANDEZ  * rate - inherits rate from parent. set_rate/round_rate/recalc_rate
2285f7aa907SGabriel FERNANDEZ  * parent - fixed parent.  No clk_set_parent support
2295f7aa907SGabriel FERNANDEZ  */
2305f7aa907SGabriel FERNANDEZ 
2315f7aa907SGabriel FERNANDEZ /**
2325f7aa907SGabriel FERNANDEZ  * struct st_clk_quadfs_pll - A pll which outputs a fixed multiplier of
2335f7aa907SGabriel FERNANDEZ  *                                  its parent clock, found inside a type of
2345f7aa907SGabriel FERNANDEZ  *                                  ST quad channel frequency synthesizer block
2355f7aa907SGabriel FERNANDEZ  *
2365f7aa907SGabriel FERNANDEZ  * @hw: handle between common and hardware-specific interfaces.
2375f7aa907SGabriel FERNANDEZ  * @regs_base: base address of the configuration registers.
2385f7aa907SGabriel FERNANDEZ  * @lock: spinlock.
2394f71bdcbSLee Jones  * @data: local driver data
2404f71bdcbSLee Jones  * @ndiv: regmap field for the ndiv control.
2415f7aa907SGabriel FERNANDEZ  */
2425f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll {
2435f7aa907SGabriel FERNANDEZ 	struct clk_hw	hw;
2445f7aa907SGabriel FERNANDEZ 	void __iomem	*regs_base;
2455f7aa907SGabriel FERNANDEZ 	spinlock_t	*lock;
2465f7aa907SGabriel FERNANDEZ 	struct clkgen_quadfs_data *data;
2475f7aa907SGabriel FERNANDEZ 	u32 ndiv;
2485f7aa907SGabriel FERNANDEZ };
2495f7aa907SGabriel FERNANDEZ 
2505f7aa907SGabriel FERNANDEZ #define to_quadfs_pll(_hw) container_of(_hw, struct st_clk_quadfs_pll, hw)
2515f7aa907SGabriel FERNANDEZ 
quadfs_pll_enable(struct clk_hw * hw)2525f7aa907SGabriel FERNANDEZ static int quadfs_pll_enable(struct clk_hw *hw)
2535f7aa907SGabriel FERNANDEZ {
2545f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
2555f7aa907SGabriel FERNANDEZ 	unsigned long flags = 0, timeout = jiffies + msecs_to_jiffies(10);
2565f7aa907SGabriel FERNANDEZ 
2575f7aa907SGabriel FERNANDEZ 	if (pll->lock)
2585f7aa907SGabriel FERNANDEZ 		spin_lock_irqsave(pll->lock, flags);
2595f7aa907SGabriel FERNANDEZ 
2605f7aa907SGabriel FERNANDEZ 	/*
2615f7aa907SGabriel FERNANDEZ 	 * Bring block out of reset if we have reset control.
2625f7aa907SGabriel FERNANDEZ 	 */
2635f7aa907SGabriel FERNANDEZ 	if (pll->data->reset_present)
2645f7aa907SGabriel FERNANDEZ 		CLKGEN_WRITE(pll, nreset, 1);
2655f7aa907SGabriel FERNANDEZ 
2665f7aa907SGabriel FERNANDEZ 	/*
2675f7aa907SGabriel FERNANDEZ 	 * Use a fixed input clock noise bandwidth filter for the moment
2685f7aa907SGabriel FERNANDEZ 	 */
2695f7aa907SGabriel FERNANDEZ 	if (pll->data->bwfilter_present)
2705f7aa907SGabriel FERNANDEZ 		CLKGEN_WRITE(pll, ref_bw, PLL_BW_GOODREF);
2715f7aa907SGabriel FERNANDEZ 
2725f7aa907SGabriel FERNANDEZ 
2735f7aa907SGabriel FERNANDEZ 	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
2745f7aa907SGabriel FERNANDEZ 
2755f7aa907SGabriel FERNANDEZ 	/*
2765f7aa907SGabriel FERNANDEZ 	 * Power up the PLL
2775f7aa907SGabriel FERNANDEZ 	 */
2788f26df84SGabriel FERNANDEZ 	CLKGEN_WRITE(pll, npda, !pll->data->powerup_polarity);
2795f7aa907SGabriel FERNANDEZ 
2805f7aa907SGabriel FERNANDEZ 	if (pll->lock)
2815f7aa907SGabriel FERNANDEZ 		spin_unlock_irqrestore(pll->lock, flags);
2825f7aa907SGabriel FERNANDEZ 
2835f7aa907SGabriel FERNANDEZ 	if (pll->data->lockstatus_present)
2845f7aa907SGabriel FERNANDEZ 		while (!CLKGEN_READ(pll, lock_status)) {
2855f7aa907SGabriel FERNANDEZ 			if (time_after(jiffies, timeout))
2865f7aa907SGabriel FERNANDEZ 				return -ETIMEDOUT;
2875f7aa907SGabriel FERNANDEZ 			cpu_relax();
2885f7aa907SGabriel FERNANDEZ 		}
2895f7aa907SGabriel FERNANDEZ 
2905f7aa907SGabriel FERNANDEZ 	return 0;
2915f7aa907SGabriel FERNANDEZ }
2925f7aa907SGabriel FERNANDEZ 
quadfs_pll_disable(struct clk_hw * hw)2935f7aa907SGabriel FERNANDEZ static void quadfs_pll_disable(struct clk_hw *hw)
2945f7aa907SGabriel FERNANDEZ {
2955f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
2965f7aa907SGabriel FERNANDEZ 	unsigned long flags = 0;
2975f7aa907SGabriel FERNANDEZ 
2985f7aa907SGabriel FERNANDEZ 	if (pll->lock)
2995f7aa907SGabriel FERNANDEZ 		spin_lock_irqsave(pll->lock, flags);
3005f7aa907SGabriel FERNANDEZ 
3015f7aa907SGabriel FERNANDEZ 	/*
3025f7aa907SGabriel FERNANDEZ 	 * Powerdown the PLL and then put block into soft reset if we have
3035f7aa907SGabriel FERNANDEZ 	 * reset control.
3045f7aa907SGabriel FERNANDEZ 	 */
3058f26df84SGabriel FERNANDEZ 	CLKGEN_WRITE(pll, npda, pll->data->powerup_polarity);
3065f7aa907SGabriel FERNANDEZ 
3075f7aa907SGabriel FERNANDEZ 	if (pll->data->reset_present)
3085f7aa907SGabriel FERNANDEZ 		CLKGEN_WRITE(pll, nreset, 0);
3095f7aa907SGabriel FERNANDEZ 
3105f7aa907SGabriel FERNANDEZ 	if (pll->lock)
3115f7aa907SGabriel FERNANDEZ 		spin_unlock_irqrestore(pll->lock, flags);
3125f7aa907SGabriel FERNANDEZ }
3135f7aa907SGabriel FERNANDEZ 
quadfs_pll_is_enabled(struct clk_hw * hw)3145f7aa907SGabriel FERNANDEZ static int quadfs_pll_is_enabled(struct clk_hw *hw)
3155f7aa907SGabriel FERNANDEZ {
3165f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
3175f7aa907SGabriel FERNANDEZ 	u32 npda = CLKGEN_READ(pll, npda);
3185f7aa907SGabriel FERNANDEZ 
319c4d339c6SGabriel Fernandez 	return pll->data->powerup_polarity ? !npda : !!npda;
3205f7aa907SGabriel FERNANDEZ }
3215f7aa907SGabriel FERNANDEZ 
clk_fs660c32_vco_get_rate(unsigned long input,struct stm_fs * fs,unsigned long * rate)3228e6dd77cSStephen Boyd static int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs,
3235f7aa907SGabriel FERNANDEZ 			   unsigned long *rate)
3245f7aa907SGabriel FERNANDEZ {
3255f7aa907SGabriel FERNANDEZ 	unsigned long nd = fs->ndiv + 16; /* ndiv value */
3265f7aa907SGabriel FERNANDEZ 
3275f7aa907SGabriel FERNANDEZ 	*rate = input * nd;
3285f7aa907SGabriel FERNANDEZ 
3295f7aa907SGabriel FERNANDEZ 	return 0;
3305f7aa907SGabriel FERNANDEZ }
3315f7aa907SGabriel FERNANDEZ 
quadfs_pll_fs660c32_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)3325f7aa907SGabriel FERNANDEZ static unsigned long quadfs_pll_fs660c32_recalc_rate(struct clk_hw *hw,
3335f7aa907SGabriel FERNANDEZ 					unsigned long parent_rate)
3345f7aa907SGabriel FERNANDEZ {
3355f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
3365f7aa907SGabriel FERNANDEZ 	unsigned long rate = 0;
3375f7aa907SGabriel FERNANDEZ 	struct stm_fs params;
3385f7aa907SGabriel FERNANDEZ 
3395f7aa907SGabriel FERNANDEZ 	params.ndiv = CLKGEN_READ(pll, ndiv);
3405f7aa907SGabriel FERNANDEZ 	if (clk_fs660c32_vco_get_rate(parent_rate, &params, &rate))
3415f7aa907SGabriel FERNANDEZ 		pr_err("%s:%s error calculating rate\n",
342836ee0f7SStephen Boyd 		       clk_hw_get_name(hw), __func__);
3435f7aa907SGabriel FERNANDEZ 
3445f7aa907SGabriel FERNANDEZ 	pll->ndiv = params.ndiv;
3455f7aa907SGabriel FERNANDEZ 
3465f7aa907SGabriel FERNANDEZ 	return rate;
3475f7aa907SGabriel FERNANDEZ }
3485f7aa907SGabriel FERNANDEZ 
clk_fs660c32_vco_get_params(unsigned long input,unsigned long output,struct stm_fs * fs)3498e6dd77cSStephen Boyd static int clk_fs660c32_vco_get_params(unsigned long input,
3505f7aa907SGabriel FERNANDEZ 				unsigned long output, struct stm_fs *fs)
3515f7aa907SGabriel FERNANDEZ {
3525f7aa907SGabriel FERNANDEZ /* Formula
3535f7aa907SGabriel FERNANDEZ    VCO frequency = (fin x ndiv) / pdiv
3545f7aa907SGabriel FERNANDEZ    ndiv = VCOfreq * pdiv / fin
3555f7aa907SGabriel FERNANDEZ    */
3565f7aa907SGabriel FERNANDEZ 	unsigned long pdiv = 1, n;
3575f7aa907SGabriel FERNANDEZ 
3585f7aa907SGabriel FERNANDEZ 	/* Output clock range: 384Mhz to 660Mhz */
3595f7aa907SGabriel FERNANDEZ 	if (output < 384000000 || output > 660000000)
3605f7aa907SGabriel FERNANDEZ 		return -EINVAL;
3615f7aa907SGabriel FERNANDEZ 
3625f7aa907SGabriel FERNANDEZ 	if (input > 40000000)
3635f7aa907SGabriel FERNANDEZ 		/* This means that PDIV would be 2 instead of 1.
3645f7aa907SGabriel FERNANDEZ 		   Not supported today. */
3655f7aa907SGabriel FERNANDEZ 		return -EINVAL;
3665f7aa907SGabriel FERNANDEZ 
3675f7aa907SGabriel FERNANDEZ 	input /= 1000;
3685f7aa907SGabriel FERNANDEZ 	output /= 1000;
3695f7aa907SGabriel FERNANDEZ 
3705f7aa907SGabriel FERNANDEZ 	n = output * pdiv / input;
3715f7aa907SGabriel FERNANDEZ 	if (n < 16)
3725f7aa907SGabriel FERNANDEZ 		n = 16;
3735f7aa907SGabriel FERNANDEZ 	fs->ndiv = n - 16; /* Converting formula value to reg value */
3745f7aa907SGabriel FERNANDEZ 
3755f7aa907SGabriel FERNANDEZ 	return 0;
3765f7aa907SGabriel FERNANDEZ }
3775f7aa907SGabriel FERNANDEZ 
quadfs_pll_fs660c32_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)3782dd52d7fSArnd Bergmann static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw,
3792dd52d7fSArnd Bergmann 					   unsigned long rate,
3802dd52d7fSArnd Bergmann 					   unsigned long *prate)
3815f7aa907SGabriel FERNANDEZ {
3825f7aa907SGabriel FERNANDEZ 	struct stm_fs params;
3835f7aa907SGabriel FERNANDEZ 
3842dd52d7fSArnd Bergmann 	if (clk_fs660c32_vco_get_params(*prate, rate, &params))
3852dd52d7fSArnd Bergmann 		return rate;
3862dd52d7fSArnd Bergmann 
3875f7aa907SGabriel FERNANDEZ 	clk_fs660c32_vco_get_rate(*prate, &params, &rate);
3885f7aa907SGabriel FERNANDEZ 
3892dd52d7fSArnd Bergmann 	pr_debug("%s: %s new rate %ld [ndiv=%u]\n",
390836ee0f7SStephen Boyd 		 __func__, clk_hw_get_name(hw),
3912dd52d7fSArnd Bergmann 		 rate, (unsigned int)params.ndiv);
3925f7aa907SGabriel FERNANDEZ 
3935f7aa907SGabriel FERNANDEZ 	return rate;
3945f7aa907SGabriel FERNANDEZ }
3955f7aa907SGabriel FERNANDEZ 
quadfs_pll_fs660c32_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)3965f7aa907SGabriel FERNANDEZ static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate,
3975f7aa907SGabriel FERNANDEZ 				unsigned long parent_rate)
3985f7aa907SGabriel FERNANDEZ {
3995f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw);
4005f7aa907SGabriel FERNANDEZ 	struct stm_fs params;
4015f7aa907SGabriel FERNANDEZ 	long hwrate = 0;
4025f7aa907SGabriel FERNANDEZ 	unsigned long flags = 0;
4039849fadfSArnd Bergmann 	int ret;
4045f7aa907SGabriel FERNANDEZ 
4055f7aa907SGabriel FERNANDEZ 	if (!rate || !parent_rate)
4065f7aa907SGabriel FERNANDEZ 		return -EINVAL;
4075f7aa907SGabriel FERNANDEZ 
4089849fadfSArnd Bergmann 	ret = clk_fs660c32_vco_get_params(parent_rate, rate, &params);
4099849fadfSArnd Bergmann 	if (ret)
4109849fadfSArnd Bergmann 		return ret;
4119849fadfSArnd Bergmann 
4125f7aa907SGabriel FERNANDEZ 	clk_fs660c32_vco_get_rate(parent_rate, &params, &hwrate);
4135f7aa907SGabriel FERNANDEZ 
4145f7aa907SGabriel FERNANDEZ 	pr_debug("%s: %s new rate %ld [ndiv=0x%x]\n",
415836ee0f7SStephen Boyd 		 __func__, clk_hw_get_name(hw),
4165f7aa907SGabriel FERNANDEZ 		 hwrate, (unsigned int)params.ndiv);
4175f7aa907SGabriel FERNANDEZ 
4185f7aa907SGabriel FERNANDEZ 	if (!hwrate)
4195f7aa907SGabriel FERNANDEZ 		return -EINVAL;
4205f7aa907SGabriel FERNANDEZ 
4215f7aa907SGabriel FERNANDEZ 	pll->ndiv = params.ndiv;
4225f7aa907SGabriel FERNANDEZ 
4235f7aa907SGabriel FERNANDEZ 	if (pll->lock)
4245f7aa907SGabriel FERNANDEZ 		spin_lock_irqsave(pll->lock, flags);
4255f7aa907SGabriel FERNANDEZ 
4265f7aa907SGabriel FERNANDEZ 	CLKGEN_WRITE(pll, ndiv, pll->ndiv);
4275f7aa907SGabriel FERNANDEZ 
4285f7aa907SGabriel FERNANDEZ 	if (pll->lock)
4295f7aa907SGabriel FERNANDEZ 		spin_unlock_irqrestore(pll->lock, flags);
4305f7aa907SGabriel FERNANDEZ 
4315f7aa907SGabriel FERNANDEZ 	return 0;
4325f7aa907SGabriel FERNANDEZ }
4335f7aa907SGabriel FERNANDEZ 
4345f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c32_ops = {
4355f7aa907SGabriel FERNANDEZ 	.enable		= quadfs_pll_enable,
4365f7aa907SGabriel FERNANDEZ 	.disable	= quadfs_pll_disable,
4375f7aa907SGabriel FERNANDEZ 	.is_enabled	= quadfs_pll_is_enabled,
4385f7aa907SGabriel FERNANDEZ 	.recalc_rate	= quadfs_pll_fs660c32_recalc_rate,
4395f7aa907SGabriel FERNANDEZ 	.round_rate	= quadfs_pll_fs660c32_round_rate,
4405f7aa907SGabriel FERNANDEZ 	.set_rate	= quadfs_pll_fs660c32_set_rate,
4415f7aa907SGabriel FERNANDEZ };
4425f7aa907SGabriel FERNANDEZ 
st_clk_register_quadfs_pll(const char * name,const char * parent_name,struct clkgen_quadfs_data * quadfs,void __iomem * reg,spinlock_t * lock)4435f7aa907SGabriel FERNANDEZ static struct clk * __init st_clk_register_quadfs_pll(
4445f7aa907SGabriel FERNANDEZ 		const char *name, const char *parent_name,
4455f7aa907SGabriel FERNANDEZ 		struct clkgen_quadfs_data *quadfs, void __iomem *reg,
4465f7aa907SGabriel FERNANDEZ 		spinlock_t *lock)
4475f7aa907SGabriel FERNANDEZ {
4485f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_pll *pll;
4495f7aa907SGabriel FERNANDEZ 	struct clk *clk;
4505f7aa907SGabriel FERNANDEZ 	struct clk_init_data init;
4515f7aa907SGabriel FERNANDEZ 
4525f7aa907SGabriel FERNANDEZ 	/*
4535f7aa907SGabriel FERNANDEZ 	 * Sanity check required pointers.
4545f7aa907SGabriel FERNANDEZ 	 */
4555f7aa907SGabriel FERNANDEZ 	if (WARN_ON(!name || !parent_name))
4565f7aa907SGabriel FERNANDEZ 		return ERR_PTR(-EINVAL);
4575f7aa907SGabriel FERNANDEZ 
4585f7aa907SGabriel FERNANDEZ 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
4595f7aa907SGabriel FERNANDEZ 	if (!pll)
4605f7aa907SGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
4615f7aa907SGabriel FERNANDEZ 
4625f7aa907SGabriel FERNANDEZ 	init.name = name;
4635f7aa907SGabriel FERNANDEZ 	init.ops = quadfs->pll_ops;
464c179c21eSStephen Boyd 	init.flags = CLK_GET_RATE_NOCACHE;
4655f7aa907SGabriel FERNANDEZ 	init.parent_names = &parent_name;
4665f7aa907SGabriel FERNANDEZ 	init.num_parents = 1;
4675f7aa907SGabriel FERNANDEZ 
4685f7aa907SGabriel FERNANDEZ 	pll->data = quadfs;
4695f7aa907SGabriel FERNANDEZ 	pll->regs_base = reg;
4705f7aa907SGabriel FERNANDEZ 	pll->lock = lock;
4715f7aa907SGabriel FERNANDEZ 	pll->hw.init = &init;
4725f7aa907SGabriel FERNANDEZ 
4735f7aa907SGabriel FERNANDEZ 	clk = clk_register(NULL, &pll->hw);
4745f7aa907SGabriel FERNANDEZ 
4755f7aa907SGabriel FERNANDEZ 	if (IS_ERR(clk))
4765f7aa907SGabriel FERNANDEZ 		kfree(pll);
4775f7aa907SGabriel FERNANDEZ 
4785f7aa907SGabriel FERNANDEZ 	return clk;
4795f7aa907SGabriel FERNANDEZ }
4805f7aa907SGabriel FERNANDEZ 
4815f7aa907SGabriel FERNANDEZ /**
4825f7aa907SGabriel FERNANDEZ  * DOC: A digital frequency synthesizer
4835f7aa907SGabriel FERNANDEZ  *
4845f7aa907SGabriel FERNANDEZ  * Traits of this clock:
4855f7aa907SGabriel FERNANDEZ  * prepare - clk_(un)prepare only ensures parent is (un)prepared
4865f7aa907SGabriel FERNANDEZ  * enable - clk_enable and clk_disable are functional
4875f7aa907SGabriel FERNANDEZ  * rate - set rate is functional
4885f7aa907SGabriel FERNANDEZ  * parent - fixed parent.  No clk_set_parent support
4895f7aa907SGabriel FERNANDEZ  */
4905f7aa907SGabriel FERNANDEZ 
4914f71bdcbSLee Jones /*
4925f7aa907SGabriel FERNANDEZ  * struct st_clk_quadfs_fsynth - One clock output from a four channel digital
4935f7aa907SGabriel FERNANDEZ  *                                  frequency synthesizer (fsynth) block.
4945f7aa907SGabriel FERNANDEZ  *
4955f7aa907SGabriel FERNANDEZ  * @hw: handle between common and hardware-specific interfaces
4965f7aa907SGabriel FERNANDEZ  *
4975f7aa907SGabriel FERNANDEZ  * @nsb: regmap field in the output control register for the digital
4985f7aa907SGabriel FERNANDEZ  *       standby of this fsynth channel. This control is active low so
4995f7aa907SGabriel FERNANDEZ  *       the channel is in standby when the control bit is cleared.
5005f7aa907SGabriel FERNANDEZ  *
5015f7aa907SGabriel FERNANDEZ  * @nsdiv: regmap field in the output control register for
5025f7aa907SGabriel FERNANDEZ  *          for the optional divide by 3 of this fsynth channel. This control
5035f7aa907SGabriel FERNANDEZ  *          is active low so the divide by 3 is active when the control bit is
5045f7aa907SGabriel FERNANDEZ  *          cleared and the divide is bypassed when the bit is set.
5055f7aa907SGabriel FERNANDEZ  */
5065f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth {
5075f7aa907SGabriel FERNANDEZ 	struct clk_hw	hw;
5085f7aa907SGabriel FERNANDEZ 	void __iomem	*regs_base;
5095f7aa907SGabriel FERNANDEZ 	spinlock_t	*lock;
5105f7aa907SGabriel FERNANDEZ 	struct clkgen_quadfs_data *data;
5115f7aa907SGabriel FERNANDEZ 
5125f7aa907SGabriel FERNANDEZ 	u32 chan;
5135f7aa907SGabriel FERNANDEZ 	/*
5145f7aa907SGabriel FERNANDEZ 	 * Cached hardware values from set_rate so we can program the
5155f7aa907SGabriel FERNANDEZ 	 * hardware in enable. There are two reasons for this:
5165f7aa907SGabriel FERNANDEZ 	 *
5175f7aa907SGabriel FERNANDEZ 	 *  1. The registers may not be writable until the parent has been
5185f7aa907SGabriel FERNANDEZ 	 *     enabled.
5195f7aa907SGabriel FERNANDEZ 	 *
5205f7aa907SGabriel FERNANDEZ 	 *  2. It restores the clock rate when a driver does an enable
5215f7aa907SGabriel FERNANDEZ 	 *     on PM restore, after a suspend to RAM has lost the hardware
5225f7aa907SGabriel FERNANDEZ 	 *     setup.
5235f7aa907SGabriel FERNANDEZ 	 */
5245f7aa907SGabriel FERNANDEZ 	u32 md;
5255f7aa907SGabriel FERNANDEZ 	u32 pe;
5265f7aa907SGabriel FERNANDEZ 	u32 sdiv;
5275f7aa907SGabriel FERNANDEZ 	u32 nsdiv;
5285f7aa907SGabriel FERNANDEZ };
5295f7aa907SGabriel FERNANDEZ 
5305f7aa907SGabriel FERNANDEZ #define to_quadfs_fsynth(_hw) \
5315f7aa907SGabriel FERNANDEZ 	container_of(_hw, struct st_clk_quadfs_fsynth, hw)
5325f7aa907SGabriel FERNANDEZ 
quadfs_fsynth_program_enable(struct st_clk_quadfs_fsynth * fs)5335f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_program_enable(struct st_clk_quadfs_fsynth *fs)
5345f7aa907SGabriel FERNANDEZ {
5355f7aa907SGabriel FERNANDEZ 	/*
5365f7aa907SGabriel FERNANDEZ 	 * Pulse the program enable register lsb to make the hardware take
5375f7aa907SGabriel FERNANDEZ 	 * notice of the new md/pe values with a glitchless transition.
5385f7aa907SGabriel FERNANDEZ 	 */
5395f7aa907SGabriel FERNANDEZ 	CLKGEN_WRITE(fs, en[fs->chan], 1);
5405f7aa907SGabriel FERNANDEZ 	CLKGEN_WRITE(fs, en[fs->chan], 0);
5415f7aa907SGabriel FERNANDEZ }
5425f7aa907SGabriel FERNANDEZ 
quadfs_fsynth_program_rate(struct st_clk_quadfs_fsynth * fs)5435f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_program_rate(struct st_clk_quadfs_fsynth *fs)
5445f7aa907SGabriel FERNANDEZ {
5455f7aa907SGabriel FERNANDEZ 	unsigned long flags = 0;
5465f7aa907SGabriel FERNANDEZ 
5475f7aa907SGabriel FERNANDEZ 	/*
5485f7aa907SGabriel FERNANDEZ 	 * Ensure the md/pe parameters are ignored while we are
5495f7aa907SGabriel FERNANDEZ 	 * reprogramming them so we can get a glitchless change
5505f7aa907SGabriel FERNANDEZ 	 * when fine tuning the speed of a running clock.
5515f7aa907SGabriel FERNANDEZ 	 */
5525f7aa907SGabriel FERNANDEZ 	CLKGEN_WRITE(fs, en[fs->chan], 0);
5535f7aa907SGabriel FERNANDEZ 
5545f7aa907SGabriel FERNANDEZ 	CLKGEN_WRITE(fs, mdiv[fs->chan], fs->md);
5555f7aa907SGabriel FERNANDEZ 	CLKGEN_WRITE(fs, pe[fs->chan], fs->pe);
5565f7aa907SGabriel FERNANDEZ 	CLKGEN_WRITE(fs, sdiv[fs->chan], fs->sdiv);
5575f7aa907SGabriel FERNANDEZ 
5585f7aa907SGabriel FERNANDEZ 	if (fs->lock)
5595f7aa907SGabriel FERNANDEZ 		spin_lock_irqsave(fs->lock, flags);
5605f7aa907SGabriel FERNANDEZ 
5615f7aa907SGabriel FERNANDEZ 	if (fs->data->nsdiv_present)
5625f7aa907SGabriel FERNANDEZ 		CLKGEN_WRITE(fs, nsdiv[fs->chan], fs->nsdiv);
5635f7aa907SGabriel FERNANDEZ 
5645f7aa907SGabriel FERNANDEZ 	if (fs->lock)
5655f7aa907SGabriel FERNANDEZ 		spin_unlock_irqrestore(fs->lock, flags);
5665f7aa907SGabriel FERNANDEZ }
5675f7aa907SGabriel FERNANDEZ 
quadfs_fsynth_enable(struct clk_hw * hw)5685f7aa907SGabriel FERNANDEZ static int quadfs_fsynth_enable(struct clk_hw *hw)
5695f7aa907SGabriel FERNANDEZ {
5705f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
5715f7aa907SGabriel FERNANDEZ 	unsigned long flags = 0;
5725f7aa907SGabriel FERNANDEZ 
573836ee0f7SStephen Boyd 	pr_debug("%s: %s\n", __func__, clk_hw_get_name(hw));
5745f7aa907SGabriel FERNANDEZ 
5755f7aa907SGabriel FERNANDEZ 	quadfs_fsynth_program_rate(fs);
5765f7aa907SGabriel FERNANDEZ 
5775f7aa907SGabriel FERNANDEZ 	if (fs->lock)
5785f7aa907SGabriel FERNANDEZ 		spin_lock_irqsave(fs->lock, flags);
5795f7aa907SGabriel FERNANDEZ 
5808f26df84SGabriel FERNANDEZ 	CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity);
5815f7aa907SGabriel FERNANDEZ 
582fc755c8bSGabriel FERNANDEZ 	if (fs->data->nrst_present)
583fc755c8bSGabriel FERNANDEZ 		CLKGEN_WRITE(fs, nrst[fs->chan], 0);
584fc755c8bSGabriel FERNANDEZ 
5855f7aa907SGabriel FERNANDEZ 	if (fs->lock)
5865f7aa907SGabriel FERNANDEZ 		spin_unlock_irqrestore(fs->lock, flags);
5875f7aa907SGabriel FERNANDEZ 
5885f7aa907SGabriel FERNANDEZ 	quadfs_fsynth_program_enable(fs);
5895f7aa907SGabriel FERNANDEZ 
5905f7aa907SGabriel FERNANDEZ 	return 0;
5915f7aa907SGabriel FERNANDEZ }
5925f7aa907SGabriel FERNANDEZ 
quadfs_fsynth_disable(struct clk_hw * hw)5935f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_disable(struct clk_hw *hw)
5945f7aa907SGabriel FERNANDEZ {
5955f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
5965f7aa907SGabriel FERNANDEZ 	unsigned long flags = 0;
5975f7aa907SGabriel FERNANDEZ 
598836ee0f7SStephen Boyd 	pr_debug("%s: %s\n", __func__, clk_hw_get_name(hw));
5995f7aa907SGabriel FERNANDEZ 
6005f7aa907SGabriel FERNANDEZ 	if (fs->lock)
6015f7aa907SGabriel FERNANDEZ 		spin_lock_irqsave(fs->lock, flags);
6025f7aa907SGabriel FERNANDEZ 
603c4d339c6SGabriel Fernandez 	CLKGEN_WRITE(fs, nsb[fs->chan], fs->data->standby_polarity);
6045f7aa907SGabriel FERNANDEZ 
6055f7aa907SGabriel FERNANDEZ 	if (fs->lock)
6065f7aa907SGabriel FERNANDEZ 		spin_unlock_irqrestore(fs->lock, flags);
6075f7aa907SGabriel FERNANDEZ }
6085f7aa907SGabriel FERNANDEZ 
quadfs_fsynth_is_enabled(struct clk_hw * hw)6095f7aa907SGabriel FERNANDEZ static int quadfs_fsynth_is_enabled(struct clk_hw *hw)
6105f7aa907SGabriel FERNANDEZ {
6115f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
6125f7aa907SGabriel FERNANDEZ 	u32 nsb = CLKGEN_READ(fs, nsb[fs->chan]);
6135f7aa907SGabriel FERNANDEZ 
6145f7aa907SGabriel FERNANDEZ 	pr_debug("%s: %s enable bit = 0x%x\n",
615836ee0f7SStephen Boyd 		 __func__, clk_hw_get_name(hw), nsb);
6165f7aa907SGabriel FERNANDEZ 
6178f26df84SGabriel FERNANDEZ 	return fs->data->standby_polarity ? !nsb : !!nsb;
6185f7aa907SGabriel FERNANDEZ }
6195f7aa907SGabriel FERNANDEZ 
6205f7aa907SGabriel FERNANDEZ #define P20		(uint64_t)(1 << 20)
6215f7aa907SGabriel FERNANDEZ 
clk_fs660c32_dig_get_rate(unsigned long input,const struct stm_fs * fs,unsigned long * rate)6225f7aa907SGabriel FERNANDEZ static int clk_fs660c32_dig_get_rate(unsigned long input,
6234abb1b40SGabriel FERNANDEZ 				const struct stm_fs *fs, unsigned long *rate)
6245f7aa907SGabriel FERNANDEZ {
6255f7aa907SGabriel FERNANDEZ 	unsigned long s = (1 << fs->sdiv);
6265f7aa907SGabriel FERNANDEZ 	unsigned long ns;
6275f7aa907SGabriel FERNANDEZ 	uint64_t res;
6285f7aa907SGabriel FERNANDEZ 
6295f7aa907SGabriel FERNANDEZ 	/*
6305f7aa907SGabriel FERNANDEZ 	 * 'nsdiv' is a register value ('BIN') which is translated
6315f7aa907SGabriel FERNANDEZ 	 * to a decimal value according to following rules.
6325f7aa907SGabriel FERNANDEZ 	 *
6335f7aa907SGabriel FERNANDEZ 	 *     nsdiv      ns.dec
6345f7aa907SGabriel FERNANDEZ 	 *       0        3
6355f7aa907SGabriel FERNANDEZ 	 *       1        1
6365f7aa907SGabriel FERNANDEZ 	 */
6375f7aa907SGabriel FERNANDEZ 	ns = (fs->nsdiv == 1) ? 1 : 3;
6385f7aa907SGabriel FERNANDEZ 
6395f7aa907SGabriel FERNANDEZ 	res = (P20 * (32 + fs->mdiv) + 32 * fs->pe) * s * ns;
6405f7aa907SGabriel FERNANDEZ 	*rate = (unsigned long)div64_u64(input * P20 * 32, res);
6415f7aa907SGabriel FERNANDEZ 
6425f7aa907SGabriel FERNANDEZ 	return 0;
6435f7aa907SGabriel FERNANDEZ }
6445f7aa907SGabriel FERNANDEZ 
645b699f3e3SGabriel Fernandez 
clk_fs660c32_get_pe(int m,int si,unsigned long * deviation,signed long input,unsigned long output,uint64_t * p,struct stm_fs * fs)646b699f3e3SGabriel Fernandez static int clk_fs660c32_get_pe(int m, int si, unsigned long *deviation,
647b699f3e3SGabriel Fernandez 		signed long input, unsigned long output, uint64_t *p,
648b699f3e3SGabriel Fernandez 		struct stm_fs *fs)
649b699f3e3SGabriel Fernandez {
650b699f3e3SGabriel Fernandez 	unsigned long new_freq, new_deviation;
651b699f3e3SGabriel Fernandez 	struct stm_fs fs_tmp;
652b699f3e3SGabriel Fernandez 	uint64_t val;
653b699f3e3SGabriel Fernandez 
654b699f3e3SGabriel Fernandez 	val = (uint64_t)output << si;
655b699f3e3SGabriel Fernandez 
656b699f3e3SGabriel Fernandez 	*p = (uint64_t)input * P20 - (32LL  + (uint64_t)m) * val * (P20 / 32LL);
657b699f3e3SGabriel Fernandez 
658b699f3e3SGabriel Fernandez 	*p = div64_u64(*p, val);
659b699f3e3SGabriel Fernandez 
660b699f3e3SGabriel Fernandez 	if (*p > 32767LL)
661b699f3e3SGabriel Fernandez 		return 1;
662b699f3e3SGabriel Fernandez 
663b699f3e3SGabriel Fernandez 	fs_tmp.mdiv = (unsigned long) m;
664b699f3e3SGabriel Fernandez 	fs_tmp.pe = (unsigned long)*p;
665b699f3e3SGabriel Fernandez 	fs_tmp.sdiv = si;
666b699f3e3SGabriel Fernandez 	fs_tmp.nsdiv = 1;
667b699f3e3SGabriel Fernandez 
668b699f3e3SGabriel Fernandez 	clk_fs660c32_dig_get_rate(input, &fs_tmp, &new_freq);
669b699f3e3SGabriel Fernandez 
670b699f3e3SGabriel Fernandez 	new_deviation = abs(output - new_freq);
671b699f3e3SGabriel Fernandez 
672b699f3e3SGabriel Fernandez 	if (new_deviation < *deviation) {
673b699f3e3SGabriel Fernandez 		fs->mdiv = m;
674b699f3e3SGabriel Fernandez 		fs->pe = (unsigned long)*p;
675b699f3e3SGabriel Fernandez 		fs->sdiv = si;
676b699f3e3SGabriel Fernandez 		fs->nsdiv = 1;
677b699f3e3SGabriel Fernandez 		*deviation = new_deviation;
678b699f3e3SGabriel Fernandez 	}
679b699f3e3SGabriel Fernandez 	return 0;
680b699f3e3SGabriel Fernandez }
681b699f3e3SGabriel Fernandez 
clk_fs660c32_dig_get_params(unsigned long input,unsigned long output,struct stm_fs * fs)682b699f3e3SGabriel Fernandez static int clk_fs660c32_dig_get_params(unsigned long input,
683b699f3e3SGabriel Fernandez 		unsigned long output, struct stm_fs *fs)
684b699f3e3SGabriel Fernandez {
685b699f3e3SGabriel Fernandez 	int si;	/* sdiv_reg (8 downto 0) */
686b699f3e3SGabriel Fernandez 	int m; /* md value */
687b699f3e3SGabriel Fernandez 	unsigned long new_freq, new_deviation;
688b699f3e3SGabriel Fernandez 	/* initial condition to say: "infinite deviation" */
689b699f3e3SGabriel Fernandez 	unsigned long deviation = ~0;
690b699f3e3SGabriel Fernandez 	uint64_t p, p1, p2;	/* pe value */
691b699f3e3SGabriel Fernandez 	int r1, r2;
692b699f3e3SGabriel Fernandez 
693b699f3e3SGabriel Fernandez 	struct stm_fs fs_tmp;
694b699f3e3SGabriel Fernandez 
695b699f3e3SGabriel Fernandez 	for (si = 0; (si <= 8) && deviation; si++) {
696b699f3e3SGabriel Fernandez 
697b699f3e3SGabriel Fernandez 		/* Boundary test to avoid useless iteration */
698b699f3e3SGabriel Fernandez 		r1 = clk_fs660c32_get_pe(0, si, &deviation,
699b699f3e3SGabriel Fernandez 				input, output, &p1, fs);
700b699f3e3SGabriel Fernandez 		r2 = clk_fs660c32_get_pe(31, si, &deviation,
701b699f3e3SGabriel Fernandez 				input, output, &p2, fs);
702b699f3e3SGabriel Fernandez 
703b699f3e3SGabriel Fernandez 		/* No solution */
704b699f3e3SGabriel Fernandez 		if (r1 && r2 && (p1 > p2))
705b699f3e3SGabriel Fernandez 			continue;
706b699f3e3SGabriel Fernandez 
707b699f3e3SGabriel Fernandez 		/* Try to find best deviation */
708b699f3e3SGabriel Fernandez 		for (m = 1; (m < 31) && deviation; m++)
709b699f3e3SGabriel Fernandez 			clk_fs660c32_get_pe(m, si, &deviation,
710b699f3e3SGabriel Fernandez 					input, output, &p, fs);
711b699f3e3SGabriel Fernandez 
712b699f3e3SGabriel Fernandez 	}
713b699f3e3SGabriel Fernandez 
714b699f3e3SGabriel Fernandez 	if (deviation == ~0) /* No solution found */
715b699f3e3SGabriel Fernandez 		return -1;
716b699f3e3SGabriel Fernandez 
717b699f3e3SGabriel Fernandez 	/* pe fine tuning if deviation not 0: +/- 2 around computed pe value */
718b699f3e3SGabriel Fernandez 	if (deviation) {
719b699f3e3SGabriel Fernandez 		fs_tmp.mdiv = fs->mdiv;
720b699f3e3SGabriel Fernandez 		fs_tmp.sdiv = fs->sdiv;
721b699f3e3SGabriel Fernandez 		fs_tmp.nsdiv = fs->nsdiv;
722b699f3e3SGabriel Fernandez 
723b699f3e3SGabriel Fernandez 		if (fs->pe > 2)
724b699f3e3SGabriel Fernandez 			p2 = fs->pe - 2;
725b699f3e3SGabriel Fernandez 		else
726b699f3e3SGabriel Fernandez 			p2 = 0;
727b699f3e3SGabriel Fernandez 
728b699f3e3SGabriel Fernandez 		for (; p2 < 32768ll && (p2 <= (fs->pe + 2)); p2++) {
729b699f3e3SGabriel Fernandez 			fs_tmp.pe = (unsigned long)p2;
730b699f3e3SGabriel Fernandez 
731b699f3e3SGabriel Fernandez 			clk_fs660c32_dig_get_rate(input, &fs_tmp, &new_freq);
732b699f3e3SGabriel Fernandez 
733b699f3e3SGabriel Fernandez 			new_deviation = abs(output - new_freq);
734b699f3e3SGabriel Fernandez 
735b699f3e3SGabriel Fernandez 			/* Check if this is a better solution */
736b699f3e3SGabriel Fernandez 			if (new_deviation < deviation) {
737b699f3e3SGabriel Fernandez 				fs->pe = (unsigned long)p2;
738b699f3e3SGabriel Fernandez 				deviation = new_deviation;
739b699f3e3SGabriel Fernandez 
740b699f3e3SGabriel Fernandez 			}
741b699f3e3SGabriel Fernandez 		}
742b699f3e3SGabriel Fernandez 	}
743b699f3e3SGabriel Fernandez 	return 0;
744b699f3e3SGabriel Fernandez }
745b699f3e3SGabriel Fernandez 
quadfs_fsynt_get_hw_value_for_recalc(struct st_clk_quadfs_fsynth * fs,struct stm_fs * params)7465f7aa907SGabriel FERNANDEZ static int quadfs_fsynt_get_hw_value_for_recalc(struct st_clk_quadfs_fsynth *fs,
7475f7aa907SGabriel FERNANDEZ 		struct stm_fs *params)
7485f7aa907SGabriel FERNANDEZ {
7495f7aa907SGabriel FERNANDEZ 	/*
7505f7aa907SGabriel FERNANDEZ 	 * Get the initial hardware values for recalc_rate
7515f7aa907SGabriel FERNANDEZ 	 */
7525f7aa907SGabriel FERNANDEZ 	params->mdiv	= CLKGEN_READ(fs, mdiv[fs->chan]);
7535f7aa907SGabriel FERNANDEZ 	params->pe	= CLKGEN_READ(fs, pe[fs->chan]);
7545f7aa907SGabriel FERNANDEZ 	params->sdiv	= CLKGEN_READ(fs, sdiv[fs->chan]);
7555f7aa907SGabriel FERNANDEZ 
7565f7aa907SGabriel FERNANDEZ 	if (fs->data->nsdiv_present)
7575f7aa907SGabriel FERNANDEZ 		params->nsdiv = CLKGEN_READ(fs, nsdiv[fs->chan]);
7585f7aa907SGabriel FERNANDEZ 	else
7595f7aa907SGabriel FERNANDEZ 		params->nsdiv = 1;
7605f7aa907SGabriel FERNANDEZ 
7615f7aa907SGabriel FERNANDEZ 	/*
7625f7aa907SGabriel FERNANDEZ 	 * If All are NULL then assume no clock rate is programmed.
7635f7aa907SGabriel FERNANDEZ 	 */
7645f7aa907SGabriel FERNANDEZ 	if (!params->mdiv && !params->pe && !params->sdiv)
7655f7aa907SGabriel FERNANDEZ 		return 1;
7665f7aa907SGabriel FERNANDEZ 
7675f7aa907SGabriel FERNANDEZ 	fs->md = params->mdiv;
7685f7aa907SGabriel FERNANDEZ 	fs->pe = params->pe;
7695f7aa907SGabriel FERNANDEZ 	fs->sdiv = params->sdiv;
7705f7aa907SGabriel FERNANDEZ 	fs->nsdiv = params->nsdiv;
7715f7aa907SGabriel FERNANDEZ 
7725f7aa907SGabriel FERNANDEZ 	return 0;
7735f7aa907SGabriel FERNANDEZ }
7745f7aa907SGabriel FERNANDEZ 
quadfs_find_best_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate,struct stm_fs * params)7755f7aa907SGabriel FERNANDEZ static long quadfs_find_best_rate(struct clk_hw *hw, unsigned long drate,
7765f7aa907SGabriel FERNANDEZ 				unsigned long prate, struct stm_fs *params)
7775f7aa907SGabriel FERNANDEZ {
7785f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
7795f7aa907SGabriel FERNANDEZ 	int (*clk_fs_get_rate)(unsigned long ,
7804abb1b40SGabriel FERNANDEZ 				const struct stm_fs *, unsigned long *);
781b699f3e3SGabriel Fernandez 	int (*clk_fs_get_params)(unsigned long, unsigned long, struct stm_fs *);
782b699f3e3SGabriel Fernandez 	unsigned long rate = 0;
7835f7aa907SGabriel FERNANDEZ 
7845f7aa907SGabriel FERNANDEZ 	clk_fs_get_rate = fs->data->get_rate;
785b699f3e3SGabriel Fernandez 	clk_fs_get_params = fs->data->get_params;
7865f7aa907SGabriel FERNANDEZ 
787b699f3e3SGabriel Fernandez 	if (!clk_fs_get_params(prate, drate, params))
788b699f3e3SGabriel Fernandez 		clk_fs_get_rate(prate, params, &rate);
7895f7aa907SGabriel FERNANDEZ 
7905f7aa907SGabriel FERNANDEZ 	return rate;
7915f7aa907SGabriel FERNANDEZ }
7925f7aa907SGabriel FERNANDEZ 
quadfs_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)7935f7aa907SGabriel FERNANDEZ static unsigned long quadfs_recalc_rate(struct clk_hw *hw,
7945f7aa907SGabriel FERNANDEZ 		unsigned long parent_rate)
7955f7aa907SGabriel FERNANDEZ {
7965f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
7975f7aa907SGabriel FERNANDEZ 	unsigned long rate = 0;
7985f7aa907SGabriel FERNANDEZ 	struct stm_fs params;
7995f7aa907SGabriel FERNANDEZ 	int (*clk_fs_get_rate)(unsigned long ,
8004abb1b40SGabriel FERNANDEZ 				const struct stm_fs *, unsigned long *);
8015f7aa907SGabriel FERNANDEZ 
8025f7aa907SGabriel FERNANDEZ 	clk_fs_get_rate = fs->data->get_rate;
8035f7aa907SGabriel FERNANDEZ 
8045f7aa907SGabriel FERNANDEZ 	if (quadfs_fsynt_get_hw_value_for_recalc(fs, &params))
8055f7aa907SGabriel FERNANDEZ 		return 0;
8065f7aa907SGabriel FERNANDEZ 
8075f7aa907SGabriel FERNANDEZ 	if (clk_fs_get_rate(parent_rate, &params, &rate)) {
8085f7aa907SGabriel FERNANDEZ 		pr_err("%s:%s error calculating rate\n",
809836ee0f7SStephen Boyd 		       clk_hw_get_name(hw), __func__);
8105f7aa907SGabriel FERNANDEZ 	}
8115f7aa907SGabriel FERNANDEZ 
812836ee0f7SStephen Boyd 	pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate);
8135f7aa907SGabriel FERNANDEZ 
8145f7aa907SGabriel FERNANDEZ 	return rate;
8155f7aa907SGabriel FERNANDEZ }
8165f7aa907SGabriel FERNANDEZ 
quadfs_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)8175f7aa907SGabriel FERNANDEZ static long quadfs_round_rate(struct clk_hw *hw, unsigned long rate,
8185f7aa907SGabriel FERNANDEZ 				     unsigned long *prate)
8195f7aa907SGabriel FERNANDEZ {
8205f7aa907SGabriel FERNANDEZ 	struct stm_fs params;
8215f7aa907SGabriel FERNANDEZ 
8225f7aa907SGabriel FERNANDEZ 	rate = quadfs_find_best_rate(hw, rate, *prate, &params);
8235f7aa907SGabriel FERNANDEZ 
8245f7aa907SGabriel FERNANDEZ 	pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
825836ee0f7SStephen Boyd 		 __func__, clk_hw_get_name(hw),
8265f7aa907SGabriel FERNANDEZ 		 rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv,
8275f7aa907SGabriel FERNANDEZ 			 (unsigned int)params.pe, (unsigned int)params.nsdiv);
8285f7aa907SGabriel FERNANDEZ 
8295f7aa907SGabriel FERNANDEZ 	return rate;
8305f7aa907SGabriel FERNANDEZ }
8315f7aa907SGabriel FERNANDEZ 
8325f7aa907SGabriel FERNANDEZ 
quadfs_program_and_enable(struct st_clk_quadfs_fsynth * fs,struct stm_fs * params)8335f7aa907SGabriel FERNANDEZ static void quadfs_program_and_enable(struct st_clk_quadfs_fsynth *fs,
8345f7aa907SGabriel FERNANDEZ 		struct stm_fs *params)
8355f7aa907SGabriel FERNANDEZ {
8365f7aa907SGabriel FERNANDEZ 	fs->md = params->mdiv;
8375f7aa907SGabriel FERNANDEZ 	fs->pe = params->pe;
8385f7aa907SGabriel FERNANDEZ 	fs->sdiv = params->sdiv;
8395f7aa907SGabriel FERNANDEZ 	fs->nsdiv = params->nsdiv;
8405f7aa907SGabriel FERNANDEZ 
8415f7aa907SGabriel FERNANDEZ 	/*
8425f7aa907SGabriel FERNANDEZ 	 * In some integrations you can only change the fsynth programming when
8435f7aa907SGabriel FERNANDEZ 	 * the parent entity containing it is enabled.
8445f7aa907SGabriel FERNANDEZ 	 */
8455f7aa907SGabriel FERNANDEZ 	quadfs_fsynth_program_rate(fs);
8465f7aa907SGabriel FERNANDEZ 	quadfs_fsynth_program_enable(fs);
8475f7aa907SGabriel FERNANDEZ }
8485f7aa907SGabriel FERNANDEZ 
quadfs_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)8495f7aa907SGabriel FERNANDEZ static int quadfs_set_rate(struct clk_hw *hw, unsigned long rate,
8505f7aa907SGabriel FERNANDEZ 				  unsigned long parent_rate)
8515f7aa907SGabriel FERNANDEZ {
8525f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw);
8535f7aa907SGabriel FERNANDEZ 	struct stm_fs params;
8545f7aa907SGabriel FERNANDEZ 	long hwrate;
8555f7aa907SGabriel FERNANDEZ 
8565f7aa907SGabriel FERNANDEZ 	if (!rate || !parent_rate)
8575f7aa907SGabriel FERNANDEZ 		return -EINVAL;
8585f7aa907SGabriel FERNANDEZ 
8595f7aa907SGabriel FERNANDEZ 	memset(&params, 0, sizeof(struct stm_fs));
8605f7aa907SGabriel FERNANDEZ 
8615f7aa907SGabriel FERNANDEZ 	hwrate = quadfs_find_best_rate(hw, rate, parent_rate, &params);
8625f7aa907SGabriel FERNANDEZ 	if (!hwrate)
8635f7aa907SGabriel FERNANDEZ 		return -EINVAL;
8645f7aa907SGabriel FERNANDEZ 
8655f7aa907SGabriel FERNANDEZ 	quadfs_program_and_enable(fs, &params);
8665f7aa907SGabriel FERNANDEZ 
8675f7aa907SGabriel FERNANDEZ 	return 0;
8685f7aa907SGabriel FERNANDEZ }
8695f7aa907SGabriel FERNANDEZ 
8705f7aa907SGabriel FERNANDEZ 
8715f7aa907SGabriel FERNANDEZ 
8725f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_ops = {
8735f7aa907SGabriel FERNANDEZ 	.enable		= quadfs_fsynth_enable,
8745f7aa907SGabriel FERNANDEZ 	.disable	= quadfs_fsynth_disable,
8755f7aa907SGabriel FERNANDEZ 	.is_enabled	= quadfs_fsynth_is_enabled,
8765f7aa907SGabriel FERNANDEZ 	.round_rate	= quadfs_round_rate,
8775f7aa907SGabriel FERNANDEZ 	.set_rate	= quadfs_set_rate,
8785f7aa907SGabriel FERNANDEZ 	.recalc_rate	= quadfs_recalc_rate,
8795f7aa907SGabriel FERNANDEZ };
8805f7aa907SGabriel FERNANDEZ 
st_clk_register_quadfs_fsynth(const char * name,const char * parent_name,struct clkgen_quadfs_data * quadfs,void __iomem * reg,u32 chan,unsigned long flags,spinlock_t * lock)8815f7aa907SGabriel FERNANDEZ static struct clk * __init st_clk_register_quadfs_fsynth(
8825f7aa907SGabriel FERNANDEZ 		const char *name, const char *parent_name,
8835f7aa907SGabriel FERNANDEZ 		struct clkgen_quadfs_data *quadfs, void __iomem *reg, u32 chan,
884a3a2d78bSLee Jones 		unsigned long flags, spinlock_t *lock)
8855f7aa907SGabriel FERNANDEZ {
8865f7aa907SGabriel FERNANDEZ 	struct st_clk_quadfs_fsynth *fs;
8875f7aa907SGabriel FERNANDEZ 	struct clk *clk;
8885f7aa907SGabriel FERNANDEZ 	struct clk_init_data init;
8895f7aa907SGabriel FERNANDEZ 
8905f7aa907SGabriel FERNANDEZ 	/*
8915f7aa907SGabriel FERNANDEZ 	 * Sanity check required pointers, note that nsdiv3 is optional.
8925f7aa907SGabriel FERNANDEZ 	 */
8935f7aa907SGabriel FERNANDEZ 	if (WARN_ON(!name || !parent_name))
8945f7aa907SGabriel FERNANDEZ 		return ERR_PTR(-EINVAL);
8955f7aa907SGabriel FERNANDEZ 
8965f7aa907SGabriel FERNANDEZ 	fs = kzalloc(sizeof(*fs), GFP_KERNEL);
8975f7aa907SGabriel FERNANDEZ 	if (!fs)
8985f7aa907SGabriel FERNANDEZ 		return ERR_PTR(-ENOMEM);
8995f7aa907SGabriel FERNANDEZ 
9005f7aa907SGabriel FERNANDEZ 	init.name = name;
9015f7aa907SGabriel FERNANDEZ 	init.ops = &st_quadfs_ops;
902c179c21eSStephen Boyd 	init.flags = flags | CLK_GET_RATE_NOCACHE;
9035f7aa907SGabriel FERNANDEZ 	init.parent_names = &parent_name;
9045f7aa907SGabriel FERNANDEZ 	init.num_parents = 1;
9055f7aa907SGabriel FERNANDEZ 
9065f7aa907SGabriel FERNANDEZ 	fs->data = quadfs;
9075f7aa907SGabriel FERNANDEZ 	fs->regs_base = reg;
9085f7aa907SGabriel FERNANDEZ 	fs->chan = chan;
9095f7aa907SGabriel FERNANDEZ 	fs->lock = lock;
9105f7aa907SGabriel FERNANDEZ 	fs->hw.init = &init;
9115f7aa907SGabriel FERNANDEZ 
9125f7aa907SGabriel FERNANDEZ 	clk = clk_register(NULL, &fs->hw);
9135f7aa907SGabriel FERNANDEZ 
9145f7aa907SGabriel FERNANDEZ 	if (IS_ERR(clk))
9155f7aa907SGabriel FERNANDEZ 		kfree(fs);
9165f7aa907SGabriel FERNANDEZ 
9175f7aa907SGabriel FERNANDEZ 	return clk;
9185f7aa907SGabriel FERNANDEZ }
9195f7aa907SGabriel FERNANDEZ 
st_of_create_quadfs_fsynths(struct device_node * np,const char * pll_name,struct clkgen_quadfs_data_clks * quadfs,void __iomem * reg,spinlock_t * lock)9205f7aa907SGabriel FERNANDEZ static void __init st_of_create_quadfs_fsynths(
9215f7aa907SGabriel FERNANDEZ 		struct device_node *np, const char *pll_name,
9225dc1a127SAlain Volmat 		struct clkgen_quadfs_data_clks *quadfs, void __iomem *reg,
9235f7aa907SGabriel FERNANDEZ 		spinlock_t *lock)
9245f7aa907SGabriel FERNANDEZ {
9255f7aa907SGabriel FERNANDEZ 	struct clk_onecell_data *clk_data;
9265f7aa907SGabriel FERNANDEZ 	int fschan;
9275f7aa907SGabriel FERNANDEZ 
9285f7aa907SGabriel FERNANDEZ 	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
9295f7aa907SGabriel FERNANDEZ 	if (!clk_data)
9305f7aa907SGabriel FERNANDEZ 		return;
9315f7aa907SGabriel FERNANDEZ 
9325f7aa907SGabriel FERNANDEZ 	clk_data->clk_num = QUADFS_MAX_CHAN;
9336396bb22SKees Cook 	clk_data->clks = kcalloc(QUADFS_MAX_CHAN, sizeof(struct clk *),
9345f7aa907SGabriel FERNANDEZ 				 GFP_KERNEL);
9355f7aa907SGabriel FERNANDEZ 
9365f7aa907SGabriel FERNANDEZ 	if (!clk_data->clks) {
9375f7aa907SGabriel FERNANDEZ 		kfree(clk_data);
9385f7aa907SGabriel FERNANDEZ 		return;
9395f7aa907SGabriel FERNANDEZ 	}
9405f7aa907SGabriel FERNANDEZ 
9415f7aa907SGabriel FERNANDEZ 	for (fschan = 0; fschan < QUADFS_MAX_CHAN; fschan++) {
9425f7aa907SGabriel FERNANDEZ 		struct clk *clk;
9435f7aa907SGabriel FERNANDEZ 		const char *clk_name;
944a3a2d78bSLee Jones 		unsigned long flags = 0;
9455f7aa907SGabriel FERNANDEZ 
9465dc1a127SAlain Volmat 		if (quadfs->outputs) {
9475dc1a127SAlain Volmat 			clk_name = quadfs->outputs[fschan].name;
9485dc1a127SAlain Volmat 			flags = quadfs->outputs[fschan].flags;
9495dc1a127SAlain Volmat 		} else {
9505dc1a127SAlain Volmat 			if (of_property_read_string_index(np,
9515dc1a127SAlain Volmat 							"clock-output-names",
9525dc1a127SAlain Volmat 							fschan, &clk_name))
9535f7aa907SGabriel FERNANDEZ 				break;
9545dc1a127SAlain Volmat 			of_clk_detect_critical(np, fschan, &flags);
9555f7aa907SGabriel FERNANDEZ 		}
9565f7aa907SGabriel FERNANDEZ 
9575f7aa907SGabriel FERNANDEZ 		/*
9585f7aa907SGabriel FERNANDEZ 		 * If we read an empty clock name then the channel is unused
9595f7aa907SGabriel FERNANDEZ 		 */
9605f7aa907SGabriel FERNANDEZ 		if (*clk_name == '\0')
9615f7aa907SGabriel FERNANDEZ 			continue;
9625f7aa907SGabriel FERNANDEZ 
9635f7aa907SGabriel FERNANDEZ 		clk = st_clk_register_quadfs_fsynth(clk_name, pll_name,
9645dc1a127SAlain Volmat 						    quadfs->data, reg, fschan,
965a3a2d78bSLee Jones 						    flags, lock);
9665f7aa907SGabriel FERNANDEZ 
9675f7aa907SGabriel FERNANDEZ 		/*
9685f7aa907SGabriel FERNANDEZ 		 * If there was an error registering this clock output, clean
9695f7aa907SGabriel FERNANDEZ 		 * up and move on to the next one.
9705f7aa907SGabriel FERNANDEZ 		 */
9715f7aa907SGabriel FERNANDEZ 		if (!IS_ERR(clk)) {
9725f7aa907SGabriel FERNANDEZ 			clk_data->clks[fschan] = clk;
9735f7aa907SGabriel FERNANDEZ 			pr_debug("%s: parent %s rate %u\n",
9745f7aa907SGabriel FERNANDEZ 				__clk_get_name(clk),
9755f7aa907SGabriel FERNANDEZ 				__clk_get_name(clk_get_parent(clk)),
9765f7aa907SGabriel FERNANDEZ 				(unsigned int)clk_get_rate(clk));
9775f7aa907SGabriel FERNANDEZ 		}
9785f7aa907SGabriel FERNANDEZ 	}
9795f7aa907SGabriel FERNANDEZ 
9805f7aa907SGabriel FERNANDEZ 	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
9815f7aa907SGabriel FERNANDEZ }
9825f7aa907SGabriel FERNANDEZ 
st_of_quadfs_setup(struct device_node * np,struct clkgen_quadfs_data_clks * datac)983880d54ffSGabriel Fernandez static void __init st_of_quadfs_setup(struct device_node *np,
9845dc1a127SAlain Volmat 		struct clkgen_quadfs_data_clks *datac)
9855f7aa907SGabriel FERNANDEZ {
9865f7aa907SGabriel FERNANDEZ 	struct clk *clk;
9875f7aa907SGabriel FERNANDEZ 	const char *pll_name, *clk_parent_name;
9885f7aa907SGabriel FERNANDEZ 	void __iomem *reg;
9895f7aa907SGabriel FERNANDEZ 	spinlock_t *lock;
99042997330SLiang He 	struct device_node *parent_np;
9915f7aa907SGabriel FERNANDEZ 
9923efe64efSAlain Volmat 	/*
9933efe64efSAlain Volmat 	 * First check for reg property within the node to keep backward
9943efe64efSAlain Volmat 	 * compatibility, then if reg doesn't exist look at the parent node
9953efe64efSAlain Volmat 	 */
9965f7aa907SGabriel FERNANDEZ 	reg = of_iomap(np, 0);
9973efe64efSAlain Volmat 	if (!reg) {
99842997330SLiang He 		parent_np = of_get_parent(np);
99942997330SLiang He 		reg = of_iomap(parent_np, 0);
100042997330SLiang He 		of_node_put(parent_np);
10013efe64efSAlain Volmat 		if (!reg) {
10023efe64efSAlain Volmat 			pr_err("%s: Failed to get base address\n", __func__);
10035f7aa907SGabriel FERNANDEZ 			return;
10043efe64efSAlain Volmat 		}
10053efe64efSAlain Volmat 	}
10065f7aa907SGabriel FERNANDEZ 
10075f7aa907SGabriel FERNANDEZ 	clk_parent_name = of_clk_get_parent_name(np, 0);
10085f7aa907SGabriel FERNANDEZ 	if (!clk_parent_name)
10095f7aa907SGabriel FERNANDEZ 		return;
10105f7aa907SGabriel FERNANDEZ 
1011e665f029SRob Herring 	pll_name = kasprintf(GFP_KERNEL, "%pOFn.pll", np);
10125f7aa907SGabriel FERNANDEZ 	if (!pll_name)
10135f7aa907SGabriel FERNANDEZ 		return;
10145f7aa907SGabriel FERNANDEZ 
10155f7aa907SGabriel FERNANDEZ 	lock = kzalloc(sizeof(*lock), GFP_KERNEL);
10165f7aa907SGabriel FERNANDEZ 	if (!lock)
10175f7aa907SGabriel FERNANDEZ 		goto err_exit;
10185f7aa907SGabriel FERNANDEZ 
10195f7aa907SGabriel FERNANDEZ 	spin_lock_init(lock);
10205f7aa907SGabriel FERNANDEZ 
10215dc1a127SAlain Volmat 	clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, datac->data,
1022880d54ffSGabriel Fernandez 			reg, lock);
1023*cfd3ffb3SXiu Jianfeng 	if (IS_ERR(clk)) {
1024*cfd3ffb3SXiu Jianfeng 		kfree(lock);
10255f7aa907SGabriel FERNANDEZ 		goto err_exit;
1026*cfd3ffb3SXiu Jianfeng 	} else
10275f7aa907SGabriel FERNANDEZ 		pr_debug("%s: parent %s rate %u\n",
10285f7aa907SGabriel FERNANDEZ 			__clk_get_name(clk),
10295f7aa907SGabriel FERNANDEZ 			__clk_get_name(clk_get_parent(clk)),
10305f7aa907SGabriel FERNANDEZ 			(unsigned int)clk_get_rate(clk));
10315f7aa907SGabriel FERNANDEZ 
10325dc1a127SAlain Volmat 	st_of_create_quadfs_fsynths(np, pll_name, datac, reg, lock);
10335f7aa907SGabriel FERNANDEZ 
10345f7aa907SGabriel FERNANDEZ err_exit:
10355f7aa907SGabriel FERNANDEZ 	kfree(pll_name); /* No longer need local copy of the PLL name */
10365f7aa907SGabriel FERNANDEZ }
1037880d54ffSGabriel Fernandez 
st_of_quadfs660C_setup(struct device_node * np)1038880d54ffSGabriel Fernandez static void __init st_of_quadfs660C_setup(struct device_node *np)
1039880d54ffSGabriel Fernandez {
10405dc1a127SAlain Volmat 	st_of_quadfs_setup(np,
10415dc1a127SAlain Volmat 		(struct clkgen_quadfs_data_clks *) &st_fs660c32_C_data);
1042880d54ffSGabriel Fernandez }
1043880d54ffSGabriel Fernandez CLK_OF_DECLARE(quadfs660C, "st,quadfs-pll", st_of_quadfs660C_setup);
1044880d54ffSGabriel Fernandez 
st_of_quadfs660D_setup(struct device_node * np)1045880d54ffSGabriel Fernandez static void __init st_of_quadfs660D_setup(struct device_node *np)
1046880d54ffSGabriel Fernandez {
10475dc1a127SAlain Volmat 	st_of_quadfs_setup(np,
10485dc1a127SAlain Volmat 		(struct clkgen_quadfs_data_clks *) &st_fs660c32_D_data);
1049880d54ffSGabriel Fernandez }
1050880d54ffSGabriel Fernandez CLK_OF_DECLARE(quadfs660D, "st,quadfs", st_of_quadfs660D_setup);
10515dc1a127SAlain Volmat 
st_of_quadfs660D0_setup(struct device_node * np)10525dc1a127SAlain Volmat static void __init st_of_quadfs660D0_setup(struct device_node *np)
10535dc1a127SAlain Volmat {
10545dc1a127SAlain Volmat 	st_of_quadfs_setup(np,
10555dc1a127SAlain Volmat 		(struct clkgen_quadfs_data_clks *) &st_fs660c32_D0_data);
10565dc1a127SAlain Volmat }
10575dc1a127SAlain Volmat CLK_OF_DECLARE(quadfs660D0, "st,quadfs-d0", st_of_quadfs660D0_setup);
10585dc1a127SAlain Volmat 
st_of_quadfs660D2_setup(struct device_node * np)10595dc1a127SAlain Volmat static void __init st_of_quadfs660D2_setup(struct device_node *np)
10605dc1a127SAlain Volmat {
10615dc1a127SAlain Volmat 	st_of_quadfs_setup(np,
10625dc1a127SAlain Volmat 		(struct clkgen_quadfs_data_clks *) &st_fs660c32_D2_data);
10635dc1a127SAlain Volmat }
10645dc1a127SAlain Volmat CLK_OF_DECLARE(quadfs660D2, "st,quadfs-d2", st_of_quadfs660D2_setup);
10655dc1a127SAlain Volmat 
st_of_quadfs660D3_setup(struct device_node * np)10665dc1a127SAlain Volmat static void __init st_of_quadfs660D3_setup(struct device_node *np)
10675dc1a127SAlain Volmat {
10685dc1a127SAlain Volmat 	st_of_quadfs_setup(np,
10695dc1a127SAlain Volmat 		(struct clkgen_quadfs_data_clks *) &st_fs660c32_D3_data);
10705dc1a127SAlain Volmat }
10715dc1a127SAlain Volmat CLK_OF_DECLARE(quadfs660D3, "st,quadfs-d3", st_of_quadfs660D3_setup);
1072