15f7aa907SGabriel FERNANDEZ /* 25f7aa907SGabriel FERNANDEZ * Copyright (C) 2014 STMicroelectronics R&D Ltd 35f7aa907SGabriel FERNANDEZ * 45f7aa907SGabriel FERNANDEZ * This program is free software; you can redistribute it and/or modify 55f7aa907SGabriel FERNANDEZ * it under the terms of the GNU General Public License version 2 as 65f7aa907SGabriel FERNANDEZ * published by the Free Software Foundation. 75f7aa907SGabriel FERNANDEZ * 85f7aa907SGabriel FERNANDEZ */ 95f7aa907SGabriel FERNANDEZ 105f7aa907SGabriel FERNANDEZ /* 115f7aa907SGabriel FERNANDEZ * Authors: 125f7aa907SGabriel FERNANDEZ * Stephen Gallimore <stephen.gallimore@st.com>, 135f7aa907SGabriel FERNANDEZ * Pankaj Dev <pankaj.dev@st.com>. 145f7aa907SGabriel FERNANDEZ */ 155f7aa907SGabriel FERNANDEZ 165f7aa907SGabriel FERNANDEZ #include <linux/slab.h> 175f7aa907SGabriel FERNANDEZ #include <linux/of_address.h> 185f7aa907SGabriel FERNANDEZ #include <linux/clk-provider.h> 195f7aa907SGabriel FERNANDEZ 205f7aa907SGabriel FERNANDEZ #include "clkgen.h" 215f7aa907SGabriel FERNANDEZ 225f7aa907SGabriel FERNANDEZ /* 235f7aa907SGabriel FERNANDEZ * Maximum input clock to the PLL before we divide it down by 2 245f7aa907SGabriel FERNANDEZ * although in reality in actual systems this has never been seen to 255f7aa907SGabriel FERNANDEZ * be used. 265f7aa907SGabriel FERNANDEZ */ 275f7aa907SGabriel FERNANDEZ #define QUADFS_NDIV_THRESHOLD 30000000 285f7aa907SGabriel FERNANDEZ 295f7aa907SGabriel FERNANDEZ #define PLL_BW_GOODREF (0L) 305f7aa907SGabriel FERNANDEZ #define PLL_BW_VBADREF (1L) 315f7aa907SGabriel FERNANDEZ #define PLL_BW_BADREF (2L) 325f7aa907SGabriel FERNANDEZ #define PLL_BW_VGOODREF (3L) 335f7aa907SGabriel FERNANDEZ 345f7aa907SGabriel FERNANDEZ #define QUADFS_MAX_CHAN 4 355f7aa907SGabriel FERNANDEZ 365f7aa907SGabriel FERNANDEZ struct stm_fs { 375f7aa907SGabriel FERNANDEZ unsigned long ndiv; 385f7aa907SGabriel FERNANDEZ unsigned long mdiv; 395f7aa907SGabriel FERNANDEZ unsigned long pe; 405f7aa907SGabriel FERNANDEZ unsigned long sdiv; 415f7aa907SGabriel FERNANDEZ unsigned long nsdiv; 425f7aa907SGabriel FERNANDEZ }; 435f7aa907SGabriel FERNANDEZ 444abb1b40SGabriel FERNANDEZ static const struct stm_fs fs216c65_rtbl[] = { 455f7aa907SGabriel FERNANDEZ { .mdiv = 0x1f, .pe = 0x0, .sdiv = 0x7, .nsdiv = 0 }, /* 312.5 Khz */ 465f7aa907SGabriel FERNANDEZ { .mdiv = 0x17, .pe = 0x25ed, .sdiv = 0x1, .nsdiv = 0 }, /* 27 MHz */ 475f7aa907SGabriel FERNANDEZ { .mdiv = 0x1a, .pe = 0x7b36, .sdiv = 0x2, .nsdiv = 1 }, /* 36.87 MHz */ 485f7aa907SGabriel FERNANDEZ { .mdiv = 0x13, .pe = 0x0, .sdiv = 0x2, .nsdiv = 1 }, /* 48 MHz */ 495f7aa907SGabriel FERNANDEZ { .mdiv = 0x11, .pe = 0x1c72, .sdiv = 0x1, .nsdiv = 1 }, /* 108 MHz */ 505f7aa907SGabriel FERNANDEZ }; 515f7aa907SGabriel FERNANDEZ 524abb1b40SGabriel FERNANDEZ static const struct stm_fs fs432c65_rtbl[] = { 535f7aa907SGabriel FERNANDEZ { .mdiv = 0x1f, .pe = 0x0, .sdiv = 0x7, .nsdiv = 0 }, /* 625 Khz */ 545f7aa907SGabriel FERNANDEZ { .mdiv = 0x11, .pe = 0x1c72, .sdiv = 0x2, .nsdiv = 1 }, /* 108 MHz */ 555f7aa907SGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x0, .nsdiv = 1 }, /* 297 MHz */ 565f7aa907SGabriel FERNANDEZ }; 575f7aa907SGabriel FERNANDEZ 584abb1b40SGabriel FERNANDEZ static const struct stm_fs fs660c32_rtbl[] = { 595f7aa907SGabriel FERNANDEZ { .mdiv = 0x01, .pe = 0x2aaa, .sdiv = 0x8, .nsdiv = 0 }, /* 600 KHz */ 605f7aa907SGabriel FERNANDEZ { .mdiv = 0x02, .pe = 0x3d33, .sdiv = 0x0, .nsdiv = 0 }, /* 148.5 Mhz */ 615f7aa907SGabriel FERNANDEZ { .mdiv = 0x13, .pe = 0x5bcc, .sdiv = 0x0, .nsdiv = 1 }, /* 297 Mhz */ 625f7aa907SGabriel FERNANDEZ { .mdiv = 0x0e, .pe = 0x1025, .sdiv = 0x0, .nsdiv = 1 }, /* 333 Mhz */ 635f7aa907SGabriel FERNANDEZ { .mdiv = 0x0b, .pe = 0x715f, .sdiv = 0x0, .nsdiv = 1 }, /* 350 Mhz */ 645f7aa907SGabriel FERNANDEZ }; 655f7aa907SGabriel FERNANDEZ 665f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data { 675f7aa907SGabriel FERNANDEZ bool reset_present; 685f7aa907SGabriel FERNANDEZ bool bwfilter_present; 695f7aa907SGabriel FERNANDEZ bool lockstatus_present; 708f26df84SGabriel FERNANDEZ bool powerup_polarity; 718f26df84SGabriel FERNANDEZ bool standby_polarity; 725f7aa907SGabriel FERNANDEZ bool nsdiv_present; 73fc755c8bSGabriel FERNANDEZ bool nrst_present; 745f7aa907SGabriel FERNANDEZ struct clkgen_field ndiv; 755f7aa907SGabriel FERNANDEZ struct clkgen_field ref_bw; 765f7aa907SGabriel FERNANDEZ struct clkgen_field nreset; 775f7aa907SGabriel FERNANDEZ struct clkgen_field npda; 785f7aa907SGabriel FERNANDEZ struct clkgen_field lock_status; 795f7aa907SGabriel FERNANDEZ 80fc755c8bSGabriel FERNANDEZ struct clkgen_field nrst[QUADFS_MAX_CHAN]; 815f7aa907SGabriel FERNANDEZ struct clkgen_field nsb[QUADFS_MAX_CHAN]; 825f7aa907SGabriel FERNANDEZ struct clkgen_field en[QUADFS_MAX_CHAN]; 835f7aa907SGabriel FERNANDEZ struct clkgen_field mdiv[QUADFS_MAX_CHAN]; 845f7aa907SGabriel FERNANDEZ struct clkgen_field pe[QUADFS_MAX_CHAN]; 855f7aa907SGabriel FERNANDEZ struct clkgen_field sdiv[QUADFS_MAX_CHAN]; 865f7aa907SGabriel FERNANDEZ struct clkgen_field nsdiv[QUADFS_MAX_CHAN]; 875f7aa907SGabriel FERNANDEZ 885f7aa907SGabriel FERNANDEZ const struct clk_ops *pll_ops; 894abb1b40SGabriel FERNANDEZ const struct stm_fs *rtbl; 905f7aa907SGabriel FERNANDEZ u8 rtbl_cnt; 914abb1b40SGabriel FERNANDEZ int (*get_rate)(unsigned long , const struct stm_fs *, 925f7aa907SGabriel FERNANDEZ unsigned long *); 935f7aa907SGabriel FERNANDEZ }; 945f7aa907SGabriel FERNANDEZ 955f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c65_ops; 965f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c32_ops; 975f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_fs216c65_ops; 985f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_fs432c65_ops; 995f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_fs660c32_ops; 1005f7aa907SGabriel FERNANDEZ 1014abb1b40SGabriel FERNANDEZ static int clk_fs216c65_get_rate(unsigned long, const struct stm_fs *, 1025f7aa907SGabriel FERNANDEZ unsigned long *); 1034abb1b40SGabriel FERNANDEZ static int clk_fs432c65_get_rate(unsigned long, const struct stm_fs *, 1045f7aa907SGabriel FERNANDEZ unsigned long *); 1054abb1b40SGabriel FERNANDEZ static int clk_fs660c32_dig_get_rate(unsigned long, const struct stm_fs *, 1065f7aa907SGabriel FERNANDEZ unsigned long *); 1075f7aa907SGabriel FERNANDEZ /* 1085f7aa907SGabriel FERNANDEZ * Values for all of the standalone instances of this clock 1095f7aa907SGabriel FERNANDEZ * generator found in STiH415 and STiH416 SYSCFG register banks. Note 1105f7aa907SGabriel FERNANDEZ * that the individual channel standby control bits (nsb) are in the 1115f7aa907SGabriel FERNANDEZ * first register along with the PLL control bits. 1125f7aa907SGabriel FERNANDEZ */ 1134abb1b40SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs216c65_416 = { 1145f7aa907SGabriel FERNANDEZ /* 416 specific */ 1155f7aa907SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x0, 0x1, 14), 1165f7aa907SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), 1175f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 11), 1185f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 12), 1195f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 13) }, 1205f7aa907SGabriel FERNANDEZ .nsdiv_present = true, 1215f7aa907SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), 1225f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 19), 1235f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 20), 1245f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 21) }, 1255f7aa907SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), 1265f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x14, 0x1f, 0), 1275f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x24, 0x1f, 0), 1285f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x34, 0x1f, 0) }, 1295f7aa907SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x10, 0x1, 0), 1305f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x20, 0x1, 0), 1315f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x30, 0x1, 0), 1325f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x40, 0x1, 0) }, 1335f7aa907SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x0, 0x1, 15), 1345f7aa907SGabriel FERNANDEZ .bwfilter_present = true, 1355f7aa907SGabriel FERNANDEZ .ref_bw = CLKGEN_FIELD(0x0, 0x3, 16), 1365f7aa907SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x8, 0xffff, 0), 1375f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x18, 0xffff, 0), 1385f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x28, 0xffff, 0), 1395f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x38, 0xffff, 0) }, 1405f7aa907SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0xC, 0x7, 0), 1415f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x1C, 0x7, 0), 1425f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x2C, 0x7, 0), 1435f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x3C, 0x7, 0) }, 1445f7aa907SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c65_ops, 1455f7aa907SGabriel FERNANDEZ .rtbl = fs216c65_rtbl, 1465f7aa907SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs216c65_rtbl), 1475f7aa907SGabriel FERNANDEZ .get_rate = clk_fs216c65_get_rate, 1485f7aa907SGabriel FERNANDEZ }; 1495f7aa907SGabriel FERNANDEZ 1504abb1b40SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs432c65_416 = { 1515f7aa907SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x0, 0x1, 14), 1525f7aa907SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), 1535f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 11), 1545f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 12), 1555f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 13) }, 1565f7aa907SGabriel FERNANDEZ .nsdiv_present = true, 1575f7aa907SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), 1585f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 19), 1595f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 20), 1605f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 21) }, 1615f7aa907SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), 1625f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x14, 0x1f, 0), 1635f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x24, 0x1f, 0), 1645f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x34, 0x1f, 0) }, 1655f7aa907SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x10, 0x1, 0), 1665f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x20, 0x1, 0), 1675f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x30, 0x1, 0), 1685f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x40, 0x1, 0) }, 1695f7aa907SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x0, 0x1, 15), 1705f7aa907SGabriel FERNANDEZ .bwfilter_present = true, 1715f7aa907SGabriel FERNANDEZ .ref_bw = CLKGEN_FIELD(0x0, 0x3, 16), 1725f7aa907SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x8, 0xffff, 0), 1735f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x18, 0xffff, 0), 1745f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x28, 0xffff, 0), 1755f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x38, 0xffff, 0) }, 1765f7aa907SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0xC, 0x7, 0), 1775f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x1C, 0x7, 0), 1785f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x2C, 0x7, 0), 1795f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x3C, 0x7, 0) }, 1805f7aa907SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c65_ops, 1815f7aa907SGabriel FERNANDEZ .rtbl = fs432c65_rtbl, 1825f7aa907SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs432c65_rtbl), 1835f7aa907SGabriel FERNANDEZ .get_rate = clk_fs432c65_get_rate, 1845f7aa907SGabriel FERNANDEZ }; 1855f7aa907SGabriel FERNANDEZ 1864abb1b40SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs660c32_E_416 = { 1875f7aa907SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x0, 0x1, 14), 1885f7aa907SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), 1895f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 11), 1905f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 12), 1915f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 13) }, 1925f7aa907SGabriel FERNANDEZ .nsdiv_present = true, 1935f7aa907SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), 1945f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 19), 1955f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 20), 1965f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 21) }, 1975f7aa907SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), 1985f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x14, 0x1f, 0), 1995f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x24, 0x1f, 0), 2005f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x34, 0x1f, 0) }, 2015f7aa907SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x10, 0x1, 0), 2025f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x20, 0x1, 0), 2035f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x30, 0x1, 0), 2045f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x40, 0x1, 0) }, 2055f7aa907SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x0, 0x7, 15), 2065f7aa907SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x8, 0x7fff, 0), 2075f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x18, 0x7fff, 0), 2085f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x28, 0x7fff, 0), 2095f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x38, 0x7fff, 0) }, 2105f7aa907SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0xC, 0xf, 0), 2115f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x1C, 0xf, 0), 2125f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x2C, 0xf, 0), 2135f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x3C, 0xf, 0) }, 2145f7aa907SGabriel FERNANDEZ .lockstatus_present = true, 2155f7aa907SGabriel FERNANDEZ .lock_status = CLKGEN_FIELD(0xAC, 0x1, 0), 2165f7aa907SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c32_ops, 2175f7aa907SGabriel FERNANDEZ .rtbl = fs660c32_rtbl, 2185f7aa907SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), 2195f7aa907SGabriel FERNANDEZ .get_rate = clk_fs660c32_dig_get_rate, 2205f7aa907SGabriel FERNANDEZ }; 2215f7aa907SGabriel FERNANDEZ 2224abb1b40SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs660c32_F_416 = { 2235f7aa907SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x0, 0x1, 14), 2245f7aa907SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), 2255f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 11), 2265f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 12), 2275f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 13) }, 2285f7aa907SGabriel FERNANDEZ .nsdiv_present = true, 2295f7aa907SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), 2305f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 19), 2315f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 20), 2325f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 21) }, 2335f7aa907SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), 2345f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x14, 0x1f, 0), 2355f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x24, 0x1f, 0), 2365f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x34, 0x1f, 0) }, 2375f7aa907SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x10, 0x1, 0), 2385f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x20, 0x1, 0), 2395f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x30, 0x1, 0), 2405f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x40, 0x1, 0) }, 2415f7aa907SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x0, 0x7, 15), 2425f7aa907SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x8, 0x7fff, 0), 2435f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x18, 0x7fff, 0), 2445f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x28, 0x7fff, 0), 2455f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x38, 0x7fff, 0) }, 2465f7aa907SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0xC, 0xf, 0), 2475f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x1C, 0xf, 0), 2485f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x2C, 0xf, 0), 2495f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x3C, 0xf, 0) }, 2505f7aa907SGabriel FERNANDEZ .lockstatus_present = true, 2515f7aa907SGabriel FERNANDEZ .lock_status = CLKGEN_FIELD(0xEC, 0x1, 0), 2525f7aa907SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c32_ops, 2535f7aa907SGabriel FERNANDEZ .rtbl = fs660c32_rtbl, 2545f7aa907SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), 2555f7aa907SGabriel FERNANDEZ .get_rate = clk_fs660c32_dig_get_rate, 2565f7aa907SGabriel FERNANDEZ }; 2575f7aa907SGabriel FERNANDEZ 2585f7aa907SGabriel FERNANDEZ /** 2595f7aa907SGabriel FERNANDEZ * DOC: A Frequency Synthesizer that multiples its input clock by a fixed factor 2605f7aa907SGabriel FERNANDEZ * 2615f7aa907SGabriel FERNANDEZ * Traits of this clock: 2625f7aa907SGabriel FERNANDEZ * prepare - clk_(un)prepare only ensures parent is (un)prepared 2635f7aa907SGabriel FERNANDEZ * enable - clk_enable and clk_disable are functional & control the Fsyn 2645f7aa907SGabriel FERNANDEZ * rate - inherits rate from parent. set_rate/round_rate/recalc_rate 2655f7aa907SGabriel FERNANDEZ * parent - fixed parent. No clk_set_parent support 2665f7aa907SGabriel FERNANDEZ */ 2675f7aa907SGabriel FERNANDEZ 2685f7aa907SGabriel FERNANDEZ /** 2695f7aa907SGabriel FERNANDEZ * struct st_clk_quadfs_pll - A pll which outputs a fixed multiplier of 2705f7aa907SGabriel FERNANDEZ * its parent clock, found inside a type of 2715f7aa907SGabriel FERNANDEZ * ST quad channel frequency synthesizer block 2725f7aa907SGabriel FERNANDEZ * 2735f7aa907SGabriel FERNANDEZ * @hw: handle between common and hardware-specific interfaces. 2745f7aa907SGabriel FERNANDEZ * @ndiv: regmap field for the ndiv control. 2755f7aa907SGabriel FERNANDEZ * @regs_base: base address of the configuration registers. 2765f7aa907SGabriel FERNANDEZ * @lock: spinlock. 2775f7aa907SGabriel FERNANDEZ * 2785f7aa907SGabriel FERNANDEZ */ 2795f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll { 2805f7aa907SGabriel FERNANDEZ struct clk_hw hw; 2815f7aa907SGabriel FERNANDEZ void __iomem *regs_base; 2825f7aa907SGabriel FERNANDEZ spinlock_t *lock; 2835f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *data; 2845f7aa907SGabriel FERNANDEZ u32 ndiv; 2855f7aa907SGabriel FERNANDEZ }; 2865f7aa907SGabriel FERNANDEZ 2875f7aa907SGabriel FERNANDEZ #define to_quadfs_pll(_hw) container_of(_hw, struct st_clk_quadfs_pll, hw) 2885f7aa907SGabriel FERNANDEZ 2895f7aa907SGabriel FERNANDEZ static int quadfs_pll_enable(struct clk_hw *hw) 2905f7aa907SGabriel FERNANDEZ { 2915f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 2925f7aa907SGabriel FERNANDEZ unsigned long flags = 0, timeout = jiffies + msecs_to_jiffies(10); 2935f7aa907SGabriel FERNANDEZ 2945f7aa907SGabriel FERNANDEZ if (pll->lock) 2955f7aa907SGabriel FERNANDEZ spin_lock_irqsave(pll->lock, flags); 2965f7aa907SGabriel FERNANDEZ 2975f7aa907SGabriel FERNANDEZ /* 2985f7aa907SGabriel FERNANDEZ * Bring block out of reset if we have reset control. 2995f7aa907SGabriel FERNANDEZ */ 3005f7aa907SGabriel FERNANDEZ if (pll->data->reset_present) 3015f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, nreset, 1); 3025f7aa907SGabriel FERNANDEZ 3035f7aa907SGabriel FERNANDEZ /* 3045f7aa907SGabriel FERNANDEZ * Use a fixed input clock noise bandwidth filter for the moment 3055f7aa907SGabriel FERNANDEZ */ 3065f7aa907SGabriel FERNANDEZ if (pll->data->bwfilter_present) 3075f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, ref_bw, PLL_BW_GOODREF); 3085f7aa907SGabriel FERNANDEZ 3095f7aa907SGabriel FERNANDEZ 3105f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, ndiv, pll->ndiv); 3115f7aa907SGabriel FERNANDEZ 3125f7aa907SGabriel FERNANDEZ /* 3135f7aa907SGabriel FERNANDEZ * Power up the PLL 3145f7aa907SGabriel FERNANDEZ */ 3158f26df84SGabriel FERNANDEZ CLKGEN_WRITE(pll, npda, !pll->data->powerup_polarity); 3165f7aa907SGabriel FERNANDEZ 3175f7aa907SGabriel FERNANDEZ if (pll->lock) 3185f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(pll->lock, flags); 3195f7aa907SGabriel FERNANDEZ 3205f7aa907SGabriel FERNANDEZ if (pll->data->lockstatus_present) 3215f7aa907SGabriel FERNANDEZ while (!CLKGEN_READ(pll, lock_status)) { 3225f7aa907SGabriel FERNANDEZ if (time_after(jiffies, timeout)) 3235f7aa907SGabriel FERNANDEZ return -ETIMEDOUT; 3245f7aa907SGabriel FERNANDEZ cpu_relax(); 3255f7aa907SGabriel FERNANDEZ } 3265f7aa907SGabriel FERNANDEZ 3275f7aa907SGabriel FERNANDEZ return 0; 3285f7aa907SGabriel FERNANDEZ } 3295f7aa907SGabriel FERNANDEZ 3305f7aa907SGabriel FERNANDEZ static void quadfs_pll_disable(struct clk_hw *hw) 3315f7aa907SGabriel FERNANDEZ { 3325f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 3335f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 3345f7aa907SGabriel FERNANDEZ 3355f7aa907SGabriel FERNANDEZ if (pll->lock) 3365f7aa907SGabriel FERNANDEZ spin_lock_irqsave(pll->lock, flags); 3375f7aa907SGabriel FERNANDEZ 3385f7aa907SGabriel FERNANDEZ /* 3395f7aa907SGabriel FERNANDEZ * Powerdown the PLL and then put block into soft reset if we have 3405f7aa907SGabriel FERNANDEZ * reset control. 3415f7aa907SGabriel FERNANDEZ */ 3428f26df84SGabriel FERNANDEZ CLKGEN_WRITE(pll, npda, pll->data->powerup_polarity); 3435f7aa907SGabriel FERNANDEZ 3445f7aa907SGabriel FERNANDEZ if (pll->data->reset_present) 3455f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, nreset, 0); 3465f7aa907SGabriel FERNANDEZ 3475f7aa907SGabriel FERNANDEZ if (pll->lock) 3485f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(pll->lock, flags); 3495f7aa907SGabriel FERNANDEZ } 3505f7aa907SGabriel FERNANDEZ 3515f7aa907SGabriel FERNANDEZ static int quadfs_pll_is_enabled(struct clk_hw *hw) 3525f7aa907SGabriel FERNANDEZ { 3535f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 3545f7aa907SGabriel FERNANDEZ u32 npda = CLKGEN_READ(pll, npda); 3555f7aa907SGabriel FERNANDEZ 3565f7aa907SGabriel FERNANDEZ return !!npda; 3575f7aa907SGabriel FERNANDEZ } 3585f7aa907SGabriel FERNANDEZ 3595f7aa907SGabriel FERNANDEZ int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs, 3605f7aa907SGabriel FERNANDEZ unsigned long *rate) 3615f7aa907SGabriel FERNANDEZ { 3625f7aa907SGabriel FERNANDEZ unsigned long nd = fs->ndiv + 16; /* ndiv value */ 3635f7aa907SGabriel FERNANDEZ 3645f7aa907SGabriel FERNANDEZ *rate = input * nd; 3655f7aa907SGabriel FERNANDEZ 3665f7aa907SGabriel FERNANDEZ return 0; 3675f7aa907SGabriel FERNANDEZ } 3685f7aa907SGabriel FERNANDEZ 3695f7aa907SGabriel FERNANDEZ static unsigned long quadfs_pll_fs660c32_recalc_rate(struct clk_hw *hw, 3705f7aa907SGabriel FERNANDEZ unsigned long parent_rate) 3715f7aa907SGabriel FERNANDEZ { 3725f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 3735f7aa907SGabriel FERNANDEZ unsigned long rate = 0; 3745f7aa907SGabriel FERNANDEZ struct stm_fs params; 3755f7aa907SGabriel FERNANDEZ 3765f7aa907SGabriel FERNANDEZ params.ndiv = CLKGEN_READ(pll, ndiv); 3775f7aa907SGabriel FERNANDEZ if (clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &rate)) 3785f7aa907SGabriel FERNANDEZ pr_err("%s:%s error calculating rate\n", 3795f7aa907SGabriel FERNANDEZ __clk_get_name(hw->clk), __func__); 3805f7aa907SGabriel FERNANDEZ 3815f7aa907SGabriel FERNANDEZ pll->ndiv = params.ndiv; 3825f7aa907SGabriel FERNANDEZ 3835f7aa907SGabriel FERNANDEZ return rate; 3845f7aa907SGabriel FERNANDEZ } 3855f7aa907SGabriel FERNANDEZ 3865f7aa907SGabriel FERNANDEZ int clk_fs660c32_vco_get_params(unsigned long input, 3875f7aa907SGabriel FERNANDEZ unsigned long output, struct stm_fs *fs) 3885f7aa907SGabriel FERNANDEZ { 3895f7aa907SGabriel FERNANDEZ /* Formula 3905f7aa907SGabriel FERNANDEZ VCO frequency = (fin x ndiv) / pdiv 3915f7aa907SGabriel FERNANDEZ ndiv = VCOfreq * pdiv / fin 3925f7aa907SGabriel FERNANDEZ */ 3935f7aa907SGabriel FERNANDEZ unsigned long pdiv = 1, n; 3945f7aa907SGabriel FERNANDEZ 3955f7aa907SGabriel FERNANDEZ /* Output clock range: 384Mhz to 660Mhz */ 3965f7aa907SGabriel FERNANDEZ if (output < 384000000 || output > 660000000) 3975f7aa907SGabriel FERNANDEZ return -EINVAL; 3985f7aa907SGabriel FERNANDEZ 3995f7aa907SGabriel FERNANDEZ if (input > 40000000) 4005f7aa907SGabriel FERNANDEZ /* This means that PDIV would be 2 instead of 1. 4015f7aa907SGabriel FERNANDEZ Not supported today. */ 4025f7aa907SGabriel FERNANDEZ return -EINVAL; 4035f7aa907SGabriel FERNANDEZ 4045f7aa907SGabriel FERNANDEZ input /= 1000; 4055f7aa907SGabriel FERNANDEZ output /= 1000; 4065f7aa907SGabriel FERNANDEZ 4075f7aa907SGabriel FERNANDEZ n = output * pdiv / input; 4085f7aa907SGabriel FERNANDEZ if (n < 16) 4095f7aa907SGabriel FERNANDEZ n = 16; 4105f7aa907SGabriel FERNANDEZ fs->ndiv = n - 16; /* Converting formula value to reg value */ 4115f7aa907SGabriel FERNANDEZ 4125f7aa907SGabriel FERNANDEZ return 0; 4135f7aa907SGabriel FERNANDEZ } 4145f7aa907SGabriel FERNANDEZ 4155f7aa907SGabriel FERNANDEZ static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, unsigned long rate 4165f7aa907SGabriel FERNANDEZ , unsigned long *prate) 4175f7aa907SGabriel FERNANDEZ { 4185f7aa907SGabriel FERNANDEZ struct stm_fs params; 4195f7aa907SGabriel FERNANDEZ 4205f7aa907SGabriel FERNANDEZ if (!clk_fs660c32_vco_get_params(*prate, rate, ¶ms)) 4215f7aa907SGabriel FERNANDEZ clk_fs660c32_vco_get_rate(*prate, ¶ms, &rate); 4225f7aa907SGabriel FERNANDEZ 4235f7aa907SGabriel FERNANDEZ pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n", 4245f7aa907SGabriel FERNANDEZ __func__, __clk_get_name(hw->clk), 4255f7aa907SGabriel FERNANDEZ rate, (unsigned int)params.sdiv, 4265f7aa907SGabriel FERNANDEZ (unsigned int)params.mdiv, 4275f7aa907SGabriel FERNANDEZ (unsigned int)params.pe, (unsigned int)params.nsdiv); 4285f7aa907SGabriel FERNANDEZ 4295f7aa907SGabriel FERNANDEZ return rate; 4305f7aa907SGabriel FERNANDEZ } 4315f7aa907SGabriel FERNANDEZ 4325f7aa907SGabriel FERNANDEZ static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate, 4335f7aa907SGabriel FERNANDEZ unsigned long parent_rate) 4345f7aa907SGabriel FERNANDEZ { 4355f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 4365f7aa907SGabriel FERNANDEZ struct stm_fs params; 4375f7aa907SGabriel FERNANDEZ long hwrate = 0; 4385f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 4395f7aa907SGabriel FERNANDEZ 4405f7aa907SGabriel FERNANDEZ if (!rate || !parent_rate) 4415f7aa907SGabriel FERNANDEZ return -EINVAL; 4425f7aa907SGabriel FERNANDEZ 4435f7aa907SGabriel FERNANDEZ if (!clk_fs660c32_vco_get_params(parent_rate, rate, ¶ms)) 4445f7aa907SGabriel FERNANDEZ clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &hwrate); 4455f7aa907SGabriel FERNANDEZ 4465f7aa907SGabriel FERNANDEZ pr_debug("%s: %s new rate %ld [ndiv=0x%x]\n", 4475f7aa907SGabriel FERNANDEZ __func__, __clk_get_name(hw->clk), 4485f7aa907SGabriel FERNANDEZ hwrate, (unsigned int)params.ndiv); 4495f7aa907SGabriel FERNANDEZ 4505f7aa907SGabriel FERNANDEZ if (!hwrate) 4515f7aa907SGabriel FERNANDEZ return -EINVAL; 4525f7aa907SGabriel FERNANDEZ 4535f7aa907SGabriel FERNANDEZ pll->ndiv = params.ndiv; 4545f7aa907SGabriel FERNANDEZ 4555f7aa907SGabriel FERNANDEZ if (pll->lock) 4565f7aa907SGabriel FERNANDEZ spin_lock_irqsave(pll->lock, flags); 4575f7aa907SGabriel FERNANDEZ 4585f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, ndiv, pll->ndiv); 4595f7aa907SGabriel FERNANDEZ 4605f7aa907SGabriel FERNANDEZ if (pll->lock) 4615f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(pll->lock, flags); 4625f7aa907SGabriel FERNANDEZ 4635f7aa907SGabriel FERNANDEZ return 0; 4645f7aa907SGabriel FERNANDEZ } 4655f7aa907SGabriel FERNANDEZ 4665f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c65_ops = { 4675f7aa907SGabriel FERNANDEZ .enable = quadfs_pll_enable, 4685f7aa907SGabriel FERNANDEZ .disable = quadfs_pll_disable, 4695f7aa907SGabriel FERNANDEZ .is_enabled = quadfs_pll_is_enabled, 4705f7aa907SGabriel FERNANDEZ }; 4715f7aa907SGabriel FERNANDEZ 4725f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c32_ops = { 4735f7aa907SGabriel FERNANDEZ .enable = quadfs_pll_enable, 4745f7aa907SGabriel FERNANDEZ .disable = quadfs_pll_disable, 4755f7aa907SGabriel FERNANDEZ .is_enabled = quadfs_pll_is_enabled, 4765f7aa907SGabriel FERNANDEZ .recalc_rate = quadfs_pll_fs660c32_recalc_rate, 4775f7aa907SGabriel FERNANDEZ .round_rate = quadfs_pll_fs660c32_round_rate, 4785f7aa907SGabriel FERNANDEZ .set_rate = quadfs_pll_fs660c32_set_rate, 4795f7aa907SGabriel FERNANDEZ }; 4805f7aa907SGabriel FERNANDEZ 4815f7aa907SGabriel FERNANDEZ static struct clk * __init st_clk_register_quadfs_pll( 4825f7aa907SGabriel FERNANDEZ const char *name, const char *parent_name, 4835f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *quadfs, void __iomem *reg, 4845f7aa907SGabriel FERNANDEZ spinlock_t *lock) 4855f7aa907SGabriel FERNANDEZ { 4865f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll; 4875f7aa907SGabriel FERNANDEZ struct clk *clk; 4885f7aa907SGabriel FERNANDEZ struct clk_init_data init; 4895f7aa907SGabriel FERNANDEZ 4905f7aa907SGabriel FERNANDEZ /* 4915f7aa907SGabriel FERNANDEZ * Sanity check required pointers. 4925f7aa907SGabriel FERNANDEZ */ 4935f7aa907SGabriel FERNANDEZ if (WARN_ON(!name || !parent_name)) 4945f7aa907SGabriel FERNANDEZ return ERR_PTR(-EINVAL); 4955f7aa907SGabriel FERNANDEZ 4965f7aa907SGabriel FERNANDEZ pll = kzalloc(sizeof(*pll), GFP_KERNEL); 4975f7aa907SGabriel FERNANDEZ if (!pll) 4985f7aa907SGabriel FERNANDEZ return ERR_PTR(-ENOMEM); 4995f7aa907SGabriel FERNANDEZ 5005f7aa907SGabriel FERNANDEZ init.name = name; 5015f7aa907SGabriel FERNANDEZ init.ops = quadfs->pll_ops; 5025f7aa907SGabriel FERNANDEZ init.flags = CLK_IS_BASIC; 5035f7aa907SGabriel FERNANDEZ init.parent_names = &parent_name; 5045f7aa907SGabriel FERNANDEZ init.num_parents = 1; 5055f7aa907SGabriel FERNANDEZ 5065f7aa907SGabriel FERNANDEZ pll->data = quadfs; 5075f7aa907SGabriel FERNANDEZ pll->regs_base = reg; 5085f7aa907SGabriel FERNANDEZ pll->lock = lock; 5095f7aa907SGabriel FERNANDEZ pll->hw.init = &init; 5105f7aa907SGabriel FERNANDEZ 5115f7aa907SGabriel FERNANDEZ clk = clk_register(NULL, &pll->hw); 5125f7aa907SGabriel FERNANDEZ 5135f7aa907SGabriel FERNANDEZ if (IS_ERR(clk)) 5145f7aa907SGabriel FERNANDEZ kfree(pll); 5155f7aa907SGabriel FERNANDEZ 5165f7aa907SGabriel FERNANDEZ return clk; 5175f7aa907SGabriel FERNANDEZ } 5185f7aa907SGabriel FERNANDEZ 5195f7aa907SGabriel FERNANDEZ /** 5205f7aa907SGabriel FERNANDEZ * DOC: A digital frequency synthesizer 5215f7aa907SGabriel FERNANDEZ * 5225f7aa907SGabriel FERNANDEZ * Traits of this clock: 5235f7aa907SGabriel FERNANDEZ * prepare - clk_(un)prepare only ensures parent is (un)prepared 5245f7aa907SGabriel FERNANDEZ * enable - clk_enable and clk_disable are functional 5255f7aa907SGabriel FERNANDEZ * rate - set rate is functional 5265f7aa907SGabriel FERNANDEZ * parent - fixed parent. No clk_set_parent support 5275f7aa907SGabriel FERNANDEZ */ 5285f7aa907SGabriel FERNANDEZ 5295f7aa907SGabriel FERNANDEZ /** 5305f7aa907SGabriel FERNANDEZ * struct st_clk_quadfs_fsynth - One clock output from a four channel digital 5315f7aa907SGabriel FERNANDEZ * frequency synthesizer (fsynth) block. 5325f7aa907SGabriel FERNANDEZ * 5335f7aa907SGabriel FERNANDEZ * @hw: handle between common and hardware-specific interfaces 5345f7aa907SGabriel FERNANDEZ * 5355f7aa907SGabriel FERNANDEZ * @nsb: regmap field in the output control register for the digital 5365f7aa907SGabriel FERNANDEZ * standby of this fsynth channel. This control is active low so 5375f7aa907SGabriel FERNANDEZ * the channel is in standby when the control bit is cleared. 5385f7aa907SGabriel FERNANDEZ * 5395f7aa907SGabriel FERNANDEZ * @nsdiv: regmap field in the output control register for 5405f7aa907SGabriel FERNANDEZ * for the optional divide by 3 of this fsynth channel. This control 5415f7aa907SGabriel FERNANDEZ * is active low so the divide by 3 is active when the control bit is 5425f7aa907SGabriel FERNANDEZ * cleared and the divide is bypassed when the bit is set. 5435f7aa907SGabriel FERNANDEZ */ 5445f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth { 5455f7aa907SGabriel FERNANDEZ struct clk_hw hw; 5465f7aa907SGabriel FERNANDEZ void __iomem *regs_base; 5475f7aa907SGabriel FERNANDEZ spinlock_t *lock; 5485f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *data; 5495f7aa907SGabriel FERNANDEZ 5505f7aa907SGabriel FERNANDEZ u32 chan; 5515f7aa907SGabriel FERNANDEZ /* 5525f7aa907SGabriel FERNANDEZ * Cached hardware values from set_rate so we can program the 5535f7aa907SGabriel FERNANDEZ * hardware in enable. There are two reasons for this: 5545f7aa907SGabriel FERNANDEZ * 5555f7aa907SGabriel FERNANDEZ * 1. The registers may not be writable until the parent has been 5565f7aa907SGabriel FERNANDEZ * enabled. 5575f7aa907SGabriel FERNANDEZ * 5585f7aa907SGabriel FERNANDEZ * 2. It restores the clock rate when a driver does an enable 5595f7aa907SGabriel FERNANDEZ * on PM restore, after a suspend to RAM has lost the hardware 5605f7aa907SGabriel FERNANDEZ * setup. 5615f7aa907SGabriel FERNANDEZ */ 5625f7aa907SGabriel FERNANDEZ u32 md; 5635f7aa907SGabriel FERNANDEZ u32 pe; 5645f7aa907SGabriel FERNANDEZ u32 sdiv; 5655f7aa907SGabriel FERNANDEZ u32 nsdiv; 5665f7aa907SGabriel FERNANDEZ }; 5675f7aa907SGabriel FERNANDEZ 5685f7aa907SGabriel FERNANDEZ #define to_quadfs_fsynth(_hw) \ 5695f7aa907SGabriel FERNANDEZ container_of(_hw, struct st_clk_quadfs_fsynth, hw) 5705f7aa907SGabriel FERNANDEZ 5715f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_program_enable(struct st_clk_quadfs_fsynth *fs) 5725f7aa907SGabriel FERNANDEZ { 5735f7aa907SGabriel FERNANDEZ /* 5745f7aa907SGabriel FERNANDEZ * Pulse the program enable register lsb to make the hardware take 5755f7aa907SGabriel FERNANDEZ * notice of the new md/pe values with a glitchless transition. 5765f7aa907SGabriel FERNANDEZ */ 5775f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, en[fs->chan], 1); 5785f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, en[fs->chan], 0); 5795f7aa907SGabriel FERNANDEZ } 5805f7aa907SGabriel FERNANDEZ 5815f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_program_rate(struct st_clk_quadfs_fsynth *fs) 5825f7aa907SGabriel FERNANDEZ { 5835f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 5845f7aa907SGabriel FERNANDEZ 5855f7aa907SGabriel FERNANDEZ /* 5865f7aa907SGabriel FERNANDEZ * Ensure the md/pe parameters are ignored while we are 5875f7aa907SGabriel FERNANDEZ * reprogramming them so we can get a glitchless change 5885f7aa907SGabriel FERNANDEZ * when fine tuning the speed of a running clock. 5895f7aa907SGabriel FERNANDEZ */ 5905f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, en[fs->chan], 0); 5915f7aa907SGabriel FERNANDEZ 5925f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, mdiv[fs->chan], fs->md); 5935f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, pe[fs->chan], fs->pe); 5945f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, sdiv[fs->chan], fs->sdiv); 5955f7aa907SGabriel FERNANDEZ 5965f7aa907SGabriel FERNANDEZ if (fs->lock) 5975f7aa907SGabriel FERNANDEZ spin_lock_irqsave(fs->lock, flags); 5985f7aa907SGabriel FERNANDEZ 5995f7aa907SGabriel FERNANDEZ if (fs->data->nsdiv_present) 6005f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, nsdiv[fs->chan], fs->nsdiv); 6015f7aa907SGabriel FERNANDEZ 6025f7aa907SGabriel FERNANDEZ if (fs->lock) 6035f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(fs->lock, flags); 6045f7aa907SGabriel FERNANDEZ } 6055f7aa907SGabriel FERNANDEZ 6065f7aa907SGabriel FERNANDEZ static int quadfs_fsynth_enable(struct clk_hw *hw) 6075f7aa907SGabriel FERNANDEZ { 6085f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 6095f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 6105f7aa907SGabriel FERNANDEZ 6115f7aa907SGabriel FERNANDEZ pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); 6125f7aa907SGabriel FERNANDEZ 6135f7aa907SGabriel FERNANDEZ quadfs_fsynth_program_rate(fs); 6145f7aa907SGabriel FERNANDEZ 6155f7aa907SGabriel FERNANDEZ if (fs->lock) 6165f7aa907SGabriel FERNANDEZ spin_lock_irqsave(fs->lock, flags); 6175f7aa907SGabriel FERNANDEZ 6188f26df84SGabriel FERNANDEZ CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity); 6195f7aa907SGabriel FERNANDEZ 620fc755c8bSGabriel FERNANDEZ if (fs->data->nrst_present) 621fc755c8bSGabriel FERNANDEZ CLKGEN_WRITE(fs, nrst[fs->chan], 0); 622fc755c8bSGabriel FERNANDEZ 6235f7aa907SGabriel FERNANDEZ if (fs->lock) 6245f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(fs->lock, flags); 6255f7aa907SGabriel FERNANDEZ 6265f7aa907SGabriel FERNANDEZ quadfs_fsynth_program_enable(fs); 6275f7aa907SGabriel FERNANDEZ 6285f7aa907SGabriel FERNANDEZ return 0; 6295f7aa907SGabriel FERNANDEZ } 6305f7aa907SGabriel FERNANDEZ 6315f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_disable(struct clk_hw *hw) 6325f7aa907SGabriel FERNANDEZ { 6335f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 6345f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 6355f7aa907SGabriel FERNANDEZ 6365f7aa907SGabriel FERNANDEZ pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); 6375f7aa907SGabriel FERNANDEZ 6385f7aa907SGabriel FERNANDEZ if (fs->lock) 6395f7aa907SGabriel FERNANDEZ spin_lock_irqsave(fs->lock, flags); 6405f7aa907SGabriel FERNANDEZ 6418f26df84SGabriel FERNANDEZ CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity); 6425f7aa907SGabriel FERNANDEZ 6435f7aa907SGabriel FERNANDEZ if (fs->lock) 6445f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(fs->lock, flags); 6455f7aa907SGabriel FERNANDEZ } 6465f7aa907SGabriel FERNANDEZ 6475f7aa907SGabriel FERNANDEZ static int quadfs_fsynth_is_enabled(struct clk_hw *hw) 6485f7aa907SGabriel FERNANDEZ { 6495f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 6505f7aa907SGabriel FERNANDEZ u32 nsb = CLKGEN_READ(fs, nsb[fs->chan]); 6515f7aa907SGabriel FERNANDEZ 6525f7aa907SGabriel FERNANDEZ pr_debug("%s: %s enable bit = 0x%x\n", 6535f7aa907SGabriel FERNANDEZ __func__, __clk_get_name(hw->clk), nsb); 6545f7aa907SGabriel FERNANDEZ 6558f26df84SGabriel FERNANDEZ return fs->data->standby_polarity ? !nsb : !!nsb; 6565f7aa907SGabriel FERNANDEZ } 6575f7aa907SGabriel FERNANDEZ 6585f7aa907SGabriel FERNANDEZ #define P15 (uint64_t)(1 << 15) 6595f7aa907SGabriel FERNANDEZ 6604abb1b40SGabriel FERNANDEZ static int clk_fs216c65_get_rate(unsigned long input, const struct stm_fs *fs, 6615f7aa907SGabriel FERNANDEZ unsigned long *rate) 6625f7aa907SGabriel FERNANDEZ { 6635f7aa907SGabriel FERNANDEZ uint64_t res; 6645f7aa907SGabriel FERNANDEZ unsigned long ns; 6655f7aa907SGabriel FERNANDEZ unsigned long nd = 8; /* ndiv stuck at 0 => val = 8 */ 6665f7aa907SGabriel FERNANDEZ unsigned long s; 6675f7aa907SGabriel FERNANDEZ long m; 6685f7aa907SGabriel FERNANDEZ 6695f7aa907SGabriel FERNANDEZ m = fs->mdiv - 32; 6705f7aa907SGabriel FERNANDEZ s = 1 << (fs->sdiv + 1); 6715f7aa907SGabriel FERNANDEZ ns = (fs->nsdiv ? 1 : 3); 6725f7aa907SGabriel FERNANDEZ 6735f7aa907SGabriel FERNANDEZ res = (uint64_t)(s * ns * P15 * (uint64_t)(m + 33)); 6745f7aa907SGabriel FERNANDEZ res = res - (s * ns * fs->pe); 6755f7aa907SGabriel FERNANDEZ *rate = div64_u64(P15 * nd * input * 32, res); 6765f7aa907SGabriel FERNANDEZ 6775f7aa907SGabriel FERNANDEZ return 0; 6785f7aa907SGabriel FERNANDEZ } 6795f7aa907SGabriel FERNANDEZ 6804abb1b40SGabriel FERNANDEZ static int clk_fs432c65_get_rate(unsigned long input, const struct stm_fs *fs, 6815f7aa907SGabriel FERNANDEZ unsigned long *rate) 6825f7aa907SGabriel FERNANDEZ { 6835f7aa907SGabriel FERNANDEZ uint64_t res; 6845f7aa907SGabriel FERNANDEZ unsigned long nd = 16; /* ndiv value; stuck at 0 (30Mhz input) */ 6855f7aa907SGabriel FERNANDEZ long m; 6865f7aa907SGabriel FERNANDEZ unsigned long sd; 6875f7aa907SGabriel FERNANDEZ unsigned long ns; 6885f7aa907SGabriel FERNANDEZ 6895f7aa907SGabriel FERNANDEZ m = fs->mdiv - 32; 6905f7aa907SGabriel FERNANDEZ sd = 1 << (fs->sdiv + 1); 6915f7aa907SGabriel FERNANDEZ ns = (fs->nsdiv ? 1 : 3); 6925f7aa907SGabriel FERNANDEZ 6935f7aa907SGabriel FERNANDEZ res = (uint64_t)(sd * ns * P15 * (uint64_t)(m + 33)); 6945f7aa907SGabriel FERNANDEZ res = res - (sd * ns * fs->pe); 6955f7aa907SGabriel FERNANDEZ *rate = div64_u64(P15 * nd * input * 32, res); 6965f7aa907SGabriel FERNANDEZ 6975f7aa907SGabriel FERNANDEZ return 0; 6985f7aa907SGabriel FERNANDEZ } 6995f7aa907SGabriel FERNANDEZ 7005f7aa907SGabriel FERNANDEZ #define P20 (uint64_t)(1 << 20) 7015f7aa907SGabriel FERNANDEZ 7025f7aa907SGabriel FERNANDEZ static int clk_fs660c32_dig_get_rate(unsigned long input, 7034abb1b40SGabriel FERNANDEZ const struct stm_fs *fs, unsigned long *rate) 7045f7aa907SGabriel FERNANDEZ { 7055f7aa907SGabriel FERNANDEZ unsigned long s = (1 << fs->sdiv); 7065f7aa907SGabriel FERNANDEZ unsigned long ns; 7075f7aa907SGabriel FERNANDEZ uint64_t res; 7085f7aa907SGabriel FERNANDEZ 7095f7aa907SGabriel FERNANDEZ /* 7105f7aa907SGabriel FERNANDEZ * 'nsdiv' is a register value ('BIN') which is translated 7115f7aa907SGabriel FERNANDEZ * to a decimal value according to following rules. 7125f7aa907SGabriel FERNANDEZ * 7135f7aa907SGabriel FERNANDEZ * nsdiv ns.dec 7145f7aa907SGabriel FERNANDEZ * 0 3 7155f7aa907SGabriel FERNANDEZ * 1 1 7165f7aa907SGabriel FERNANDEZ */ 7175f7aa907SGabriel FERNANDEZ ns = (fs->nsdiv == 1) ? 1 : 3; 7185f7aa907SGabriel FERNANDEZ 7195f7aa907SGabriel FERNANDEZ res = (P20 * (32 + fs->mdiv) + 32 * fs->pe) * s * ns; 7205f7aa907SGabriel FERNANDEZ *rate = (unsigned long)div64_u64(input * P20 * 32, res); 7215f7aa907SGabriel FERNANDEZ 7225f7aa907SGabriel FERNANDEZ return 0; 7235f7aa907SGabriel FERNANDEZ } 7245f7aa907SGabriel FERNANDEZ 7255f7aa907SGabriel FERNANDEZ static int quadfs_fsynt_get_hw_value_for_recalc(struct st_clk_quadfs_fsynth *fs, 7265f7aa907SGabriel FERNANDEZ struct stm_fs *params) 7275f7aa907SGabriel FERNANDEZ { 7285f7aa907SGabriel FERNANDEZ /* 7295f7aa907SGabriel FERNANDEZ * Get the initial hardware values for recalc_rate 7305f7aa907SGabriel FERNANDEZ */ 7315f7aa907SGabriel FERNANDEZ params->mdiv = CLKGEN_READ(fs, mdiv[fs->chan]); 7325f7aa907SGabriel FERNANDEZ params->pe = CLKGEN_READ(fs, pe[fs->chan]); 7335f7aa907SGabriel FERNANDEZ params->sdiv = CLKGEN_READ(fs, sdiv[fs->chan]); 7345f7aa907SGabriel FERNANDEZ 7355f7aa907SGabriel FERNANDEZ if (fs->data->nsdiv_present) 7365f7aa907SGabriel FERNANDEZ params->nsdiv = CLKGEN_READ(fs, nsdiv[fs->chan]); 7375f7aa907SGabriel FERNANDEZ else 7385f7aa907SGabriel FERNANDEZ params->nsdiv = 1; 7395f7aa907SGabriel FERNANDEZ 7405f7aa907SGabriel FERNANDEZ /* 7415f7aa907SGabriel FERNANDEZ * If All are NULL then assume no clock rate is programmed. 7425f7aa907SGabriel FERNANDEZ */ 7435f7aa907SGabriel FERNANDEZ if (!params->mdiv && !params->pe && !params->sdiv) 7445f7aa907SGabriel FERNANDEZ return 1; 7455f7aa907SGabriel FERNANDEZ 7465f7aa907SGabriel FERNANDEZ fs->md = params->mdiv; 7475f7aa907SGabriel FERNANDEZ fs->pe = params->pe; 7485f7aa907SGabriel FERNANDEZ fs->sdiv = params->sdiv; 7495f7aa907SGabriel FERNANDEZ fs->nsdiv = params->nsdiv; 7505f7aa907SGabriel FERNANDEZ 7515f7aa907SGabriel FERNANDEZ return 0; 7525f7aa907SGabriel FERNANDEZ } 7535f7aa907SGabriel FERNANDEZ 7545f7aa907SGabriel FERNANDEZ static long quadfs_find_best_rate(struct clk_hw *hw, unsigned long drate, 7555f7aa907SGabriel FERNANDEZ unsigned long prate, struct stm_fs *params) 7565f7aa907SGabriel FERNANDEZ { 7575f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 7585f7aa907SGabriel FERNANDEZ int (*clk_fs_get_rate)(unsigned long , 7594abb1b40SGabriel FERNANDEZ const struct stm_fs *, unsigned long *); 7605f7aa907SGabriel FERNANDEZ struct stm_fs prev_params; 7615f7aa907SGabriel FERNANDEZ unsigned long prev_rate, rate = 0; 7625f7aa907SGabriel FERNANDEZ unsigned long diff_rate, prev_diff_rate = ~0; 7635f7aa907SGabriel FERNANDEZ int index; 7645f7aa907SGabriel FERNANDEZ 7655f7aa907SGabriel FERNANDEZ clk_fs_get_rate = fs->data->get_rate; 7665f7aa907SGabriel FERNANDEZ 7675f7aa907SGabriel FERNANDEZ for (index = 0; index < fs->data->rtbl_cnt; index++) { 7685f7aa907SGabriel FERNANDEZ prev_rate = rate; 7695f7aa907SGabriel FERNANDEZ 7705f7aa907SGabriel FERNANDEZ *params = fs->data->rtbl[index]; 7715f7aa907SGabriel FERNANDEZ prev_params = *params; 7725f7aa907SGabriel FERNANDEZ 7735f7aa907SGabriel FERNANDEZ clk_fs_get_rate(prate, &fs->data->rtbl[index], &rate); 7745f7aa907SGabriel FERNANDEZ 7755f7aa907SGabriel FERNANDEZ diff_rate = abs(drate - rate); 7765f7aa907SGabriel FERNANDEZ 7775f7aa907SGabriel FERNANDEZ if (diff_rate > prev_diff_rate) { 7785f7aa907SGabriel FERNANDEZ rate = prev_rate; 7795f7aa907SGabriel FERNANDEZ *params = prev_params; 7805f7aa907SGabriel FERNANDEZ break; 7815f7aa907SGabriel FERNANDEZ } 7825f7aa907SGabriel FERNANDEZ 7835f7aa907SGabriel FERNANDEZ prev_diff_rate = diff_rate; 7845f7aa907SGabriel FERNANDEZ 7855f7aa907SGabriel FERNANDEZ if (drate == rate) 7865f7aa907SGabriel FERNANDEZ return rate; 7875f7aa907SGabriel FERNANDEZ } 7885f7aa907SGabriel FERNANDEZ 7895f7aa907SGabriel FERNANDEZ 7905f7aa907SGabriel FERNANDEZ if (index == fs->data->rtbl_cnt) 7915f7aa907SGabriel FERNANDEZ *params = prev_params; 7925f7aa907SGabriel FERNANDEZ 7935f7aa907SGabriel FERNANDEZ return rate; 7945f7aa907SGabriel FERNANDEZ } 7955f7aa907SGabriel FERNANDEZ 7965f7aa907SGabriel FERNANDEZ static unsigned long quadfs_recalc_rate(struct clk_hw *hw, 7975f7aa907SGabriel FERNANDEZ unsigned long parent_rate) 7985f7aa907SGabriel FERNANDEZ { 7995f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 8005f7aa907SGabriel FERNANDEZ unsigned long rate = 0; 8015f7aa907SGabriel FERNANDEZ struct stm_fs params; 8025f7aa907SGabriel FERNANDEZ int (*clk_fs_get_rate)(unsigned long , 8034abb1b40SGabriel FERNANDEZ const struct stm_fs *, unsigned long *); 8045f7aa907SGabriel FERNANDEZ 8055f7aa907SGabriel FERNANDEZ clk_fs_get_rate = fs->data->get_rate; 8065f7aa907SGabriel FERNANDEZ 8075f7aa907SGabriel FERNANDEZ if (quadfs_fsynt_get_hw_value_for_recalc(fs, ¶ms)) 8085f7aa907SGabriel FERNANDEZ return 0; 8095f7aa907SGabriel FERNANDEZ 8105f7aa907SGabriel FERNANDEZ if (clk_fs_get_rate(parent_rate, ¶ms, &rate)) { 8115f7aa907SGabriel FERNANDEZ pr_err("%s:%s error calculating rate\n", 8125f7aa907SGabriel FERNANDEZ __clk_get_name(hw->clk), __func__); 8135f7aa907SGabriel FERNANDEZ } 8145f7aa907SGabriel FERNANDEZ 8155f7aa907SGabriel FERNANDEZ pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate); 8165f7aa907SGabriel FERNANDEZ 8175f7aa907SGabriel FERNANDEZ return rate; 8185f7aa907SGabriel FERNANDEZ } 8195f7aa907SGabriel FERNANDEZ 8205f7aa907SGabriel FERNANDEZ static long quadfs_round_rate(struct clk_hw *hw, unsigned long rate, 8215f7aa907SGabriel FERNANDEZ unsigned long *prate) 8225f7aa907SGabriel FERNANDEZ { 8235f7aa907SGabriel FERNANDEZ struct stm_fs params; 8245f7aa907SGabriel FERNANDEZ 8255f7aa907SGabriel FERNANDEZ rate = quadfs_find_best_rate(hw, rate, *prate, ¶ms); 8265f7aa907SGabriel FERNANDEZ 8275f7aa907SGabriel FERNANDEZ pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n", 8285f7aa907SGabriel FERNANDEZ __func__, __clk_get_name(hw->clk), 8295f7aa907SGabriel FERNANDEZ rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv, 8305f7aa907SGabriel FERNANDEZ (unsigned int)params.pe, (unsigned int)params.nsdiv); 8315f7aa907SGabriel FERNANDEZ 8325f7aa907SGabriel FERNANDEZ return rate; 8335f7aa907SGabriel FERNANDEZ } 8345f7aa907SGabriel FERNANDEZ 8355f7aa907SGabriel FERNANDEZ 8365f7aa907SGabriel FERNANDEZ static void quadfs_program_and_enable(struct st_clk_quadfs_fsynth *fs, 8375f7aa907SGabriel FERNANDEZ struct stm_fs *params) 8385f7aa907SGabriel FERNANDEZ { 8395f7aa907SGabriel FERNANDEZ fs->md = params->mdiv; 8405f7aa907SGabriel FERNANDEZ fs->pe = params->pe; 8415f7aa907SGabriel FERNANDEZ fs->sdiv = params->sdiv; 8425f7aa907SGabriel FERNANDEZ fs->nsdiv = params->nsdiv; 8435f7aa907SGabriel FERNANDEZ 8445f7aa907SGabriel FERNANDEZ /* 8455f7aa907SGabriel FERNANDEZ * In some integrations you can only change the fsynth programming when 8465f7aa907SGabriel FERNANDEZ * the parent entity containing it is enabled. 8475f7aa907SGabriel FERNANDEZ */ 8485f7aa907SGabriel FERNANDEZ quadfs_fsynth_program_rate(fs); 8495f7aa907SGabriel FERNANDEZ quadfs_fsynth_program_enable(fs); 8505f7aa907SGabriel FERNANDEZ } 8515f7aa907SGabriel FERNANDEZ 8525f7aa907SGabriel FERNANDEZ static int quadfs_set_rate(struct clk_hw *hw, unsigned long rate, 8535f7aa907SGabriel FERNANDEZ unsigned long parent_rate) 8545f7aa907SGabriel FERNANDEZ { 8555f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 8565f7aa907SGabriel FERNANDEZ struct stm_fs params; 8575f7aa907SGabriel FERNANDEZ long hwrate; 8585f7aa907SGabriel FERNANDEZ int uninitialized_var(i); 8595f7aa907SGabriel FERNANDEZ 8605f7aa907SGabriel FERNANDEZ if (!rate || !parent_rate) 8615f7aa907SGabriel FERNANDEZ return -EINVAL; 8625f7aa907SGabriel FERNANDEZ 8635f7aa907SGabriel FERNANDEZ memset(¶ms, 0, sizeof(struct stm_fs)); 8645f7aa907SGabriel FERNANDEZ 8655f7aa907SGabriel FERNANDEZ hwrate = quadfs_find_best_rate(hw, rate, parent_rate, ¶ms); 8665f7aa907SGabriel FERNANDEZ if (!hwrate) 8675f7aa907SGabriel FERNANDEZ return -EINVAL; 8685f7aa907SGabriel FERNANDEZ 8695f7aa907SGabriel FERNANDEZ quadfs_program_and_enable(fs, ¶ms); 8705f7aa907SGabriel FERNANDEZ 8715f7aa907SGabriel FERNANDEZ return 0; 8725f7aa907SGabriel FERNANDEZ } 8735f7aa907SGabriel FERNANDEZ 8745f7aa907SGabriel FERNANDEZ 8755f7aa907SGabriel FERNANDEZ 8765f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_ops = { 8775f7aa907SGabriel FERNANDEZ .enable = quadfs_fsynth_enable, 8785f7aa907SGabriel FERNANDEZ .disable = quadfs_fsynth_disable, 8795f7aa907SGabriel FERNANDEZ .is_enabled = quadfs_fsynth_is_enabled, 8805f7aa907SGabriel FERNANDEZ .round_rate = quadfs_round_rate, 8815f7aa907SGabriel FERNANDEZ .set_rate = quadfs_set_rate, 8825f7aa907SGabriel FERNANDEZ .recalc_rate = quadfs_recalc_rate, 8835f7aa907SGabriel FERNANDEZ }; 8845f7aa907SGabriel FERNANDEZ 8855f7aa907SGabriel FERNANDEZ static struct clk * __init st_clk_register_quadfs_fsynth( 8865f7aa907SGabriel FERNANDEZ const char *name, const char *parent_name, 8875f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *quadfs, void __iomem *reg, u32 chan, 8885f7aa907SGabriel FERNANDEZ spinlock_t *lock) 8895f7aa907SGabriel FERNANDEZ { 8905f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs; 8915f7aa907SGabriel FERNANDEZ struct clk *clk; 8925f7aa907SGabriel FERNANDEZ struct clk_init_data init; 8935f7aa907SGabriel FERNANDEZ 8945f7aa907SGabriel FERNANDEZ /* 8955f7aa907SGabriel FERNANDEZ * Sanity check required pointers, note that nsdiv3 is optional. 8965f7aa907SGabriel FERNANDEZ */ 8975f7aa907SGabriel FERNANDEZ if (WARN_ON(!name || !parent_name)) 8985f7aa907SGabriel FERNANDEZ return ERR_PTR(-EINVAL); 8995f7aa907SGabriel FERNANDEZ 9005f7aa907SGabriel FERNANDEZ fs = kzalloc(sizeof(*fs), GFP_KERNEL); 9015f7aa907SGabriel FERNANDEZ if (!fs) 9025f7aa907SGabriel FERNANDEZ return ERR_PTR(-ENOMEM); 9035f7aa907SGabriel FERNANDEZ 9045f7aa907SGabriel FERNANDEZ init.name = name; 9055f7aa907SGabriel FERNANDEZ init.ops = &st_quadfs_ops; 9065f7aa907SGabriel FERNANDEZ init.flags = CLK_GET_RATE_NOCACHE | CLK_IS_BASIC; 9075f7aa907SGabriel FERNANDEZ init.parent_names = &parent_name; 9085f7aa907SGabriel FERNANDEZ init.num_parents = 1; 9095f7aa907SGabriel FERNANDEZ 9105f7aa907SGabriel FERNANDEZ fs->data = quadfs; 9115f7aa907SGabriel FERNANDEZ fs->regs_base = reg; 9125f7aa907SGabriel FERNANDEZ fs->chan = chan; 9135f7aa907SGabriel FERNANDEZ fs->lock = lock; 9145f7aa907SGabriel FERNANDEZ fs->hw.init = &init; 9155f7aa907SGabriel FERNANDEZ 9165f7aa907SGabriel FERNANDEZ clk = clk_register(NULL, &fs->hw); 9175f7aa907SGabriel FERNANDEZ 9185f7aa907SGabriel FERNANDEZ if (IS_ERR(clk)) 9195f7aa907SGabriel FERNANDEZ kfree(fs); 9205f7aa907SGabriel FERNANDEZ 9215f7aa907SGabriel FERNANDEZ return clk; 9225f7aa907SGabriel FERNANDEZ } 9235f7aa907SGabriel FERNANDEZ 9245f7aa907SGabriel FERNANDEZ static struct of_device_id quadfs_of_match[] = { 9255f7aa907SGabriel FERNANDEZ { 9265f7aa907SGabriel FERNANDEZ .compatible = "st,stih416-quadfs216", 92779bb8aa1SGabriel FERNANDEZ .data = &st_fs216c65_416 9285f7aa907SGabriel FERNANDEZ }, 9295f7aa907SGabriel FERNANDEZ { 9305f7aa907SGabriel FERNANDEZ .compatible = "st,stih416-quadfs432", 93179bb8aa1SGabriel FERNANDEZ .data = &st_fs432c65_416 9325f7aa907SGabriel FERNANDEZ }, 9335f7aa907SGabriel FERNANDEZ { 9345f7aa907SGabriel FERNANDEZ .compatible = "st,stih416-quadfs660-E", 93579bb8aa1SGabriel FERNANDEZ .data = &st_fs660c32_E_416 9365f7aa907SGabriel FERNANDEZ }, 9375f7aa907SGabriel FERNANDEZ { 9385f7aa907SGabriel FERNANDEZ .compatible = "st,stih416-quadfs660-F", 93979bb8aa1SGabriel FERNANDEZ .data = &st_fs660c32_F_416 9405f7aa907SGabriel FERNANDEZ }, 9415f7aa907SGabriel FERNANDEZ {} 9425f7aa907SGabriel FERNANDEZ }; 9435f7aa907SGabriel FERNANDEZ 9445f7aa907SGabriel FERNANDEZ static void __init st_of_create_quadfs_fsynths( 9455f7aa907SGabriel FERNANDEZ struct device_node *np, const char *pll_name, 9465f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *quadfs, void __iomem *reg, 9475f7aa907SGabriel FERNANDEZ spinlock_t *lock) 9485f7aa907SGabriel FERNANDEZ { 9495f7aa907SGabriel FERNANDEZ struct clk_onecell_data *clk_data; 9505f7aa907SGabriel FERNANDEZ int fschan; 9515f7aa907SGabriel FERNANDEZ 9525f7aa907SGabriel FERNANDEZ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 9535f7aa907SGabriel FERNANDEZ if (!clk_data) 9545f7aa907SGabriel FERNANDEZ return; 9555f7aa907SGabriel FERNANDEZ 9565f7aa907SGabriel FERNANDEZ clk_data->clk_num = QUADFS_MAX_CHAN; 9575f7aa907SGabriel FERNANDEZ clk_data->clks = kzalloc(QUADFS_MAX_CHAN * sizeof(struct clk *), 9585f7aa907SGabriel FERNANDEZ GFP_KERNEL); 9595f7aa907SGabriel FERNANDEZ 9605f7aa907SGabriel FERNANDEZ if (!clk_data->clks) { 9615f7aa907SGabriel FERNANDEZ kfree(clk_data); 9625f7aa907SGabriel FERNANDEZ return; 9635f7aa907SGabriel FERNANDEZ } 9645f7aa907SGabriel FERNANDEZ 9655f7aa907SGabriel FERNANDEZ for (fschan = 0; fschan < QUADFS_MAX_CHAN; fschan++) { 9665f7aa907SGabriel FERNANDEZ struct clk *clk; 9675f7aa907SGabriel FERNANDEZ const char *clk_name; 9685f7aa907SGabriel FERNANDEZ 9695f7aa907SGabriel FERNANDEZ if (of_property_read_string_index(np, "clock-output-names", 9705f7aa907SGabriel FERNANDEZ fschan, &clk_name)) { 9715f7aa907SGabriel FERNANDEZ break; 9725f7aa907SGabriel FERNANDEZ } 9735f7aa907SGabriel FERNANDEZ 9745f7aa907SGabriel FERNANDEZ /* 9755f7aa907SGabriel FERNANDEZ * If we read an empty clock name then the channel is unused 9765f7aa907SGabriel FERNANDEZ */ 9775f7aa907SGabriel FERNANDEZ if (*clk_name == '\0') 9785f7aa907SGabriel FERNANDEZ continue; 9795f7aa907SGabriel FERNANDEZ 9805f7aa907SGabriel FERNANDEZ clk = st_clk_register_quadfs_fsynth(clk_name, pll_name, 9815f7aa907SGabriel FERNANDEZ quadfs, reg, fschan, lock); 9825f7aa907SGabriel FERNANDEZ 9835f7aa907SGabriel FERNANDEZ /* 9845f7aa907SGabriel FERNANDEZ * If there was an error registering this clock output, clean 9855f7aa907SGabriel FERNANDEZ * up and move on to the next one. 9865f7aa907SGabriel FERNANDEZ */ 9875f7aa907SGabriel FERNANDEZ if (!IS_ERR(clk)) { 9885f7aa907SGabriel FERNANDEZ clk_data->clks[fschan] = clk; 9895f7aa907SGabriel FERNANDEZ pr_debug("%s: parent %s rate %u\n", 9905f7aa907SGabriel FERNANDEZ __clk_get_name(clk), 9915f7aa907SGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 9925f7aa907SGabriel FERNANDEZ (unsigned int)clk_get_rate(clk)); 9935f7aa907SGabriel FERNANDEZ } 9945f7aa907SGabriel FERNANDEZ } 9955f7aa907SGabriel FERNANDEZ 9965f7aa907SGabriel FERNANDEZ of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); 9975f7aa907SGabriel FERNANDEZ } 9985f7aa907SGabriel FERNANDEZ 9995f7aa907SGabriel FERNANDEZ static void __init st_of_quadfs_setup(struct device_node *np) 10005f7aa907SGabriel FERNANDEZ { 10015f7aa907SGabriel FERNANDEZ const struct of_device_id *match; 10025f7aa907SGabriel FERNANDEZ struct clk *clk; 10035f7aa907SGabriel FERNANDEZ const char *pll_name, *clk_parent_name; 10045f7aa907SGabriel FERNANDEZ void __iomem *reg; 10055f7aa907SGabriel FERNANDEZ spinlock_t *lock; 10065f7aa907SGabriel FERNANDEZ 10075f7aa907SGabriel FERNANDEZ match = of_match_node(quadfs_of_match, np); 10085f7aa907SGabriel FERNANDEZ if (WARN_ON(!match)) 10095f7aa907SGabriel FERNANDEZ return; 10105f7aa907SGabriel FERNANDEZ 10115f7aa907SGabriel FERNANDEZ reg = of_iomap(np, 0); 10125f7aa907SGabriel FERNANDEZ if (!reg) 10135f7aa907SGabriel FERNANDEZ return; 10145f7aa907SGabriel FERNANDEZ 10155f7aa907SGabriel FERNANDEZ clk_parent_name = of_clk_get_parent_name(np, 0); 10165f7aa907SGabriel FERNANDEZ if (!clk_parent_name) 10175f7aa907SGabriel FERNANDEZ return; 10185f7aa907SGabriel FERNANDEZ 10195f7aa907SGabriel FERNANDEZ pll_name = kasprintf(GFP_KERNEL, "%s.pll", np->name); 10205f7aa907SGabriel FERNANDEZ if (!pll_name) 10215f7aa907SGabriel FERNANDEZ return; 10225f7aa907SGabriel FERNANDEZ 10235f7aa907SGabriel FERNANDEZ lock = kzalloc(sizeof(*lock), GFP_KERNEL); 10245f7aa907SGabriel FERNANDEZ if (!lock) 10255f7aa907SGabriel FERNANDEZ goto err_exit; 10265f7aa907SGabriel FERNANDEZ 10275f7aa907SGabriel FERNANDEZ spin_lock_init(lock); 10285f7aa907SGabriel FERNANDEZ 10295f7aa907SGabriel FERNANDEZ clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, 10305f7aa907SGabriel FERNANDEZ (struct clkgen_quadfs_data *) match->data, reg, lock); 10315f7aa907SGabriel FERNANDEZ if (IS_ERR(clk)) 10325f7aa907SGabriel FERNANDEZ goto err_exit; 10335f7aa907SGabriel FERNANDEZ else 10345f7aa907SGabriel FERNANDEZ pr_debug("%s: parent %s rate %u\n", 10355f7aa907SGabriel FERNANDEZ __clk_get_name(clk), 10365f7aa907SGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 10375f7aa907SGabriel FERNANDEZ (unsigned int)clk_get_rate(clk)); 10385f7aa907SGabriel FERNANDEZ 10395f7aa907SGabriel FERNANDEZ st_of_create_quadfs_fsynths(np, pll_name, 10405f7aa907SGabriel FERNANDEZ (struct clkgen_quadfs_data *)match->data, 10415f7aa907SGabriel FERNANDEZ reg, lock); 10425f7aa907SGabriel FERNANDEZ 10435f7aa907SGabriel FERNANDEZ err_exit: 10445f7aa907SGabriel FERNANDEZ kfree(pll_name); /* No longer need local copy of the PLL name */ 10455f7aa907SGabriel FERNANDEZ } 10465f7aa907SGabriel FERNANDEZ CLK_OF_DECLARE(quadfs, "st,quadfs", st_of_quadfs_setup); 1047