162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2014 STMicroelectronics R&D Ltd 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* 762306a36Sopenharmony_ci * Authors: 862306a36Sopenharmony_ci * Stephen Gallimore <stephen.gallimore@st.com>, 962306a36Sopenharmony_ci * Pankaj Dev <pankaj.dev@st.com>. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/of_address.h> 1462306a36Sopenharmony_ci#include <linux/clk.h> 1562306a36Sopenharmony_ci#include <linux/clk-provider.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "clkgen.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Maximum input clock to the PLL before we divide it down by 2 2162306a36Sopenharmony_ci * although in reality in actual systems this has never been seen to 2262306a36Sopenharmony_ci * be used. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci#define QUADFS_NDIV_THRESHOLD 30000000 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define PLL_BW_GOODREF (0L) 2762306a36Sopenharmony_ci#define PLL_BW_VBADREF (1L) 2862306a36Sopenharmony_ci#define PLL_BW_BADREF (2L) 2962306a36Sopenharmony_ci#define PLL_BW_VGOODREF (3L) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define QUADFS_MAX_CHAN 4 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct stm_fs { 3462306a36Sopenharmony_ci unsigned long ndiv; 3562306a36Sopenharmony_ci unsigned long mdiv; 3662306a36Sopenharmony_ci unsigned long pe; 3762306a36Sopenharmony_ci unsigned long sdiv; 3862306a36Sopenharmony_ci unsigned long nsdiv; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct clkgen_quadfs_data { 4262306a36Sopenharmony_ci bool reset_present; 4362306a36Sopenharmony_ci bool bwfilter_present; 4462306a36Sopenharmony_ci bool lockstatus_present; 4562306a36Sopenharmony_ci bool powerup_polarity; 4662306a36Sopenharmony_ci bool standby_polarity; 4762306a36Sopenharmony_ci bool nsdiv_present; 4862306a36Sopenharmony_ci bool nrst_present; 4962306a36Sopenharmony_ci struct clkgen_field ndiv; 5062306a36Sopenharmony_ci struct clkgen_field ref_bw; 5162306a36Sopenharmony_ci struct clkgen_field nreset; 5262306a36Sopenharmony_ci struct clkgen_field npda; 5362306a36Sopenharmony_ci struct clkgen_field lock_status; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci struct clkgen_field nrst[QUADFS_MAX_CHAN]; 5662306a36Sopenharmony_ci struct clkgen_field nsb[QUADFS_MAX_CHAN]; 5762306a36Sopenharmony_ci struct clkgen_field en[QUADFS_MAX_CHAN]; 5862306a36Sopenharmony_ci struct clkgen_field mdiv[QUADFS_MAX_CHAN]; 5962306a36Sopenharmony_ci struct clkgen_field pe[QUADFS_MAX_CHAN]; 6062306a36Sopenharmony_ci struct clkgen_field sdiv[QUADFS_MAX_CHAN]; 6162306a36Sopenharmony_ci struct clkgen_field nsdiv[QUADFS_MAX_CHAN]; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci const struct clk_ops *pll_ops; 6462306a36Sopenharmony_ci int (*get_params)(unsigned long, unsigned long, struct stm_fs *); 6562306a36Sopenharmony_ci int (*get_rate)(unsigned long , const struct stm_fs *, 6662306a36Sopenharmony_ci unsigned long *); 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistruct clkgen_clk_out { 7062306a36Sopenharmony_ci const char *name; 7162306a36Sopenharmony_ci unsigned long flags; 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistruct clkgen_quadfs_data_clks { 7562306a36Sopenharmony_ci struct clkgen_quadfs_data *data; 7662306a36Sopenharmony_ci const struct clkgen_clk_out *outputs; 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic const struct clk_ops st_quadfs_pll_c32_ops; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int clk_fs660c32_dig_get_params(unsigned long input, 8262306a36Sopenharmony_ci unsigned long output, struct stm_fs *fs); 8362306a36Sopenharmony_cistatic int clk_fs660c32_dig_get_rate(unsigned long, const struct stm_fs *, 8462306a36Sopenharmony_ci unsigned long *); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic const struct clkgen_quadfs_data st_fs660c32_C = { 8762306a36Sopenharmony_ci .nrst_present = true, 8862306a36Sopenharmony_ci .nrst = { CLKGEN_FIELD(0x2f0, 0x1, 0), 8962306a36Sopenharmony_ci CLKGEN_FIELD(0x2f0, 0x1, 1), 9062306a36Sopenharmony_ci CLKGEN_FIELD(0x2f0, 0x1, 2), 9162306a36Sopenharmony_ci CLKGEN_FIELD(0x2f0, 0x1, 3) }, 9262306a36Sopenharmony_ci .npda = CLKGEN_FIELD(0x2f0, 0x1, 12), 9362306a36Sopenharmony_ci .nsb = { CLKGEN_FIELD(0x2f0, 0x1, 8), 9462306a36Sopenharmony_ci CLKGEN_FIELD(0x2f0, 0x1, 9), 9562306a36Sopenharmony_ci CLKGEN_FIELD(0x2f0, 0x1, 10), 9662306a36Sopenharmony_ci CLKGEN_FIELD(0x2f0, 0x1, 11) }, 9762306a36Sopenharmony_ci .nsdiv_present = true, 9862306a36Sopenharmony_ci .nsdiv = { CLKGEN_FIELD(0x304, 0x1, 24), 9962306a36Sopenharmony_ci CLKGEN_FIELD(0x308, 0x1, 24), 10062306a36Sopenharmony_ci CLKGEN_FIELD(0x30c, 0x1, 24), 10162306a36Sopenharmony_ci CLKGEN_FIELD(0x310, 0x1, 24) }, 10262306a36Sopenharmony_ci .mdiv = { CLKGEN_FIELD(0x304, 0x1f, 15), 10362306a36Sopenharmony_ci CLKGEN_FIELD(0x308, 0x1f, 15), 10462306a36Sopenharmony_ci CLKGEN_FIELD(0x30c, 0x1f, 15), 10562306a36Sopenharmony_ci CLKGEN_FIELD(0x310, 0x1f, 15) }, 10662306a36Sopenharmony_ci .en = { CLKGEN_FIELD(0x2fc, 0x1, 0), 10762306a36Sopenharmony_ci CLKGEN_FIELD(0x2fc, 0x1, 1), 10862306a36Sopenharmony_ci CLKGEN_FIELD(0x2fc, 0x1, 2), 10962306a36Sopenharmony_ci CLKGEN_FIELD(0x2fc, 0x1, 3) }, 11062306a36Sopenharmony_ci .ndiv = CLKGEN_FIELD(0x2f4, 0x7, 16), 11162306a36Sopenharmony_ci .pe = { CLKGEN_FIELD(0x304, 0x7fff, 0), 11262306a36Sopenharmony_ci CLKGEN_FIELD(0x308, 0x7fff, 0), 11362306a36Sopenharmony_ci CLKGEN_FIELD(0x30c, 0x7fff, 0), 11462306a36Sopenharmony_ci CLKGEN_FIELD(0x310, 0x7fff, 0) }, 11562306a36Sopenharmony_ci .sdiv = { CLKGEN_FIELD(0x304, 0xf, 20), 11662306a36Sopenharmony_ci CLKGEN_FIELD(0x308, 0xf, 20), 11762306a36Sopenharmony_ci CLKGEN_FIELD(0x30c, 0xf, 20), 11862306a36Sopenharmony_ci CLKGEN_FIELD(0x310, 0xf, 20) }, 11962306a36Sopenharmony_ci .lockstatus_present = true, 12062306a36Sopenharmony_ci .lock_status = CLKGEN_FIELD(0x2f0, 0x1, 24), 12162306a36Sopenharmony_ci .powerup_polarity = 1, 12262306a36Sopenharmony_ci .standby_polarity = 1, 12362306a36Sopenharmony_ci .pll_ops = &st_quadfs_pll_c32_ops, 12462306a36Sopenharmony_ci .get_params = clk_fs660c32_dig_get_params, 12562306a36Sopenharmony_ci .get_rate = clk_fs660c32_dig_get_rate, 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic const struct clkgen_clk_out st_fs660c32_C_clks[] = { 12962306a36Sopenharmony_ci { .name = "clk-s-c0-fs0-ch0", }, 13062306a36Sopenharmony_ci { .name = "clk-s-c0-fs0-ch1", }, 13162306a36Sopenharmony_ci { .name = "clk-s-c0-fs0-ch2", }, 13262306a36Sopenharmony_ci { .name = "clk-s-c0-fs0-ch3", }, 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic const struct clkgen_quadfs_data_clks st_fs660c32_C_data = { 13662306a36Sopenharmony_ci .data = (struct clkgen_quadfs_data *)&st_fs660c32_C, 13762306a36Sopenharmony_ci .outputs = st_fs660c32_C_clks, 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic const struct clkgen_quadfs_data st_fs660c32_D = { 14162306a36Sopenharmony_ci .nrst_present = true, 14262306a36Sopenharmony_ci .nrst = { CLKGEN_FIELD(0x2a0, 0x1, 0), 14362306a36Sopenharmony_ci CLKGEN_FIELD(0x2a0, 0x1, 1), 14462306a36Sopenharmony_ci CLKGEN_FIELD(0x2a0, 0x1, 2), 14562306a36Sopenharmony_ci CLKGEN_FIELD(0x2a0, 0x1, 3) }, 14662306a36Sopenharmony_ci .ndiv = CLKGEN_FIELD(0x2a4, 0x7, 16), 14762306a36Sopenharmony_ci .pe = { CLKGEN_FIELD(0x2b4, 0x7fff, 0), 14862306a36Sopenharmony_ci CLKGEN_FIELD(0x2b8, 0x7fff, 0), 14962306a36Sopenharmony_ci CLKGEN_FIELD(0x2bc, 0x7fff, 0), 15062306a36Sopenharmony_ci CLKGEN_FIELD(0x2c0, 0x7fff, 0) }, 15162306a36Sopenharmony_ci .sdiv = { CLKGEN_FIELD(0x2b4, 0xf, 20), 15262306a36Sopenharmony_ci CLKGEN_FIELD(0x2b8, 0xf, 20), 15362306a36Sopenharmony_ci CLKGEN_FIELD(0x2bc, 0xf, 20), 15462306a36Sopenharmony_ci CLKGEN_FIELD(0x2c0, 0xf, 20) }, 15562306a36Sopenharmony_ci .npda = CLKGEN_FIELD(0x2a0, 0x1, 12), 15662306a36Sopenharmony_ci .nsb = { CLKGEN_FIELD(0x2a0, 0x1, 8), 15762306a36Sopenharmony_ci CLKGEN_FIELD(0x2a0, 0x1, 9), 15862306a36Sopenharmony_ci CLKGEN_FIELD(0x2a0, 0x1, 10), 15962306a36Sopenharmony_ci CLKGEN_FIELD(0x2a0, 0x1, 11) }, 16062306a36Sopenharmony_ci .nsdiv_present = true, 16162306a36Sopenharmony_ci .nsdiv = { CLKGEN_FIELD(0x2b4, 0x1, 24), 16262306a36Sopenharmony_ci CLKGEN_FIELD(0x2b8, 0x1, 24), 16362306a36Sopenharmony_ci CLKGEN_FIELD(0x2bc, 0x1, 24), 16462306a36Sopenharmony_ci CLKGEN_FIELD(0x2c0, 0x1, 24) }, 16562306a36Sopenharmony_ci .mdiv = { CLKGEN_FIELD(0x2b4, 0x1f, 15), 16662306a36Sopenharmony_ci CLKGEN_FIELD(0x2b8, 0x1f, 15), 16762306a36Sopenharmony_ci CLKGEN_FIELD(0x2bc, 0x1f, 15), 16862306a36Sopenharmony_ci CLKGEN_FIELD(0x2c0, 0x1f, 15) }, 16962306a36Sopenharmony_ci .en = { CLKGEN_FIELD(0x2ac, 0x1, 0), 17062306a36Sopenharmony_ci CLKGEN_FIELD(0x2ac, 0x1, 1), 17162306a36Sopenharmony_ci CLKGEN_FIELD(0x2ac, 0x1, 2), 17262306a36Sopenharmony_ci CLKGEN_FIELD(0x2ac, 0x1, 3) }, 17362306a36Sopenharmony_ci .lockstatus_present = true, 17462306a36Sopenharmony_ci .lock_status = CLKGEN_FIELD(0x2A0, 0x1, 24), 17562306a36Sopenharmony_ci .powerup_polarity = 1, 17662306a36Sopenharmony_ci .standby_polarity = 1, 17762306a36Sopenharmony_ci .pll_ops = &st_quadfs_pll_c32_ops, 17862306a36Sopenharmony_ci .get_params = clk_fs660c32_dig_get_params, 17962306a36Sopenharmony_ci .get_rate = clk_fs660c32_dig_get_rate,}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic const struct clkgen_quadfs_data_clks st_fs660c32_D_data = { 18262306a36Sopenharmony_ci .data = (struct clkgen_quadfs_data *)&st_fs660c32_D, 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const struct clkgen_clk_out st_fs660c32_D0_clks[] = { 18662306a36Sopenharmony_ci { .name = "clk-s-d0-fs0-ch0", }, 18762306a36Sopenharmony_ci { .name = "clk-s-d0-fs0-ch1", }, 18862306a36Sopenharmony_ci { .name = "clk-s-d0-fs0-ch2", }, 18962306a36Sopenharmony_ci { .name = "clk-s-d0-fs0-ch3", }, 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic const struct clkgen_quadfs_data_clks st_fs660c32_D0_data = { 19362306a36Sopenharmony_ci .data = (struct clkgen_quadfs_data *)&st_fs660c32_D, 19462306a36Sopenharmony_ci .outputs = st_fs660c32_D0_clks, 19562306a36Sopenharmony_ci}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic const struct clkgen_clk_out st_fs660c32_D2_clks[] = { 19862306a36Sopenharmony_ci { .name = "clk-s-d2-fs0-ch0", }, 19962306a36Sopenharmony_ci { .name = "clk-s-d2-fs0-ch1", }, 20062306a36Sopenharmony_ci { .name = "clk-s-d2-fs0-ch2", }, 20162306a36Sopenharmony_ci { .name = "clk-s-d2-fs0-ch3", }, 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic const struct clkgen_quadfs_data_clks st_fs660c32_D2_data = { 20562306a36Sopenharmony_ci .data = (struct clkgen_quadfs_data *)&st_fs660c32_D, 20662306a36Sopenharmony_ci .outputs = st_fs660c32_D2_clks, 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic const struct clkgen_clk_out st_fs660c32_D3_clks[] = { 21062306a36Sopenharmony_ci { .name = "clk-s-d3-fs0-ch0", }, 21162306a36Sopenharmony_ci { .name = "clk-s-d3-fs0-ch1", }, 21262306a36Sopenharmony_ci { .name = "clk-s-d3-fs0-ch2", }, 21362306a36Sopenharmony_ci { .name = "clk-s-d3-fs0-ch3", }, 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic const struct clkgen_quadfs_data_clks st_fs660c32_D3_data = { 21762306a36Sopenharmony_ci .data = (struct clkgen_quadfs_data *)&st_fs660c32_D, 21862306a36Sopenharmony_ci .outputs = st_fs660c32_D3_clks, 21962306a36Sopenharmony_ci}; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/** 22262306a36Sopenharmony_ci * DOC: A Frequency Synthesizer that multiples its input clock by a fixed factor 22362306a36Sopenharmony_ci * 22462306a36Sopenharmony_ci * Traits of this clock: 22562306a36Sopenharmony_ci * prepare - clk_(un)prepare only ensures parent is (un)prepared 22662306a36Sopenharmony_ci * enable - clk_enable and clk_disable are functional & control the Fsyn 22762306a36Sopenharmony_ci * rate - inherits rate from parent. set_rate/round_rate/recalc_rate 22862306a36Sopenharmony_ci * parent - fixed parent. No clk_set_parent support 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/** 23262306a36Sopenharmony_ci * struct st_clk_quadfs_pll - A pll which outputs a fixed multiplier of 23362306a36Sopenharmony_ci * its parent clock, found inside a type of 23462306a36Sopenharmony_ci * ST quad channel frequency synthesizer block 23562306a36Sopenharmony_ci * 23662306a36Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces. 23762306a36Sopenharmony_ci * @regs_base: base address of the configuration registers. 23862306a36Sopenharmony_ci * @lock: spinlock. 23962306a36Sopenharmony_ci * @data: local driver data 24062306a36Sopenharmony_ci * @ndiv: regmap field for the ndiv control. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_cistruct st_clk_quadfs_pll { 24362306a36Sopenharmony_ci struct clk_hw hw; 24462306a36Sopenharmony_ci void __iomem *regs_base; 24562306a36Sopenharmony_ci spinlock_t *lock; 24662306a36Sopenharmony_ci struct clkgen_quadfs_data *data; 24762306a36Sopenharmony_ci u32 ndiv; 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci#define to_quadfs_pll(_hw) container_of(_hw, struct st_clk_quadfs_pll, hw) 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int quadfs_pll_enable(struct clk_hw *hw) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 25562306a36Sopenharmony_ci unsigned long flags = 0, timeout = jiffies + msecs_to_jiffies(10); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (pll->lock) 25862306a36Sopenharmony_ci spin_lock_irqsave(pll->lock, flags); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * Bring block out of reset if we have reset control. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci if (pll->data->reset_present) 26462306a36Sopenharmony_ci CLKGEN_WRITE(pll, nreset, 1); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * Use a fixed input clock noise bandwidth filter for the moment 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci if (pll->data->bwfilter_present) 27062306a36Sopenharmony_ci CLKGEN_WRITE(pll, ref_bw, PLL_BW_GOODREF); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci CLKGEN_WRITE(pll, ndiv, pll->ndiv); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* 27662306a36Sopenharmony_ci * Power up the PLL 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ci CLKGEN_WRITE(pll, npda, !pll->data->powerup_polarity); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (pll->lock) 28162306a36Sopenharmony_ci spin_unlock_irqrestore(pll->lock, flags); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (pll->data->lockstatus_present) 28462306a36Sopenharmony_ci while (!CLKGEN_READ(pll, lock_status)) { 28562306a36Sopenharmony_ci if (time_after(jiffies, timeout)) 28662306a36Sopenharmony_ci return -ETIMEDOUT; 28762306a36Sopenharmony_ci cpu_relax(); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic void quadfs_pll_disable(struct clk_hw *hw) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 29662306a36Sopenharmony_ci unsigned long flags = 0; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (pll->lock) 29962306a36Sopenharmony_ci spin_lock_irqsave(pll->lock, flags); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * Powerdown the PLL and then put block into soft reset if we have 30362306a36Sopenharmony_ci * reset control. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci CLKGEN_WRITE(pll, npda, pll->data->powerup_polarity); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (pll->data->reset_present) 30862306a36Sopenharmony_ci CLKGEN_WRITE(pll, nreset, 0); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (pll->lock) 31162306a36Sopenharmony_ci spin_unlock_irqrestore(pll->lock, flags); 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int quadfs_pll_is_enabled(struct clk_hw *hw) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 31762306a36Sopenharmony_ci u32 npda = CLKGEN_READ(pll, npda); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return pll->data->powerup_polarity ? !npda : !!npda; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs, 32362306a36Sopenharmony_ci unsigned long *rate) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci unsigned long nd = fs->ndiv + 16; /* ndiv value */ 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci *rate = input * nd; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic unsigned long quadfs_pll_fs660c32_recalc_rate(struct clk_hw *hw, 33362306a36Sopenharmony_ci unsigned long parent_rate) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 33662306a36Sopenharmony_ci unsigned long rate = 0; 33762306a36Sopenharmony_ci struct stm_fs params; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci params.ndiv = CLKGEN_READ(pll, ndiv); 34062306a36Sopenharmony_ci if (clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &rate)) 34162306a36Sopenharmony_ci pr_err("%s:%s error calculating rate\n", 34262306a36Sopenharmony_ci clk_hw_get_name(hw), __func__); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci pll->ndiv = params.ndiv; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return rate; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int clk_fs660c32_vco_get_params(unsigned long input, 35062306a36Sopenharmony_ci unsigned long output, struct stm_fs *fs) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci/* Formula 35362306a36Sopenharmony_ci VCO frequency = (fin x ndiv) / pdiv 35462306a36Sopenharmony_ci ndiv = VCOfreq * pdiv / fin 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci unsigned long pdiv = 1, n; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* Output clock range: 384Mhz to 660Mhz */ 35962306a36Sopenharmony_ci if (output < 384000000 || output > 660000000) 36062306a36Sopenharmony_ci return -EINVAL; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (input > 40000000) 36362306a36Sopenharmony_ci /* This means that PDIV would be 2 instead of 1. 36462306a36Sopenharmony_ci Not supported today. */ 36562306a36Sopenharmony_ci return -EINVAL; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci input /= 1000; 36862306a36Sopenharmony_ci output /= 1000; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci n = output * pdiv / input; 37162306a36Sopenharmony_ci if (n < 16) 37262306a36Sopenharmony_ci n = 16; 37362306a36Sopenharmony_ci fs->ndiv = n - 16; /* Converting formula value to reg value */ 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, 37962306a36Sopenharmony_ci unsigned long rate, 38062306a36Sopenharmony_ci unsigned long *prate) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct stm_fs params; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (clk_fs660c32_vco_get_params(*prate, rate, ¶ms)) 38562306a36Sopenharmony_ci return rate; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci clk_fs660c32_vco_get_rate(*prate, ¶ms, &rate); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci pr_debug("%s: %s new rate %ld [ndiv=%u]\n", 39062306a36Sopenharmony_ci __func__, clk_hw_get_name(hw), 39162306a36Sopenharmony_ci rate, (unsigned int)params.ndiv); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return rate; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate, 39762306a36Sopenharmony_ci unsigned long parent_rate) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 40062306a36Sopenharmony_ci struct stm_fs params; 40162306a36Sopenharmony_ci long hwrate = 0; 40262306a36Sopenharmony_ci unsigned long flags = 0; 40362306a36Sopenharmony_ci int ret; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (!rate || !parent_rate) 40662306a36Sopenharmony_ci return -EINVAL; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ret = clk_fs660c32_vco_get_params(parent_rate, rate, ¶ms); 40962306a36Sopenharmony_ci if (ret) 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &hwrate); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci pr_debug("%s: %s new rate %ld [ndiv=0x%x]\n", 41562306a36Sopenharmony_ci __func__, clk_hw_get_name(hw), 41662306a36Sopenharmony_ci hwrate, (unsigned int)params.ndiv); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!hwrate) 41962306a36Sopenharmony_ci return -EINVAL; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci pll->ndiv = params.ndiv; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (pll->lock) 42462306a36Sopenharmony_ci spin_lock_irqsave(pll->lock, flags); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci CLKGEN_WRITE(pll, ndiv, pll->ndiv); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (pll->lock) 42962306a36Sopenharmony_ci spin_unlock_irqrestore(pll->lock, flags); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic const struct clk_ops st_quadfs_pll_c32_ops = { 43562306a36Sopenharmony_ci .enable = quadfs_pll_enable, 43662306a36Sopenharmony_ci .disable = quadfs_pll_disable, 43762306a36Sopenharmony_ci .is_enabled = quadfs_pll_is_enabled, 43862306a36Sopenharmony_ci .recalc_rate = quadfs_pll_fs660c32_recalc_rate, 43962306a36Sopenharmony_ci .round_rate = quadfs_pll_fs660c32_round_rate, 44062306a36Sopenharmony_ci .set_rate = quadfs_pll_fs660c32_set_rate, 44162306a36Sopenharmony_ci}; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic struct clk * __init st_clk_register_quadfs_pll( 44462306a36Sopenharmony_ci const char *name, const char *parent_name, 44562306a36Sopenharmony_ci struct clkgen_quadfs_data *quadfs, void __iomem *reg, 44662306a36Sopenharmony_ci spinlock_t *lock) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct st_clk_quadfs_pll *pll; 44962306a36Sopenharmony_ci struct clk *clk; 45062306a36Sopenharmony_ci struct clk_init_data init; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * Sanity check required pointers. 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_ci if (WARN_ON(!name || !parent_name)) 45662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci pll = kzalloc(sizeof(*pll), GFP_KERNEL); 45962306a36Sopenharmony_ci if (!pll) 46062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci init.name = name; 46362306a36Sopenharmony_ci init.ops = quadfs->pll_ops; 46462306a36Sopenharmony_ci init.flags = CLK_GET_RATE_NOCACHE; 46562306a36Sopenharmony_ci init.parent_names = &parent_name; 46662306a36Sopenharmony_ci init.num_parents = 1; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci pll->data = quadfs; 46962306a36Sopenharmony_ci pll->regs_base = reg; 47062306a36Sopenharmony_ci pll->lock = lock; 47162306a36Sopenharmony_ci pll->hw.init = &init; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci clk = clk_register(NULL, &pll->hw); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (IS_ERR(clk)) 47662306a36Sopenharmony_ci kfree(pll); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return clk; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci/** 48262306a36Sopenharmony_ci * DOC: A digital frequency synthesizer 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * Traits of this clock: 48562306a36Sopenharmony_ci * prepare - clk_(un)prepare only ensures parent is (un)prepared 48662306a36Sopenharmony_ci * enable - clk_enable and clk_disable are functional 48762306a36Sopenharmony_ci * rate - set rate is functional 48862306a36Sopenharmony_ci * parent - fixed parent. No clk_set_parent support 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci/* 49262306a36Sopenharmony_ci * struct st_clk_quadfs_fsynth - One clock output from a four channel digital 49362306a36Sopenharmony_ci * frequency synthesizer (fsynth) block. 49462306a36Sopenharmony_ci * 49562306a36Sopenharmony_ci * @hw: handle between common and hardware-specific interfaces 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * @nsb: regmap field in the output control register for the digital 49862306a36Sopenharmony_ci * standby of this fsynth channel. This control is active low so 49962306a36Sopenharmony_ci * the channel is in standby when the control bit is cleared. 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci * @nsdiv: regmap field in the output control register for 50262306a36Sopenharmony_ci * for the optional divide by 3 of this fsynth channel. This control 50362306a36Sopenharmony_ci * is active low so the divide by 3 is active when the control bit is 50462306a36Sopenharmony_ci * cleared and the divide is bypassed when the bit is set. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_cistruct st_clk_quadfs_fsynth { 50762306a36Sopenharmony_ci struct clk_hw hw; 50862306a36Sopenharmony_ci void __iomem *regs_base; 50962306a36Sopenharmony_ci spinlock_t *lock; 51062306a36Sopenharmony_ci struct clkgen_quadfs_data *data; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci u32 chan; 51362306a36Sopenharmony_ci /* 51462306a36Sopenharmony_ci * Cached hardware values from set_rate so we can program the 51562306a36Sopenharmony_ci * hardware in enable. There are two reasons for this: 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci * 1. The registers may not be writable until the parent has been 51862306a36Sopenharmony_ci * enabled. 51962306a36Sopenharmony_ci * 52062306a36Sopenharmony_ci * 2. It restores the clock rate when a driver does an enable 52162306a36Sopenharmony_ci * on PM restore, after a suspend to RAM has lost the hardware 52262306a36Sopenharmony_ci * setup. 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_ci u32 md; 52562306a36Sopenharmony_ci u32 pe; 52662306a36Sopenharmony_ci u32 sdiv; 52762306a36Sopenharmony_ci u32 nsdiv; 52862306a36Sopenharmony_ci}; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci#define to_quadfs_fsynth(_hw) \ 53162306a36Sopenharmony_ci container_of(_hw, struct st_clk_quadfs_fsynth, hw) 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic void quadfs_fsynth_program_enable(struct st_clk_quadfs_fsynth *fs) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci /* 53662306a36Sopenharmony_ci * Pulse the program enable register lsb to make the hardware take 53762306a36Sopenharmony_ci * notice of the new md/pe values with a glitchless transition. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci CLKGEN_WRITE(fs, en[fs->chan], 1); 54062306a36Sopenharmony_ci CLKGEN_WRITE(fs, en[fs->chan], 0); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic void quadfs_fsynth_program_rate(struct st_clk_quadfs_fsynth *fs) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci unsigned long flags = 0; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* 54862306a36Sopenharmony_ci * Ensure the md/pe parameters are ignored while we are 54962306a36Sopenharmony_ci * reprogramming them so we can get a glitchless change 55062306a36Sopenharmony_ci * when fine tuning the speed of a running clock. 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_ci CLKGEN_WRITE(fs, en[fs->chan], 0); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci CLKGEN_WRITE(fs, mdiv[fs->chan], fs->md); 55562306a36Sopenharmony_ci CLKGEN_WRITE(fs, pe[fs->chan], fs->pe); 55662306a36Sopenharmony_ci CLKGEN_WRITE(fs, sdiv[fs->chan], fs->sdiv); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (fs->lock) 55962306a36Sopenharmony_ci spin_lock_irqsave(fs->lock, flags); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (fs->data->nsdiv_present) 56262306a36Sopenharmony_ci CLKGEN_WRITE(fs, nsdiv[fs->chan], fs->nsdiv); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (fs->lock) 56562306a36Sopenharmony_ci spin_unlock_irqrestore(fs->lock, flags); 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic int quadfs_fsynth_enable(struct clk_hw *hw) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 57162306a36Sopenharmony_ci unsigned long flags = 0; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci pr_debug("%s: %s\n", __func__, clk_hw_get_name(hw)); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci quadfs_fsynth_program_rate(fs); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (fs->lock) 57862306a36Sopenharmony_ci spin_lock_irqsave(fs->lock, flags); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (fs->data->nrst_present) 58362306a36Sopenharmony_ci CLKGEN_WRITE(fs, nrst[fs->chan], 0); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (fs->lock) 58662306a36Sopenharmony_ci spin_unlock_irqrestore(fs->lock, flags); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci quadfs_fsynth_program_enable(fs); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic void quadfs_fsynth_disable(struct clk_hw *hw) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 59662306a36Sopenharmony_ci unsigned long flags = 0; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci pr_debug("%s: %s\n", __func__, clk_hw_get_name(hw)); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (fs->lock) 60162306a36Sopenharmony_ci spin_lock_irqsave(fs->lock, flags); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci CLKGEN_WRITE(fs, nsb[fs->chan], fs->data->standby_polarity); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (fs->lock) 60662306a36Sopenharmony_ci spin_unlock_irqrestore(fs->lock, flags); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int quadfs_fsynth_is_enabled(struct clk_hw *hw) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 61262306a36Sopenharmony_ci u32 nsb = CLKGEN_READ(fs, nsb[fs->chan]); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci pr_debug("%s: %s enable bit = 0x%x\n", 61562306a36Sopenharmony_ci __func__, clk_hw_get_name(hw), nsb); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci return fs->data->standby_polarity ? !nsb : !!nsb; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci#define P20 (uint64_t)(1 << 20) 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int clk_fs660c32_dig_get_rate(unsigned long input, 62362306a36Sopenharmony_ci const struct stm_fs *fs, unsigned long *rate) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci unsigned long s = (1 << fs->sdiv); 62662306a36Sopenharmony_ci unsigned long ns; 62762306a36Sopenharmony_ci uint64_t res; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* 63062306a36Sopenharmony_ci * 'nsdiv' is a register value ('BIN') which is translated 63162306a36Sopenharmony_ci * to a decimal value according to following rules. 63262306a36Sopenharmony_ci * 63362306a36Sopenharmony_ci * nsdiv ns.dec 63462306a36Sopenharmony_ci * 0 3 63562306a36Sopenharmony_ci * 1 1 63662306a36Sopenharmony_ci */ 63762306a36Sopenharmony_ci ns = (fs->nsdiv == 1) ? 1 : 3; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci res = (P20 * (32 + fs->mdiv) + 32 * fs->pe) * s * ns; 64062306a36Sopenharmony_ci *rate = (unsigned long)div64_u64(input * P20 * 32, res); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci return 0; 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int clk_fs660c32_get_pe(int m, int si, unsigned long *deviation, 64762306a36Sopenharmony_ci signed long input, unsigned long output, uint64_t *p, 64862306a36Sopenharmony_ci struct stm_fs *fs) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci unsigned long new_freq, new_deviation; 65162306a36Sopenharmony_ci struct stm_fs fs_tmp; 65262306a36Sopenharmony_ci uint64_t val; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci val = (uint64_t)output << si; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci *p = (uint64_t)input * P20 - (32LL + (uint64_t)m) * val * (P20 / 32LL); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci *p = div64_u64(*p, val); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (*p > 32767LL) 66162306a36Sopenharmony_ci return 1; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci fs_tmp.mdiv = (unsigned long) m; 66462306a36Sopenharmony_ci fs_tmp.pe = (unsigned long)*p; 66562306a36Sopenharmony_ci fs_tmp.sdiv = si; 66662306a36Sopenharmony_ci fs_tmp.nsdiv = 1; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci clk_fs660c32_dig_get_rate(input, &fs_tmp, &new_freq); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci new_deviation = abs(output - new_freq); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (new_deviation < *deviation) { 67362306a36Sopenharmony_ci fs->mdiv = m; 67462306a36Sopenharmony_ci fs->pe = (unsigned long)*p; 67562306a36Sopenharmony_ci fs->sdiv = si; 67662306a36Sopenharmony_ci fs->nsdiv = 1; 67762306a36Sopenharmony_ci *deviation = new_deviation; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int clk_fs660c32_dig_get_params(unsigned long input, 68362306a36Sopenharmony_ci unsigned long output, struct stm_fs *fs) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci int si; /* sdiv_reg (8 downto 0) */ 68662306a36Sopenharmony_ci int m; /* md value */ 68762306a36Sopenharmony_ci unsigned long new_freq, new_deviation; 68862306a36Sopenharmony_ci /* initial condition to say: "infinite deviation" */ 68962306a36Sopenharmony_ci unsigned long deviation = ~0; 69062306a36Sopenharmony_ci uint64_t p, p1, p2; /* pe value */ 69162306a36Sopenharmony_ci int r1, r2; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci struct stm_fs fs_tmp; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci for (si = 0; (si <= 8) && deviation; si++) { 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* Boundary test to avoid useless iteration */ 69862306a36Sopenharmony_ci r1 = clk_fs660c32_get_pe(0, si, &deviation, 69962306a36Sopenharmony_ci input, output, &p1, fs); 70062306a36Sopenharmony_ci r2 = clk_fs660c32_get_pe(31, si, &deviation, 70162306a36Sopenharmony_ci input, output, &p2, fs); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* No solution */ 70462306a36Sopenharmony_ci if (r1 && r2 && (p1 > p2)) 70562306a36Sopenharmony_ci continue; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Try to find best deviation */ 70862306a36Sopenharmony_ci for (m = 1; (m < 31) && deviation; m++) 70962306a36Sopenharmony_ci clk_fs660c32_get_pe(m, si, &deviation, 71062306a36Sopenharmony_ci input, output, &p, fs); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (deviation == ~0) /* No solution found */ 71562306a36Sopenharmony_ci return -1; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* pe fine tuning if deviation not 0: +/- 2 around computed pe value */ 71862306a36Sopenharmony_ci if (deviation) { 71962306a36Sopenharmony_ci fs_tmp.mdiv = fs->mdiv; 72062306a36Sopenharmony_ci fs_tmp.sdiv = fs->sdiv; 72162306a36Sopenharmony_ci fs_tmp.nsdiv = fs->nsdiv; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (fs->pe > 2) 72462306a36Sopenharmony_ci p2 = fs->pe - 2; 72562306a36Sopenharmony_ci else 72662306a36Sopenharmony_ci p2 = 0; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci for (; p2 < 32768ll && (p2 <= (fs->pe + 2)); p2++) { 72962306a36Sopenharmony_ci fs_tmp.pe = (unsigned long)p2; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci clk_fs660c32_dig_get_rate(input, &fs_tmp, &new_freq); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci new_deviation = abs(output - new_freq); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* Check if this is a better solution */ 73662306a36Sopenharmony_ci if (new_deviation < deviation) { 73762306a36Sopenharmony_ci fs->pe = (unsigned long)p2; 73862306a36Sopenharmony_ci deviation = new_deviation; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci return 0; 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic int quadfs_fsynt_get_hw_value_for_recalc(struct st_clk_quadfs_fsynth *fs, 74762306a36Sopenharmony_ci struct stm_fs *params) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci /* 75062306a36Sopenharmony_ci * Get the initial hardware values for recalc_rate 75162306a36Sopenharmony_ci */ 75262306a36Sopenharmony_ci params->mdiv = CLKGEN_READ(fs, mdiv[fs->chan]); 75362306a36Sopenharmony_ci params->pe = CLKGEN_READ(fs, pe[fs->chan]); 75462306a36Sopenharmony_ci params->sdiv = CLKGEN_READ(fs, sdiv[fs->chan]); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (fs->data->nsdiv_present) 75762306a36Sopenharmony_ci params->nsdiv = CLKGEN_READ(fs, nsdiv[fs->chan]); 75862306a36Sopenharmony_ci else 75962306a36Sopenharmony_ci params->nsdiv = 1; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* 76262306a36Sopenharmony_ci * If All are NULL then assume no clock rate is programmed. 76362306a36Sopenharmony_ci */ 76462306a36Sopenharmony_ci if (!params->mdiv && !params->pe && !params->sdiv) 76562306a36Sopenharmony_ci return 1; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci fs->md = params->mdiv; 76862306a36Sopenharmony_ci fs->pe = params->pe; 76962306a36Sopenharmony_ci fs->sdiv = params->sdiv; 77062306a36Sopenharmony_ci fs->nsdiv = params->nsdiv; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci return 0; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic long quadfs_find_best_rate(struct clk_hw *hw, unsigned long drate, 77662306a36Sopenharmony_ci unsigned long prate, struct stm_fs *params) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 77962306a36Sopenharmony_ci int (*clk_fs_get_rate)(unsigned long , 78062306a36Sopenharmony_ci const struct stm_fs *, unsigned long *); 78162306a36Sopenharmony_ci int (*clk_fs_get_params)(unsigned long, unsigned long, struct stm_fs *); 78262306a36Sopenharmony_ci unsigned long rate = 0; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci clk_fs_get_rate = fs->data->get_rate; 78562306a36Sopenharmony_ci clk_fs_get_params = fs->data->get_params; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (!clk_fs_get_params(prate, drate, params)) 78862306a36Sopenharmony_ci clk_fs_get_rate(prate, params, &rate); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci return rate; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic unsigned long quadfs_recalc_rate(struct clk_hw *hw, 79462306a36Sopenharmony_ci unsigned long parent_rate) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 79762306a36Sopenharmony_ci unsigned long rate = 0; 79862306a36Sopenharmony_ci struct stm_fs params; 79962306a36Sopenharmony_ci int (*clk_fs_get_rate)(unsigned long , 80062306a36Sopenharmony_ci const struct stm_fs *, unsigned long *); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci clk_fs_get_rate = fs->data->get_rate; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (quadfs_fsynt_get_hw_value_for_recalc(fs, ¶ms)) 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (clk_fs_get_rate(parent_rate, ¶ms, &rate)) { 80862306a36Sopenharmony_ci pr_err("%s:%s error calculating rate\n", 80962306a36Sopenharmony_ci clk_hw_get_name(hw), __func__); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci pr_debug("%s:%s rate %lu\n", clk_hw_get_name(hw), __func__, rate); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return rate; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic long quadfs_round_rate(struct clk_hw *hw, unsigned long rate, 81862306a36Sopenharmony_ci unsigned long *prate) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci struct stm_fs params; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci rate = quadfs_find_best_rate(hw, rate, *prate, ¶ms); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n", 82562306a36Sopenharmony_ci __func__, clk_hw_get_name(hw), 82662306a36Sopenharmony_ci rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv, 82762306a36Sopenharmony_ci (unsigned int)params.pe, (unsigned int)params.nsdiv); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci return rate; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic void quadfs_program_and_enable(struct st_clk_quadfs_fsynth *fs, 83462306a36Sopenharmony_ci struct stm_fs *params) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci fs->md = params->mdiv; 83762306a36Sopenharmony_ci fs->pe = params->pe; 83862306a36Sopenharmony_ci fs->sdiv = params->sdiv; 83962306a36Sopenharmony_ci fs->nsdiv = params->nsdiv; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* 84262306a36Sopenharmony_ci * In some integrations you can only change the fsynth programming when 84362306a36Sopenharmony_ci * the parent entity containing it is enabled. 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ci quadfs_fsynth_program_rate(fs); 84662306a36Sopenharmony_ci quadfs_fsynth_program_enable(fs); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic int quadfs_set_rate(struct clk_hw *hw, unsigned long rate, 85062306a36Sopenharmony_ci unsigned long parent_rate) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 85362306a36Sopenharmony_ci struct stm_fs params; 85462306a36Sopenharmony_ci long hwrate; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (!rate || !parent_rate) 85762306a36Sopenharmony_ci return -EINVAL; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci memset(¶ms, 0, sizeof(struct stm_fs)); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci hwrate = quadfs_find_best_rate(hw, rate, parent_rate, ¶ms); 86262306a36Sopenharmony_ci if (!hwrate) 86362306a36Sopenharmony_ci return -EINVAL; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci quadfs_program_and_enable(fs, ¶ms); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci return 0; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic const struct clk_ops st_quadfs_ops = { 87362306a36Sopenharmony_ci .enable = quadfs_fsynth_enable, 87462306a36Sopenharmony_ci .disable = quadfs_fsynth_disable, 87562306a36Sopenharmony_ci .is_enabled = quadfs_fsynth_is_enabled, 87662306a36Sopenharmony_ci .round_rate = quadfs_round_rate, 87762306a36Sopenharmony_ci .set_rate = quadfs_set_rate, 87862306a36Sopenharmony_ci .recalc_rate = quadfs_recalc_rate, 87962306a36Sopenharmony_ci}; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic struct clk * __init st_clk_register_quadfs_fsynth( 88262306a36Sopenharmony_ci const char *name, const char *parent_name, 88362306a36Sopenharmony_ci struct clkgen_quadfs_data *quadfs, void __iomem *reg, u32 chan, 88462306a36Sopenharmony_ci unsigned long flags, spinlock_t *lock) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct st_clk_quadfs_fsynth *fs; 88762306a36Sopenharmony_ci struct clk *clk; 88862306a36Sopenharmony_ci struct clk_init_data init; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* 89162306a36Sopenharmony_ci * Sanity check required pointers, note that nsdiv3 is optional. 89262306a36Sopenharmony_ci */ 89362306a36Sopenharmony_ci if (WARN_ON(!name || !parent_name)) 89462306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci fs = kzalloc(sizeof(*fs), GFP_KERNEL); 89762306a36Sopenharmony_ci if (!fs) 89862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci init.name = name; 90162306a36Sopenharmony_ci init.ops = &st_quadfs_ops; 90262306a36Sopenharmony_ci init.flags = flags | CLK_GET_RATE_NOCACHE; 90362306a36Sopenharmony_ci init.parent_names = &parent_name; 90462306a36Sopenharmony_ci init.num_parents = 1; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci fs->data = quadfs; 90762306a36Sopenharmony_ci fs->regs_base = reg; 90862306a36Sopenharmony_ci fs->chan = chan; 90962306a36Sopenharmony_ci fs->lock = lock; 91062306a36Sopenharmony_ci fs->hw.init = &init; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci clk = clk_register(NULL, &fs->hw); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (IS_ERR(clk)) 91562306a36Sopenharmony_ci kfree(fs); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci return clk; 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic void __init st_of_create_quadfs_fsynths( 92162306a36Sopenharmony_ci struct device_node *np, const char *pll_name, 92262306a36Sopenharmony_ci struct clkgen_quadfs_data_clks *quadfs, void __iomem *reg, 92362306a36Sopenharmony_ci spinlock_t *lock) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct clk_onecell_data *clk_data; 92662306a36Sopenharmony_ci int fschan; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 92962306a36Sopenharmony_ci if (!clk_data) 93062306a36Sopenharmony_ci return; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci clk_data->clk_num = QUADFS_MAX_CHAN; 93362306a36Sopenharmony_ci clk_data->clks = kcalloc(QUADFS_MAX_CHAN, sizeof(struct clk *), 93462306a36Sopenharmony_ci GFP_KERNEL); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (!clk_data->clks) { 93762306a36Sopenharmony_ci kfree(clk_data); 93862306a36Sopenharmony_ci return; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci for (fschan = 0; fschan < QUADFS_MAX_CHAN; fschan++) { 94262306a36Sopenharmony_ci struct clk *clk; 94362306a36Sopenharmony_ci const char *clk_name; 94462306a36Sopenharmony_ci unsigned long flags = 0; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (quadfs->outputs) { 94762306a36Sopenharmony_ci clk_name = quadfs->outputs[fschan].name; 94862306a36Sopenharmony_ci flags = quadfs->outputs[fschan].flags; 94962306a36Sopenharmony_ci } else { 95062306a36Sopenharmony_ci if (of_property_read_string_index(np, 95162306a36Sopenharmony_ci "clock-output-names", 95262306a36Sopenharmony_ci fschan, &clk_name)) 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci of_clk_detect_critical(np, fschan, &flags); 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci /* 95862306a36Sopenharmony_ci * If we read an empty clock name then the channel is unused 95962306a36Sopenharmony_ci */ 96062306a36Sopenharmony_ci if (*clk_name == '\0') 96162306a36Sopenharmony_ci continue; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci clk = st_clk_register_quadfs_fsynth(clk_name, pll_name, 96462306a36Sopenharmony_ci quadfs->data, reg, fschan, 96562306a36Sopenharmony_ci flags, lock); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* 96862306a36Sopenharmony_ci * If there was an error registering this clock output, clean 96962306a36Sopenharmony_ci * up and move on to the next one. 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ci if (!IS_ERR(clk)) { 97262306a36Sopenharmony_ci clk_data->clks[fschan] = clk; 97362306a36Sopenharmony_ci pr_debug("%s: parent %s rate %u\n", 97462306a36Sopenharmony_ci __clk_get_name(clk), 97562306a36Sopenharmony_ci __clk_get_name(clk_get_parent(clk)), 97662306a36Sopenharmony_ci (unsigned int)clk_get_rate(clk)); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic void __init st_of_quadfs_setup(struct device_node *np, 98462306a36Sopenharmony_ci struct clkgen_quadfs_data_clks *datac) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci struct clk *clk; 98762306a36Sopenharmony_ci const char *pll_name, *clk_parent_name; 98862306a36Sopenharmony_ci void __iomem *reg; 98962306a36Sopenharmony_ci spinlock_t *lock; 99062306a36Sopenharmony_ci struct device_node *parent_np; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* 99362306a36Sopenharmony_ci * First check for reg property within the node to keep backward 99462306a36Sopenharmony_ci * compatibility, then if reg doesn't exist look at the parent node 99562306a36Sopenharmony_ci */ 99662306a36Sopenharmony_ci reg = of_iomap(np, 0); 99762306a36Sopenharmony_ci if (!reg) { 99862306a36Sopenharmony_ci parent_np = of_get_parent(np); 99962306a36Sopenharmony_ci reg = of_iomap(parent_np, 0); 100062306a36Sopenharmony_ci of_node_put(parent_np); 100162306a36Sopenharmony_ci if (!reg) { 100262306a36Sopenharmony_ci pr_err("%s: Failed to get base address\n", __func__); 100362306a36Sopenharmony_ci return; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci clk_parent_name = of_clk_get_parent_name(np, 0); 100862306a36Sopenharmony_ci if (!clk_parent_name) 100962306a36Sopenharmony_ci return; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci pll_name = kasprintf(GFP_KERNEL, "%pOFn.pll", np); 101262306a36Sopenharmony_ci if (!pll_name) 101362306a36Sopenharmony_ci return; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci lock = kzalloc(sizeof(*lock), GFP_KERNEL); 101662306a36Sopenharmony_ci if (!lock) 101762306a36Sopenharmony_ci goto err_exit; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci spin_lock_init(lock); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, datac->data, 102262306a36Sopenharmony_ci reg, lock); 102362306a36Sopenharmony_ci if (IS_ERR(clk)) { 102462306a36Sopenharmony_ci kfree(lock); 102562306a36Sopenharmony_ci goto err_exit; 102662306a36Sopenharmony_ci } else 102762306a36Sopenharmony_ci pr_debug("%s: parent %s rate %u\n", 102862306a36Sopenharmony_ci __clk_get_name(clk), 102962306a36Sopenharmony_ci __clk_get_name(clk_get_parent(clk)), 103062306a36Sopenharmony_ci (unsigned int)clk_get_rate(clk)); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci st_of_create_quadfs_fsynths(np, pll_name, datac, reg, lock); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cierr_exit: 103562306a36Sopenharmony_ci kfree(pll_name); /* No longer need local copy of the PLL name */ 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic void __init st_of_quadfs660C_setup(struct device_node *np) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci st_of_quadfs_setup(np, 104162306a36Sopenharmony_ci (struct clkgen_quadfs_data_clks *) &st_fs660c32_C_data); 104262306a36Sopenharmony_ci} 104362306a36Sopenharmony_ciCLK_OF_DECLARE(quadfs660C, "st,quadfs-pll", st_of_quadfs660C_setup); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cistatic void __init st_of_quadfs660D_setup(struct device_node *np) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci st_of_quadfs_setup(np, 104862306a36Sopenharmony_ci (struct clkgen_quadfs_data_clks *) &st_fs660c32_D_data); 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ciCLK_OF_DECLARE(quadfs660D, "st,quadfs", st_of_quadfs660D_setup); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic void __init st_of_quadfs660D0_setup(struct device_node *np) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci st_of_quadfs_setup(np, 105562306a36Sopenharmony_ci (struct clkgen_quadfs_data_clks *) &st_fs660c32_D0_data); 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ciCLK_OF_DECLARE(quadfs660D0, "st,quadfs-d0", st_of_quadfs660D0_setup); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic void __init st_of_quadfs660D2_setup(struct device_node *np) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci st_of_quadfs_setup(np, 106262306a36Sopenharmony_ci (struct clkgen_quadfs_data_clks *) &st_fs660c32_D2_data); 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ciCLK_OF_DECLARE(quadfs660D2, "st,quadfs-d2", st_of_quadfs660D2_setup); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic void __init st_of_quadfs660D3_setup(struct device_node *np) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci st_of_quadfs_setup(np, 106962306a36Sopenharmony_ci (struct clkgen_quadfs_data_clks *) &st_fs660c32_D3_data); 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ciCLK_OF_DECLARE(quadfs660D3, "st,quadfs-d3", st_of_quadfs660D3_setup); 1072