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, ¶ms, &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, ¶ms))
3852dd52d7fSArnd Bergmann return rate;
3862dd52d7fSArnd Bergmann
3875f7aa907SGabriel FERNANDEZ clk_fs660c32_vco_get_rate(*prate, ¶ms, &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, ¶ms);
4099849fadfSArnd Bergmann if (ret)
4109849fadfSArnd Bergmann return ret;
4119849fadfSArnd Bergmann
4125f7aa907SGabriel FERNANDEZ clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &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, ¶ms))
8055f7aa907SGabriel FERNANDEZ return 0;
8065f7aa907SGabriel FERNANDEZ
8075f7aa907SGabriel FERNANDEZ if (clk_fs_get_rate(parent_rate, ¶ms, &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, ¶ms);
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(¶ms, 0, sizeof(struct stm_fs));
8605f7aa907SGabriel FERNANDEZ
8615f7aa907SGabriel FERNANDEZ hwrate = quadfs_find_best_rate(hw, rate, parent_rate, ¶ms);
8625f7aa907SGabriel FERNANDEZ if (!hwrate)
8635f7aa907SGabriel FERNANDEZ return -EINVAL;
8645f7aa907SGabriel FERNANDEZ
8655f7aa907SGabriel FERNANDEZ quadfs_program_and_enable(fs, ¶ms);
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