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 */ 54f1a788ffSGabriel FERNANDEZ { .mdiv = 0x13, .pe = 0x777c, .sdiv = 0x4, .nsdiv = 1 }, /* 25.175 MHz */ 55f1a788ffSGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0x4d35, .sdiv = 0x2, .nsdiv = 0 }, /* 25.200 MHz */ 56f1a788ffSGabriel FERNANDEZ { .mdiv = 0x11, .pe = 0x1c72, .sdiv = 0x4, .nsdiv = 1 }, /* 27.000 MHz */ 57f1a788ffSGabriel FERNANDEZ { .mdiv = 0x17, .pe = 0x28f5, .sdiv = 0x2, .nsdiv = 0 }, /* 27.027 MHz */ 58f1a788ffSGabriel FERNANDEZ { .mdiv = 0x16, .pe = 0x3359, .sdiv = 0x2, .nsdiv = 0 }, /* 28.320 MHz */ 59f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1f, .pe = 0x2083, .sdiv = 0x3, .nsdiv = 1 }, /* 30.240 MHz */ 60f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1e, .pe = 0x430d, .sdiv = 0x3, .nsdiv = 1 }, /* 31.500 MHz */ 61f1a788ffSGabriel FERNANDEZ { .mdiv = 0x17, .pe = 0x0, .sdiv = 0x3, .nsdiv = 1 }, /* 40.000 MHz */ 62f1a788ffSGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x1, .nsdiv = 0 }, /* 49.500 MHz */ 63f1a788ffSGabriel FERNANDEZ { .mdiv = 0x13, .pe = 0x6667, .sdiv = 0x3, .nsdiv = 1 }, /* 50.000 MHz */ 64f1a788ffSGabriel FERNANDEZ { .mdiv = 0x10, .pe = 0x1ee6, .sdiv = 0x3, .nsdiv = 1 }, /* 57.284 MHz */ 65f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1d, .pe = 0x3b14, .sdiv = 0x2, .nsdiv = 1 }, /* 65.000 MHz */ 66f1a788ffSGabriel FERNANDEZ { .mdiv = 0x12, .pe = 0x7c65, .sdiv = 0x1, .nsdiv = 0 }, /* 71.000 MHz */ 67f1a788ffSGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0xecd, .sdiv = 0x2, .nsdiv = 1 }, /* 74.176 MHz */ 68f1a788ffSGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x2, .nsdiv = 1 }, /* 74.250 MHz */ 69f1a788ffSGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0x3334, .sdiv = 0x2, .nsdiv = 1 }, /* 75.000 MHz */ 70f1a788ffSGabriel FERNANDEZ { .mdiv = 0x18, .pe = 0x5138, .sdiv = 0x2, .nsdiv = 1 }, /* 78.800 MHz */ 71f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1d, .pe = 0x77d, .sdiv = 0x0, .nsdiv = 0 }, /* 85.500 MHz */ 72f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1c, .pe = 0x13d5, .sdiv = 0x0, .nsdiv = 0 }, /* 88.750 MHz */ 73f1a788ffSGabriel FERNANDEZ { .mdiv = 0x11, .pe = 0x1c72, .sdiv = 0x2, .nsdiv = 1 }, /* 108.000 MHz */ 74f1a788ffSGabriel FERNANDEZ { .mdiv = 0x17, .pe = 0x28f5, .sdiv = 0x0, .nsdiv = 0 }, /* 108.108 MHz */ 75f1a788ffSGabriel FERNANDEZ { .mdiv = 0x10, .pe = 0x6e26, .sdiv = 0x2, .nsdiv = 1 }, /* 118.963 MHz */ 76f1a788ffSGabriel FERNANDEZ { .mdiv = 0x15, .pe = 0x3e63, .sdiv = 0x0, .nsdiv = 0 }, /* 119.000 MHz */ 77f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1c, .pe = 0x471d, .sdiv = 0x1, .nsdiv = 1 }, /* 135.000 MHz */ 78f1a788ffSGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0xecd, .sdiv = 0x1, .nsdiv = 1 }, /* 148.352 MHz */ 79f1a788ffSGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x1, .nsdiv = 1 }, /* 148.500 MHz */ 805f7aa907SGabriel FERNANDEZ { .mdiv = 0x19, .pe = 0x121a, .sdiv = 0x0, .nsdiv = 1 }, /* 297 MHz */ 815f7aa907SGabriel FERNANDEZ }; 825f7aa907SGabriel FERNANDEZ 834abb1b40SGabriel FERNANDEZ static const struct stm_fs fs660c32_rtbl[] = { 84f1a788ffSGabriel FERNANDEZ { .mdiv = 0x14, .pe = 0x376b, .sdiv = 0x4, .nsdiv = 1 }, /* 25.175 MHz */ 85f1a788ffSGabriel FERNANDEZ { .mdiv = 0x14, .pe = 0x30c3, .sdiv = 0x4, .nsdiv = 1 }, /* 25.200 MHz */ 86f1a788ffSGabriel FERNANDEZ { .mdiv = 0x10, .pe = 0x71c7, .sdiv = 0x4, .nsdiv = 1 }, /* 27.000 MHz */ 87f1a788ffSGabriel FERNANDEZ { .mdiv = 0x00, .pe = 0x47af, .sdiv = 0x3, .nsdiv = 0 }, /* 27.027 MHz */ 88f1a788ffSGabriel FERNANDEZ { .mdiv = 0x0e, .pe = 0x4e1a, .sdiv = 0x4, .nsdiv = 1 }, /* 28.320 MHz */ 89f1a788ffSGabriel FERNANDEZ { .mdiv = 0x0b, .pe = 0x534d, .sdiv = 0x4, .nsdiv = 1 }, /* 30.240 MHz */ 90f1a788ffSGabriel FERNANDEZ { .mdiv = 0x17, .pe = 0x6fbf, .sdiv = 0x2, .nsdiv = 0 }, /* 31.500 MHz */ 91f1a788ffSGabriel FERNANDEZ { .mdiv = 0x01, .pe = 0x0, .sdiv = 0x4, .nsdiv = 1 }, /* 40.000 MHz */ 92f1a788ffSGabriel FERNANDEZ { .mdiv = 0x15, .pe = 0x2aab, .sdiv = 0x3, .nsdiv = 1 }, /* 49.500 MHz */ 93f1a788ffSGabriel FERNANDEZ { .mdiv = 0x14, .pe = 0x6666, .sdiv = 0x3, .nsdiv = 1 }, /* 50.000 MHz */ 94f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1d, .pe = 0x395f, .sdiv = 0x1, .nsdiv = 0 }, /* 57.284 MHz */ 95f1a788ffSGabriel FERNANDEZ { .mdiv = 0x08, .pe = 0x4ec5, .sdiv = 0x3, .nsdiv = 1 }, /* 65.000 MHz */ 96f1a788ffSGabriel FERNANDEZ { .mdiv = 0x05, .pe = 0x1770, .sdiv = 0x3, .nsdiv = 1 }, /* 71.000 MHz */ 97f1a788ffSGabriel FERNANDEZ { .mdiv = 0x03, .pe = 0x4ba7, .sdiv = 0x3, .nsdiv = 1 }, /* 74.176 MHz */ 98f1a788ffSGabriel FERNANDEZ { .mdiv = 0x0f, .pe = 0x3426, .sdiv = 0x1, .nsdiv = 0 }, /* 74.250 MHz */ 99f1a788ffSGabriel FERNANDEZ { .mdiv = 0x0e, .pe = 0x7777, .sdiv = 0x1, .nsdiv = 0 }, /* 75.000 MHz */ 100f1a788ffSGabriel FERNANDEZ { .mdiv = 0x01, .pe = 0x4053, .sdiv = 0x3, .nsdiv = 1 }, /* 78.800 MHz */ 101f1a788ffSGabriel FERNANDEZ { .mdiv = 0x09, .pe = 0x15b5, .sdiv = 0x1, .nsdiv = 0 }, /* 85.500 MHz */ 102f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1b, .pe = 0x3f19, .sdiv = 0x2, .nsdiv = 1 }, /* 88.750 MHz */ 103f1a788ffSGabriel FERNANDEZ { .mdiv = 0x10, .pe = 0x71c7, .sdiv = 0x2, .nsdiv = 1 }, /* 108.000 MHz */ 104f1a788ffSGabriel FERNANDEZ { .mdiv = 0x00, .pe = 0x47af, .sdiv = 0x1, .nsdiv = 0 }, /* 108.108 MHz */ 105f1a788ffSGabriel FERNANDEZ { .mdiv = 0x0c, .pe = 0x3118, .sdiv = 0x2, .nsdiv = 1 }, /* 118.963 MHz */ 106f1a788ffSGabriel FERNANDEZ { .mdiv = 0x0c, .pe = 0x2f54, .sdiv = 0x2, .nsdiv = 1 }, /* 119.000 MHz */ 107f1a788ffSGabriel FERNANDEZ { .mdiv = 0x07, .pe = 0xe39, .sdiv = 0x2, .nsdiv = 1 }, /* 135.000 MHz */ 108f1a788ffSGabriel FERNANDEZ { .mdiv = 0x03, .pe = 0x4ba7, .sdiv = 0x2, .nsdiv = 1 }, /* 148.352 MHz */ 109f1a788ffSGabriel FERNANDEZ { .mdiv = 0x0f, .pe = 0x3426, .sdiv = 0x0, .nsdiv = 0 }, /* 148.500 MHz */ 110f1a788ffSGabriel FERNANDEZ { .mdiv = 0x03, .pe = 0x4ba7, .sdiv = 0x1, .nsdiv = 1 }, /* 296.704 MHz */ 111f1a788ffSGabriel FERNANDEZ { .mdiv = 0x03, .pe = 0x471c, .sdiv = 0x1, .nsdiv = 1 }, /* 297.000 MHz */ 112f1a788ffSGabriel FERNANDEZ { .mdiv = 0x00, .pe = 0x295f, .sdiv = 0x1, .nsdiv = 1 }, /* 326.700 MHz */ 113f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1f, .pe = 0x3633, .sdiv = 0x0, .nsdiv = 1 }, /* 333.000 MHz */ 114f1a788ffSGabriel FERNANDEZ { .mdiv = 0x1c, .pe = 0x0, .sdiv = 0x0, .nsdiv = 1 }, /* 352.000 Mhz */ 1155f7aa907SGabriel FERNANDEZ }; 1165f7aa907SGabriel FERNANDEZ 1175f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data { 1185f7aa907SGabriel FERNANDEZ bool reset_present; 1195f7aa907SGabriel FERNANDEZ bool bwfilter_present; 1205f7aa907SGabriel FERNANDEZ bool lockstatus_present; 1218f26df84SGabriel FERNANDEZ bool powerup_polarity; 1228f26df84SGabriel FERNANDEZ bool standby_polarity; 1235f7aa907SGabriel FERNANDEZ bool nsdiv_present; 124fc755c8bSGabriel FERNANDEZ bool nrst_present; 1255f7aa907SGabriel FERNANDEZ struct clkgen_field ndiv; 1265f7aa907SGabriel FERNANDEZ struct clkgen_field ref_bw; 1275f7aa907SGabriel FERNANDEZ struct clkgen_field nreset; 1285f7aa907SGabriel FERNANDEZ struct clkgen_field npda; 1295f7aa907SGabriel FERNANDEZ struct clkgen_field lock_status; 1305f7aa907SGabriel FERNANDEZ 131fc755c8bSGabriel FERNANDEZ struct clkgen_field nrst[QUADFS_MAX_CHAN]; 1325f7aa907SGabriel FERNANDEZ struct clkgen_field nsb[QUADFS_MAX_CHAN]; 1335f7aa907SGabriel FERNANDEZ struct clkgen_field en[QUADFS_MAX_CHAN]; 1345f7aa907SGabriel FERNANDEZ struct clkgen_field mdiv[QUADFS_MAX_CHAN]; 1355f7aa907SGabriel FERNANDEZ struct clkgen_field pe[QUADFS_MAX_CHAN]; 1365f7aa907SGabriel FERNANDEZ struct clkgen_field sdiv[QUADFS_MAX_CHAN]; 1375f7aa907SGabriel FERNANDEZ struct clkgen_field nsdiv[QUADFS_MAX_CHAN]; 1385f7aa907SGabriel FERNANDEZ 1395f7aa907SGabriel FERNANDEZ const struct clk_ops *pll_ops; 1404abb1b40SGabriel FERNANDEZ const struct stm_fs *rtbl; 1415f7aa907SGabriel FERNANDEZ u8 rtbl_cnt; 1424abb1b40SGabriel FERNANDEZ int (*get_rate)(unsigned long , const struct stm_fs *, 1435f7aa907SGabriel FERNANDEZ unsigned long *); 1445f7aa907SGabriel FERNANDEZ }; 1455f7aa907SGabriel FERNANDEZ 1465f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c65_ops; 1475f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c32_ops; 1485f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_fs216c65_ops; 1495f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_fs432c65_ops; 1505f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_fs660c32_ops; 1515f7aa907SGabriel FERNANDEZ 1524abb1b40SGabriel FERNANDEZ static int clk_fs216c65_get_rate(unsigned long, const struct stm_fs *, 1535f7aa907SGabriel FERNANDEZ unsigned long *); 1544abb1b40SGabriel FERNANDEZ static int clk_fs432c65_get_rate(unsigned long, const struct stm_fs *, 1555f7aa907SGabriel FERNANDEZ unsigned long *); 1564abb1b40SGabriel FERNANDEZ static int clk_fs660c32_dig_get_rate(unsigned long, const struct stm_fs *, 1575f7aa907SGabriel FERNANDEZ unsigned long *); 1585f7aa907SGabriel FERNANDEZ /* 1595f7aa907SGabriel FERNANDEZ * Values for all of the standalone instances of this clock 1605f7aa907SGabriel FERNANDEZ * generator found in STiH415 and STiH416 SYSCFG register banks. Note 1615f7aa907SGabriel FERNANDEZ * that the individual channel standby control bits (nsb) are in the 1625f7aa907SGabriel FERNANDEZ * first register along with the PLL control bits. 1635f7aa907SGabriel FERNANDEZ */ 1644abb1b40SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs216c65_416 = { 1655f7aa907SGabriel FERNANDEZ /* 416 specific */ 1665f7aa907SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x0, 0x1, 14), 1675f7aa907SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), 1685f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 11), 1695f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 12), 1705f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 13) }, 1715f7aa907SGabriel FERNANDEZ .nsdiv_present = true, 1725f7aa907SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), 1735f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 19), 1745f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 20), 1755f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 21) }, 1765f7aa907SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), 1775f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x14, 0x1f, 0), 1785f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x24, 0x1f, 0), 1795f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x34, 0x1f, 0) }, 1805f7aa907SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x10, 0x1, 0), 1815f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x20, 0x1, 0), 1825f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x30, 0x1, 0), 1835f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x40, 0x1, 0) }, 1845f7aa907SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x0, 0x1, 15), 1855f7aa907SGabriel FERNANDEZ .bwfilter_present = true, 1865f7aa907SGabriel FERNANDEZ .ref_bw = CLKGEN_FIELD(0x0, 0x3, 16), 1875f7aa907SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x8, 0xffff, 0), 1885f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x18, 0xffff, 0), 1895f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x28, 0xffff, 0), 1905f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x38, 0xffff, 0) }, 1915f7aa907SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0xC, 0x7, 0), 1925f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x1C, 0x7, 0), 1935f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x2C, 0x7, 0), 1945f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x3C, 0x7, 0) }, 1955f7aa907SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c65_ops, 1965f7aa907SGabriel FERNANDEZ .rtbl = fs216c65_rtbl, 1975f7aa907SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs216c65_rtbl), 1985f7aa907SGabriel FERNANDEZ .get_rate = clk_fs216c65_get_rate, 1995f7aa907SGabriel FERNANDEZ }; 2005f7aa907SGabriel FERNANDEZ 2014abb1b40SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs432c65_416 = { 2025f7aa907SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x0, 0x1, 14), 2035f7aa907SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), 2045f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 11), 2055f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 12), 2065f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 13) }, 2075f7aa907SGabriel FERNANDEZ .nsdiv_present = true, 2085f7aa907SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), 2095f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 19), 2105f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 20), 2115f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 21) }, 2125f7aa907SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), 2135f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x14, 0x1f, 0), 2145f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x24, 0x1f, 0), 2155f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x34, 0x1f, 0) }, 2165f7aa907SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x10, 0x1, 0), 2175f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x20, 0x1, 0), 2185f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x30, 0x1, 0), 2195f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x40, 0x1, 0) }, 2205f7aa907SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x0, 0x1, 15), 2215f7aa907SGabriel FERNANDEZ .bwfilter_present = true, 2225f7aa907SGabriel FERNANDEZ .ref_bw = CLKGEN_FIELD(0x0, 0x3, 16), 2235f7aa907SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x8, 0xffff, 0), 2245f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x18, 0xffff, 0), 2255f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x28, 0xffff, 0), 2265f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x38, 0xffff, 0) }, 2275f7aa907SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0xC, 0x7, 0), 2285f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x1C, 0x7, 0), 2295f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x2C, 0x7, 0), 2305f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x3C, 0x7, 0) }, 2315f7aa907SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c65_ops, 2325f7aa907SGabriel FERNANDEZ .rtbl = fs432c65_rtbl, 2335f7aa907SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs432c65_rtbl), 2345f7aa907SGabriel FERNANDEZ .get_rate = clk_fs432c65_get_rate, 2355f7aa907SGabriel FERNANDEZ }; 2365f7aa907SGabriel FERNANDEZ 2374abb1b40SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs660c32_E_416 = { 2385f7aa907SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x0, 0x1, 14), 2395f7aa907SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), 2405f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 11), 2415f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 12), 2425f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 13) }, 2435f7aa907SGabriel FERNANDEZ .nsdiv_present = true, 2445f7aa907SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), 2455f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 19), 2465f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 20), 2475f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 21) }, 2485f7aa907SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), 2495f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x14, 0x1f, 0), 2505f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x24, 0x1f, 0), 2515f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x34, 0x1f, 0) }, 2525f7aa907SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x10, 0x1, 0), 2535f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x20, 0x1, 0), 2545f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x30, 0x1, 0), 2555f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x40, 0x1, 0) }, 2565f7aa907SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x0, 0x7, 15), 2575f7aa907SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x8, 0x7fff, 0), 2585f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x18, 0x7fff, 0), 2595f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x28, 0x7fff, 0), 2605f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x38, 0x7fff, 0) }, 2615f7aa907SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0xC, 0xf, 0), 2625f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x1C, 0xf, 0), 2635f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x2C, 0xf, 0), 2645f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x3C, 0xf, 0) }, 2655f7aa907SGabriel FERNANDEZ .lockstatus_present = true, 2665f7aa907SGabriel FERNANDEZ .lock_status = CLKGEN_FIELD(0xAC, 0x1, 0), 2675f7aa907SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c32_ops, 2685f7aa907SGabriel FERNANDEZ .rtbl = fs660c32_rtbl, 2695f7aa907SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), 2705f7aa907SGabriel FERNANDEZ .get_rate = clk_fs660c32_dig_get_rate, 2715f7aa907SGabriel FERNANDEZ }; 2725f7aa907SGabriel FERNANDEZ 2734abb1b40SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs660c32_F_416 = { 2745f7aa907SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x0, 0x1, 14), 2755f7aa907SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x0, 0x1, 10), 2765f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 11), 2775f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 12), 2785f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 13) }, 2795f7aa907SGabriel FERNANDEZ .nsdiv_present = true, 2805f7aa907SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x0, 0x1, 18), 2815f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 19), 2825f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 20), 2835f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x0, 0x1, 21) }, 2845f7aa907SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x4, 0x1f, 0), 2855f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x14, 0x1f, 0), 2865f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x24, 0x1f, 0), 2875f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x34, 0x1f, 0) }, 2885f7aa907SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x10, 0x1, 0), 2895f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x20, 0x1, 0), 2905f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x30, 0x1, 0), 2915f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x40, 0x1, 0) }, 2925f7aa907SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x0, 0x7, 15), 2935f7aa907SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x8, 0x7fff, 0), 2945f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x18, 0x7fff, 0), 2955f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x28, 0x7fff, 0), 2965f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x38, 0x7fff, 0) }, 2975f7aa907SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0xC, 0xf, 0), 2985f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x1C, 0xf, 0), 2995f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x2C, 0xf, 0), 3005f7aa907SGabriel FERNANDEZ CLKGEN_FIELD(0x3C, 0xf, 0) }, 3015f7aa907SGabriel FERNANDEZ .lockstatus_present = true, 3025f7aa907SGabriel FERNANDEZ .lock_status = CLKGEN_FIELD(0xEC, 0x1, 0), 3035f7aa907SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c32_ops, 3045f7aa907SGabriel FERNANDEZ .rtbl = fs660c32_rtbl, 3055f7aa907SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), 3065f7aa907SGabriel FERNANDEZ .get_rate = clk_fs660c32_dig_get_rate, 3075f7aa907SGabriel FERNANDEZ }; 3085f7aa907SGabriel FERNANDEZ 30951306d56SGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs660c32_C_407 = { 31051306d56SGabriel FERNANDEZ .nrst_present = true, 31151306d56SGabriel FERNANDEZ .nrst = { CLKGEN_FIELD(0x2f0, 0x1, 0), 31251306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2f0, 0x1, 1), 31351306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2f0, 0x1, 2), 31451306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2f0, 0x1, 3) }, 31551306d56SGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x2f0, 0x1, 12), 31651306d56SGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x2f0, 0x1, 8), 31751306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2f0, 0x1, 9), 31851306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2f0, 0x1, 10), 31951306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2f0, 0x1, 11) }, 32051306d56SGabriel FERNANDEZ .nsdiv_present = true, 32151306d56SGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x304, 0x1, 24), 32251306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x308, 0x1, 24), 32351306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x30c, 0x1, 24), 32451306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x310, 0x1, 24) }, 32551306d56SGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x304, 0x1f, 15), 32651306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x308, 0x1f, 15), 32751306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x30c, 0x1f, 15), 32851306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x310, 0x1f, 15) }, 32951306d56SGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x2fc, 0x1, 0), 33051306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2fc, 0x1, 1), 33151306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2fc, 0x1, 2), 33251306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x2fc, 0x1, 3) }, 33351306d56SGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x2f4, 0x7, 16), 33451306d56SGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x304, 0x7fff, 0), 33551306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x308, 0x7fff, 0), 33651306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x30c, 0x7fff, 0), 33751306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x310, 0x7fff, 0) }, 33851306d56SGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0x304, 0xf, 20), 33951306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x308, 0xf, 20), 34051306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x30c, 0xf, 20), 34151306d56SGabriel FERNANDEZ CLKGEN_FIELD(0x310, 0xf, 20) }, 34251306d56SGabriel FERNANDEZ .lockstatus_present = true, 34351306d56SGabriel FERNANDEZ .lock_status = CLKGEN_FIELD(0x2A0, 0x1, 24), 34451306d56SGabriel FERNANDEZ .powerup_polarity = 1, 34551306d56SGabriel FERNANDEZ .standby_polarity = 1, 34651306d56SGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c32_ops, 34751306d56SGabriel FERNANDEZ .rtbl = fs660c32_rtbl, 34851306d56SGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), 34951306d56SGabriel FERNANDEZ .get_rate = clk_fs660c32_dig_get_rate, 35051306d56SGabriel FERNANDEZ }; 35151306d56SGabriel FERNANDEZ 35258de9b8eSGabriel FERNANDEZ static const struct clkgen_quadfs_data st_fs660c32_D_407 = { 35358de9b8eSGabriel FERNANDEZ .nrst_present = true, 35458de9b8eSGabriel FERNANDEZ .nrst = { CLKGEN_FIELD(0x2a0, 0x1, 0), 35558de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2a0, 0x1, 1), 35658de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2a0, 0x1, 2), 35758de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2a0, 0x1, 3) }, 35858de9b8eSGabriel FERNANDEZ .ndiv = CLKGEN_FIELD(0x2a4, 0x7, 16), 35958de9b8eSGabriel FERNANDEZ .pe = { CLKGEN_FIELD(0x2b4, 0x7fff, 0), 36058de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2b8, 0x7fff, 0), 36158de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2bc, 0x7fff, 0), 36258de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2c0, 0x7fff, 0) }, 36358de9b8eSGabriel FERNANDEZ .sdiv = { CLKGEN_FIELD(0x2b4, 0xf, 20), 36458de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2b8, 0xf, 20), 36558de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2bc, 0xf, 20), 36658de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2c0, 0xf, 20) }, 36758de9b8eSGabriel FERNANDEZ .npda = CLKGEN_FIELD(0x2a0, 0x1, 12), 36858de9b8eSGabriel FERNANDEZ .nsb = { CLKGEN_FIELD(0x2a0, 0x1, 8), 36958de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2a0, 0x1, 9), 37058de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2a0, 0x1, 10), 37158de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2a0, 0x1, 11) }, 37258de9b8eSGabriel FERNANDEZ .nsdiv_present = true, 37358de9b8eSGabriel FERNANDEZ .nsdiv = { CLKGEN_FIELD(0x2b4, 0x1, 24), 37458de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2b8, 0x1, 24), 37558de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2bc, 0x1, 24), 37658de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2c0, 0x1, 24) }, 37758de9b8eSGabriel FERNANDEZ .mdiv = { CLKGEN_FIELD(0x2b4, 0x1f, 15), 37858de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2b8, 0x1f, 15), 37958de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2bc, 0x1f, 15), 38058de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2c0, 0x1f, 15) }, 38158de9b8eSGabriel FERNANDEZ .en = { CLKGEN_FIELD(0x2ac, 0x1, 0), 38258de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2ac, 0x1, 1), 38358de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2ac, 0x1, 2), 38458de9b8eSGabriel FERNANDEZ CLKGEN_FIELD(0x2ac, 0x1, 3) }, 38558de9b8eSGabriel FERNANDEZ .lockstatus_present = true, 38658de9b8eSGabriel FERNANDEZ .lock_status = CLKGEN_FIELD(0x2A0, 0x1, 24), 38758de9b8eSGabriel FERNANDEZ .powerup_polarity = 1, 38858de9b8eSGabriel FERNANDEZ .standby_polarity = 1, 38958de9b8eSGabriel FERNANDEZ .pll_ops = &st_quadfs_pll_c32_ops, 39058de9b8eSGabriel FERNANDEZ .rtbl = fs660c32_rtbl, 39158de9b8eSGabriel FERNANDEZ .rtbl_cnt = ARRAY_SIZE(fs660c32_rtbl), 39258de9b8eSGabriel FERNANDEZ .get_rate = clk_fs660c32_dig_get_rate,}; 39358de9b8eSGabriel FERNANDEZ 3945f7aa907SGabriel FERNANDEZ /** 3955f7aa907SGabriel FERNANDEZ * DOC: A Frequency Synthesizer that multiples its input clock by a fixed factor 3965f7aa907SGabriel FERNANDEZ * 3975f7aa907SGabriel FERNANDEZ * Traits of this clock: 3985f7aa907SGabriel FERNANDEZ * prepare - clk_(un)prepare only ensures parent is (un)prepared 3995f7aa907SGabriel FERNANDEZ * enable - clk_enable and clk_disable are functional & control the Fsyn 4005f7aa907SGabriel FERNANDEZ * rate - inherits rate from parent. set_rate/round_rate/recalc_rate 4015f7aa907SGabriel FERNANDEZ * parent - fixed parent. No clk_set_parent support 4025f7aa907SGabriel FERNANDEZ */ 4035f7aa907SGabriel FERNANDEZ 4045f7aa907SGabriel FERNANDEZ /** 4055f7aa907SGabriel FERNANDEZ * struct st_clk_quadfs_pll - A pll which outputs a fixed multiplier of 4065f7aa907SGabriel FERNANDEZ * its parent clock, found inside a type of 4075f7aa907SGabriel FERNANDEZ * ST quad channel frequency synthesizer block 4085f7aa907SGabriel FERNANDEZ * 4095f7aa907SGabriel FERNANDEZ * @hw: handle between common and hardware-specific interfaces. 4105f7aa907SGabriel FERNANDEZ * @ndiv: regmap field for the ndiv control. 4115f7aa907SGabriel FERNANDEZ * @regs_base: base address of the configuration registers. 4125f7aa907SGabriel FERNANDEZ * @lock: spinlock. 4135f7aa907SGabriel FERNANDEZ * 4145f7aa907SGabriel FERNANDEZ */ 4155f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll { 4165f7aa907SGabriel FERNANDEZ struct clk_hw hw; 4175f7aa907SGabriel FERNANDEZ void __iomem *regs_base; 4185f7aa907SGabriel FERNANDEZ spinlock_t *lock; 4195f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *data; 4205f7aa907SGabriel FERNANDEZ u32 ndiv; 4215f7aa907SGabriel FERNANDEZ }; 4225f7aa907SGabriel FERNANDEZ 4235f7aa907SGabriel FERNANDEZ #define to_quadfs_pll(_hw) container_of(_hw, struct st_clk_quadfs_pll, hw) 4245f7aa907SGabriel FERNANDEZ 4255f7aa907SGabriel FERNANDEZ static int quadfs_pll_enable(struct clk_hw *hw) 4265f7aa907SGabriel FERNANDEZ { 4275f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 4285f7aa907SGabriel FERNANDEZ unsigned long flags = 0, timeout = jiffies + msecs_to_jiffies(10); 4295f7aa907SGabriel FERNANDEZ 4305f7aa907SGabriel FERNANDEZ if (pll->lock) 4315f7aa907SGabriel FERNANDEZ spin_lock_irqsave(pll->lock, flags); 4325f7aa907SGabriel FERNANDEZ 4335f7aa907SGabriel FERNANDEZ /* 4345f7aa907SGabriel FERNANDEZ * Bring block out of reset if we have reset control. 4355f7aa907SGabriel FERNANDEZ */ 4365f7aa907SGabriel FERNANDEZ if (pll->data->reset_present) 4375f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, nreset, 1); 4385f7aa907SGabriel FERNANDEZ 4395f7aa907SGabriel FERNANDEZ /* 4405f7aa907SGabriel FERNANDEZ * Use a fixed input clock noise bandwidth filter for the moment 4415f7aa907SGabriel FERNANDEZ */ 4425f7aa907SGabriel FERNANDEZ if (pll->data->bwfilter_present) 4435f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, ref_bw, PLL_BW_GOODREF); 4445f7aa907SGabriel FERNANDEZ 4455f7aa907SGabriel FERNANDEZ 4465f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, ndiv, pll->ndiv); 4475f7aa907SGabriel FERNANDEZ 4485f7aa907SGabriel FERNANDEZ /* 4495f7aa907SGabriel FERNANDEZ * Power up the PLL 4505f7aa907SGabriel FERNANDEZ */ 4518f26df84SGabriel FERNANDEZ CLKGEN_WRITE(pll, npda, !pll->data->powerup_polarity); 4525f7aa907SGabriel FERNANDEZ 4535f7aa907SGabriel FERNANDEZ if (pll->lock) 4545f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(pll->lock, flags); 4555f7aa907SGabriel FERNANDEZ 4565f7aa907SGabriel FERNANDEZ if (pll->data->lockstatus_present) 4575f7aa907SGabriel FERNANDEZ while (!CLKGEN_READ(pll, lock_status)) { 4585f7aa907SGabriel FERNANDEZ if (time_after(jiffies, timeout)) 4595f7aa907SGabriel FERNANDEZ return -ETIMEDOUT; 4605f7aa907SGabriel FERNANDEZ cpu_relax(); 4615f7aa907SGabriel FERNANDEZ } 4625f7aa907SGabriel FERNANDEZ 4635f7aa907SGabriel FERNANDEZ return 0; 4645f7aa907SGabriel FERNANDEZ } 4655f7aa907SGabriel FERNANDEZ 4665f7aa907SGabriel FERNANDEZ static void quadfs_pll_disable(struct clk_hw *hw) 4675f7aa907SGabriel FERNANDEZ { 4685f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 4695f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 4705f7aa907SGabriel FERNANDEZ 4715f7aa907SGabriel FERNANDEZ if (pll->lock) 4725f7aa907SGabriel FERNANDEZ spin_lock_irqsave(pll->lock, flags); 4735f7aa907SGabriel FERNANDEZ 4745f7aa907SGabriel FERNANDEZ /* 4755f7aa907SGabriel FERNANDEZ * Powerdown the PLL and then put block into soft reset if we have 4765f7aa907SGabriel FERNANDEZ * reset control. 4775f7aa907SGabriel FERNANDEZ */ 4788f26df84SGabriel FERNANDEZ CLKGEN_WRITE(pll, npda, pll->data->powerup_polarity); 4795f7aa907SGabriel FERNANDEZ 4805f7aa907SGabriel FERNANDEZ if (pll->data->reset_present) 4815f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, nreset, 0); 4825f7aa907SGabriel FERNANDEZ 4835f7aa907SGabriel FERNANDEZ if (pll->lock) 4845f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(pll->lock, flags); 4855f7aa907SGabriel FERNANDEZ } 4865f7aa907SGabriel FERNANDEZ 4875f7aa907SGabriel FERNANDEZ static int quadfs_pll_is_enabled(struct clk_hw *hw) 4885f7aa907SGabriel FERNANDEZ { 4895f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 4905f7aa907SGabriel FERNANDEZ u32 npda = CLKGEN_READ(pll, npda); 4915f7aa907SGabriel FERNANDEZ 4925f7aa907SGabriel FERNANDEZ return !!npda; 4935f7aa907SGabriel FERNANDEZ } 4945f7aa907SGabriel FERNANDEZ 4955f7aa907SGabriel FERNANDEZ int clk_fs660c32_vco_get_rate(unsigned long input, struct stm_fs *fs, 4965f7aa907SGabriel FERNANDEZ unsigned long *rate) 4975f7aa907SGabriel FERNANDEZ { 4985f7aa907SGabriel FERNANDEZ unsigned long nd = fs->ndiv + 16; /* ndiv value */ 4995f7aa907SGabriel FERNANDEZ 5005f7aa907SGabriel FERNANDEZ *rate = input * nd; 5015f7aa907SGabriel FERNANDEZ 5025f7aa907SGabriel FERNANDEZ return 0; 5035f7aa907SGabriel FERNANDEZ } 5045f7aa907SGabriel FERNANDEZ 5055f7aa907SGabriel FERNANDEZ static unsigned long quadfs_pll_fs660c32_recalc_rate(struct clk_hw *hw, 5065f7aa907SGabriel FERNANDEZ unsigned long parent_rate) 5075f7aa907SGabriel FERNANDEZ { 5085f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 5095f7aa907SGabriel FERNANDEZ unsigned long rate = 0; 5105f7aa907SGabriel FERNANDEZ struct stm_fs params; 5115f7aa907SGabriel FERNANDEZ 5125f7aa907SGabriel FERNANDEZ params.ndiv = CLKGEN_READ(pll, ndiv); 5135f7aa907SGabriel FERNANDEZ if (clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &rate)) 5145f7aa907SGabriel FERNANDEZ pr_err("%s:%s error calculating rate\n", 5155f7aa907SGabriel FERNANDEZ __clk_get_name(hw->clk), __func__); 5165f7aa907SGabriel FERNANDEZ 5175f7aa907SGabriel FERNANDEZ pll->ndiv = params.ndiv; 5185f7aa907SGabriel FERNANDEZ 5195f7aa907SGabriel FERNANDEZ return rate; 5205f7aa907SGabriel FERNANDEZ } 5215f7aa907SGabriel FERNANDEZ 5225f7aa907SGabriel FERNANDEZ int clk_fs660c32_vco_get_params(unsigned long input, 5235f7aa907SGabriel FERNANDEZ unsigned long output, struct stm_fs *fs) 5245f7aa907SGabriel FERNANDEZ { 5255f7aa907SGabriel FERNANDEZ /* Formula 5265f7aa907SGabriel FERNANDEZ VCO frequency = (fin x ndiv) / pdiv 5275f7aa907SGabriel FERNANDEZ ndiv = VCOfreq * pdiv / fin 5285f7aa907SGabriel FERNANDEZ */ 5295f7aa907SGabriel FERNANDEZ unsigned long pdiv = 1, n; 5305f7aa907SGabriel FERNANDEZ 5315f7aa907SGabriel FERNANDEZ /* Output clock range: 384Mhz to 660Mhz */ 5325f7aa907SGabriel FERNANDEZ if (output < 384000000 || output > 660000000) 5335f7aa907SGabriel FERNANDEZ return -EINVAL; 5345f7aa907SGabriel FERNANDEZ 5355f7aa907SGabriel FERNANDEZ if (input > 40000000) 5365f7aa907SGabriel FERNANDEZ /* This means that PDIV would be 2 instead of 1. 5375f7aa907SGabriel FERNANDEZ Not supported today. */ 5385f7aa907SGabriel FERNANDEZ return -EINVAL; 5395f7aa907SGabriel FERNANDEZ 5405f7aa907SGabriel FERNANDEZ input /= 1000; 5415f7aa907SGabriel FERNANDEZ output /= 1000; 5425f7aa907SGabriel FERNANDEZ 5435f7aa907SGabriel FERNANDEZ n = output * pdiv / input; 5445f7aa907SGabriel FERNANDEZ if (n < 16) 5455f7aa907SGabriel FERNANDEZ n = 16; 5465f7aa907SGabriel FERNANDEZ fs->ndiv = n - 16; /* Converting formula value to reg value */ 5475f7aa907SGabriel FERNANDEZ 5485f7aa907SGabriel FERNANDEZ return 0; 5495f7aa907SGabriel FERNANDEZ } 5505f7aa907SGabriel FERNANDEZ 5515f7aa907SGabriel FERNANDEZ static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, unsigned long rate 5525f7aa907SGabriel FERNANDEZ , unsigned long *prate) 5535f7aa907SGabriel FERNANDEZ { 5545f7aa907SGabriel FERNANDEZ struct stm_fs params; 5555f7aa907SGabriel FERNANDEZ 5565f7aa907SGabriel FERNANDEZ if (!clk_fs660c32_vco_get_params(*prate, rate, ¶ms)) 5575f7aa907SGabriel FERNANDEZ clk_fs660c32_vco_get_rate(*prate, ¶ms, &rate); 5585f7aa907SGabriel FERNANDEZ 5595f7aa907SGabriel FERNANDEZ pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n", 5605f7aa907SGabriel FERNANDEZ __func__, __clk_get_name(hw->clk), 5615f7aa907SGabriel FERNANDEZ rate, (unsigned int)params.sdiv, 5625f7aa907SGabriel FERNANDEZ (unsigned int)params.mdiv, 5635f7aa907SGabriel FERNANDEZ (unsigned int)params.pe, (unsigned int)params.nsdiv); 5645f7aa907SGabriel FERNANDEZ 5655f7aa907SGabriel FERNANDEZ return rate; 5665f7aa907SGabriel FERNANDEZ } 5675f7aa907SGabriel FERNANDEZ 5685f7aa907SGabriel FERNANDEZ static int quadfs_pll_fs660c32_set_rate(struct clk_hw *hw, unsigned long rate, 5695f7aa907SGabriel FERNANDEZ unsigned long parent_rate) 5705f7aa907SGabriel FERNANDEZ { 5715f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll = to_quadfs_pll(hw); 5725f7aa907SGabriel FERNANDEZ struct stm_fs params; 5735f7aa907SGabriel FERNANDEZ long hwrate = 0; 5745f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 5755f7aa907SGabriel FERNANDEZ 5765f7aa907SGabriel FERNANDEZ if (!rate || !parent_rate) 5775f7aa907SGabriel FERNANDEZ return -EINVAL; 5785f7aa907SGabriel FERNANDEZ 5795f7aa907SGabriel FERNANDEZ if (!clk_fs660c32_vco_get_params(parent_rate, rate, ¶ms)) 5805f7aa907SGabriel FERNANDEZ clk_fs660c32_vco_get_rate(parent_rate, ¶ms, &hwrate); 5815f7aa907SGabriel FERNANDEZ 5825f7aa907SGabriel FERNANDEZ pr_debug("%s: %s new rate %ld [ndiv=0x%x]\n", 5835f7aa907SGabriel FERNANDEZ __func__, __clk_get_name(hw->clk), 5845f7aa907SGabriel FERNANDEZ hwrate, (unsigned int)params.ndiv); 5855f7aa907SGabriel FERNANDEZ 5865f7aa907SGabriel FERNANDEZ if (!hwrate) 5875f7aa907SGabriel FERNANDEZ return -EINVAL; 5885f7aa907SGabriel FERNANDEZ 5895f7aa907SGabriel FERNANDEZ pll->ndiv = params.ndiv; 5905f7aa907SGabriel FERNANDEZ 5915f7aa907SGabriel FERNANDEZ if (pll->lock) 5925f7aa907SGabriel FERNANDEZ spin_lock_irqsave(pll->lock, flags); 5935f7aa907SGabriel FERNANDEZ 5945f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(pll, ndiv, pll->ndiv); 5955f7aa907SGabriel FERNANDEZ 5965f7aa907SGabriel FERNANDEZ if (pll->lock) 5975f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(pll->lock, flags); 5985f7aa907SGabriel FERNANDEZ 5995f7aa907SGabriel FERNANDEZ return 0; 6005f7aa907SGabriel FERNANDEZ } 6015f7aa907SGabriel FERNANDEZ 6025f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c65_ops = { 6035f7aa907SGabriel FERNANDEZ .enable = quadfs_pll_enable, 6045f7aa907SGabriel FERNANDEZ .disable = quadfs_pll_disable, 6055f7aa907SGabriel FERNANDEZ .is_enabled = quadfs_pll_is_enabled, 6065f7aa907SGabriel FERNANDEZ }; 6075f7aa907SGabriel FERNANDEZ 6085f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_pll_c32_ops = { 6095f7aa907SGabriel FERNANDEZ .enable = quadfs_pll_enable, 6105f7aa907SGabriel FERNANDEZ .disable = quadfs_pll_disable, 6115f7aa907SGabriel FERNANDEZ .is_enabled = quadfs_pll_is_enabled, 6125f7aa907SGabriel FERNANDEZ .recalc_rate = quadfs_pll_fs660c32_recalc_rate, 6135f7aa907SGabriel FERNANDEZ .round_rate = quadfs_pll_fs660c32_round_rate, 6145f7aa907SGabriel FERNANDEZ .set_rate = quadfs_pll_fs660c32_set_rate, 6155f7aa907SGabriel FERNANDEZ }; 6165f7aa907SGabriel FERNANDEZ 6175f7aa907SGabriel FERNANDEZ static struct clk * __init st_clk_register_quadfs_pll( 6185f7aa907SGabriel FERNANDEZ const char *name, const char *parent_name, 6195f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *quadfs, void __iomem *reg, 6205f7aa907SGabriel FERNANDEZ spinlock_t *lock) 6215f7aa907SGabriel FERNANDEZ { 6225f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_pll *pll; 6235f7aa907SGabriel FERNANDEZ struct clk *clk; 6245f7aa907SGabriel FERNANDEZ struct clk_init_data init; 6255f7aa907SGabriel FERNANDEZ 6265f7aa907SGabriel FERNANDEZ /* 6275f7aa907SGabriel FERNANDEZ * Sanity check required pointers. 6285f7aa907SGabriel FERNANDEZ */ 6295f7aa907SGabriel FERNANDEZ if (WARN_ON(!name || !parent_name)) 6305f7aa907SGabriel FERNANDEZ return ERR_PTR(-EINVAL); 6315f7aa907SGabriel FERNANDEZ 6325f7aa907SGabriel FERNANDEZ pll = kzalloc(sizeof(*pll), GFP_KERNEL); 6335f7aa907SGabriel FERNANDEZ if (!pll) 6345f7aa907SGabriel FERNANDEZ return ERR_PTR(-ENOMEM); 6355f7aa907SGabriel FERNANDEZ 6365f7aa907SGabriel FERNANDEZ init.name = name; 6375f7aa907SGabriel FERNANDEZ init.ops = quadfs->pll_ops; 6385f7aa907SGabriel FERNANDEZ init.flags = CLK_IS_BASIC; 6395f7aa907SGabriel FERNANDEZ init.parent_names = &parent_name; 6405f7aa907SGabriel FERNANDEZ init.num_parents = 1; 6415f7aa907SGabriel FERNANDEZ 6425f7aa907SGabriel FERNANDEZ pll->data = quadfs; 6435f7aa907SGabriel FERNANDEZ pll->regs_base = reg; 6445f7aa907SGabriel FERNANDEZ pll->lock = lock; 6455f7aa907SGabriel FERNANDEZ pll->hw.init = &init; 6465f7aa907SGabriel FERNANDEZ 6475f7aa907SGabriel FERNANDEZ clk = clk_register(NULL, &pll->hw); 6485f7aa907SGabriel FERNANDEZ 6495f7aa907SGabriel FERNANDEZ if (IS_ERR(clk)) 6505f7aa907SGabriel FERNANDEZ kfree(pll); 6515f7aa907SGabriel FERNANDEZ 6525f7aa907SGabriel FERNANDEZ return clk; 6535f7aa907SGabriel FERNANDEZ } 6545f7aa907SGabriel FERNANDEZ 6555f7aa907SGabriel FERNANDEZ /** 6565f7aa907SGabriel FERNANDEZ * DOC: A digital frequency synthesizer 6575f7aa907SGabriel FERNANDEZ * 6585f7aa907SGabriel FERNANDEZ * Traits of this clock: 6595f7aa907SGabriel FERNANDEZ * prepare - clk_(un)prepare only ensures parent is (un)prepared 6605f7aa907SGabriel FERNANDEZ * enable - clk_enable and clk_disable are functional 6615f7aa907SGabriel FERNANDEZ * rate - set rate is functional 6625f7aa907SGabriel FERNANDEZ * parent - fixed parent. No clk_set_parent support 6635f7aa907SGabriel FERNANDEZ */ 6645f7aa907SGabriel FERNANDEZ 6655f7aa907SGabriel FERNANDEZ /** 6665f7aa907SGabriel FERNANDEZ * struct st_clk_quadfs_fsynth - One clock output from a four channel digital 6675f7aa907SGabriel FERNANDEZ * frequency synthesizer (fsynth) block. 6685f7aa907SGabriel FERNANDEZ * 6695f7aa907SGabriel FERNANDEZ * @hw: handle between common and hardware-specific interfaces 6705f7aa907SGabriel FERNANDEZ * 6715f7aa907SGabriel FERNANDEZ * @nsb: regmap field in the output control register for the digital 6725f7aa907SGabriel FERNANDEZ * standby of this fsynth channel. This control is active low so 6735f7aa907SGabriel FERNANDEZ * the channel is in standby when the control bit is cleared. 6745f7aa907SGabriel FERNANDEZ * 6755f7aa907SGabriel FERNANDEZ * @nsdiv: regmap field in the output control register for 6765f7aa907SGabriel FERNANDEZ * for the optional divide by 3 of this fsynth channel. This control 6775f7aa907SGabriel FERNANDEZ * is active low so the divide by 3 is active when the control bit is 6785f7aa907SGabriel FERNANDEZ * cleared and the divide is bypassed when the bit is set. 6795f7aa907SGabriel FERNANDEZ */ 6805f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth { 6815f7aa907SGabriel FERNANDEZ struct clk_hw hw; 6825f7aa907SGabriel FERNANDEZ void __iomem *regs_base; 6835f7aa907SGabriel FERNANDEZ spinlock_t *lock; 6845f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *data; 6855f7aa907SGabriel FERNANDEZ 6865f7aa907SGabriel FERNANDEZ u32 chan; 6875f7aa907SGabriel FERNANDEZ /* 6885f7aa907SGabriel FERNANDEZ * Cached hardware values from set_rate so we can program the 6895f7aa907SGabriel FERNANDEZ * hardware in enable. There are two reasons for this: 6905f7aa907SGabriel FERNANDEZ * 6915f7aa907SGabriel FERNANDEZ * 1. The registers may not be writable until the parent has been 6925f7aa907SGabriel FERNANDEZ * enabled. 6935f7aa907SGabriel FERNANDEZ * 6945f7aa907SGabriel FERNANDEZ * 2. It restores the clock rate when a driver does an enable 6955f7aa907SGabriel FERNANDEZ * on PM restore, after a suspend to RAM has lost the hardware 6965f7aa907SGabriel FERNANDEZ * setup. 6975f7aa907SGabriel FERNANDEZ */ 6985f7aa907SGabriel FERNANDEZ u32 md; 6995f7aa907SGabriel FERNANDEZ u32 pe; 7005f7aa907SGabriel FERNANDEZ u32 sdiv; 7015f7aa907SGabriel FERNANDEZ u32 nsdiv; 7025f7aa907SGabriel FERNANDEZ }; 7035f7aa907SGabriel FERNANDEZ 7045f7aa907SGabriel FERNANDEZ #define to_quadfs_fsynth(_hw) \ 7055f7aa907SGabriel FERNANDEZ container_of(_hw, struct st_clk_quadfs_fsynth, hw) 7065f7aa907SGabriel FERNANDEZ 7075f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_program_enable(struct st_clk_quadfs_fsynth *fs) 7085f7aa907SGabriel FERNANDEZ { 7095f7aa907SGabriel FERNANDEZ /* 7105f7aa907SGabriel FERNANDEZ * Pulse the program enable register lsb to make the hardware take 7115f7aa907SGabriel FERNANDEZ * notice of the new md/pe values with a glitchless transition. 7125f7aa907SGabriel FERNANDEZ */ 7135f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, en[fs->chan], 1); 7145f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, en[fs->chan], 0); 7155f7aa907SGabriel FERNANDEZ } 7165f7aa907SGabriel FERNANDEZ 7175f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_program_rate(struct st_clk_quadfs_fsynth *fs) 7185f7aa907SGabriel FERNANDEZ { 7195f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 7205f7aa907SGabriel FERNANDEZ 7215f7aa907SGabriel FERNANDEZ /* 7225f7aa907SGabriel FERNANDEZ * Ensure the md/pe parameters are ignored while we are 7235f7aa907SGabriel FERNANDEZ * reprogramming them so we can get a glitchless change 7245f7aa907SGabriel FERNANDEZ * when fine tuning the speed of a running clock. 7255f7aa907SGabriel FERNANDEZ */ 7265f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, en[fs->chan], 0); 7275f7aa907SGabriel FERNANDEZ 7285f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, mdiv[fs->chan], fs->md); 7295f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, pe[fs->chan], fs->pe); 7305f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, sdiv[fs->chan], fs->sdiv); 7315f7aa907SGabriel FERNANDEZ 7325f7aa907SGabriel FERNANDEZ if (fs->lock) 7335f7aa907SGabriel FERNANDEZ spin_lock_irqsave(fs->lock, flags); 7345f7aa907SGabriel FERNANDEZ 7355f7aa907SGabriel FERNANDEZ if (fs->data->nsdiv_present) 7365f7aa907SGabriel FERNANDEZ CLKGEN_WRITE(fs, nsdiv[fs->chan], fs->nsdiv); 7375f7aa907SGabriel FERNANDEZ 7385f7aa907SGabriel FERNANDEZ if (fs->lock) 7395f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(fs->lock, flags); 7405f7aa907SGabriel FERNANDEZ } 7415f7aa907SGabriel FERNANDEZ 7425f7aa907SGabriel FERNANDEZ static int quadfs_fsynth_enable(struct clk_hw *hw) 7435f7aa907SGabriel FERNANDEZ { 7445f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 7455f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 7465f7aa907SGabriel FERNANDEZ 7475f7aa907SGabriel FERNANDEZ pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); 7485f7aa907SGabriel FERNANDEZ 7495f7aa907SGabriel FERNANDEZ quadfs_fsynth_program_rate(fs); 7505f7aa907SGabriel FERNANDEZ 7515f7aa907SGabriel FERNANDEZ if (fs->lock) 7525f7aa907SGabriel FERNANDEZ spin_lock_irqsave(fs->lock, flags); 7535f7aa907SGabriel FERNANDEZ 7548f26df84SGabriel FERNANDEZ CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity); 7555f7aa907SGabriel FERNANDEZ 756fc755c8bSGabriel FERNANDEZ if (fs->data->nrst_present) 757fc755c8bSGabriel FERNANDEZ CLKGEN_WRITE(fs, nrst[fs->chan], 0); 758fc755c8bSGabriel FERNANDEZ 7595f7aa907SGabriel FERNANDEZ if (fs->lock) 7605f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(fs->lock, flags); 7615f7aa907SGabriel FERNANDEZ 7625f7aa907SGabriel FERNANDEZ quadfs_fsynth_program_enable(fs); 7635f7aa907SGabriel FERNANDEZ 7645f7aa907SGabriel FERNANDEZ return 0; 7655f7aa907SGabriel FERNANDEZ } 7665f7aa907SGabriel FERNANDEZ 7675f7aa907SGabriel FERNANDEZ static void quadfs_fsynth_disable(struct clk_hw *hw) 7685f7aa907SGabriel FERNANDEZ { 7695f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 7705f7aa907SGabriel FERNANDEZ unsigned long flags = 0; 7715f7aa907SGabriel FERNANDEZ 7725f7aa907SGabriel FERNANDEZ pr_debug("%s: %s\n", __func__, __clk_get_name(hw->clk)); 7735f7aa907SGabriel FERNANDEZ 7745f7aa907SGabriel FERNANDEZ if (fs->lock) 7755f7aa907SGabriel FERNANDEZ spin_lock_irqsave(fs->lock, flags); 7765f7aa907SGabriel FERNANDEZ 7778f26df84SGabriel FERNANDEZ CLKGEN_WRITE(fs, nsb[fs->chan], !fs->data->standby_polarity); 7785f7aa907SGabriel FERNANDEZ 7795f7aa907SGabriel FERNANDEZ if (fs->lock) 7805f7aa907SGabriel FERNANDEZ spin_unlock_irqrestore(fs->lock, flags); 7815f7aa907SGabriel FERNANDEZ } 7825f7aa907SGabriel FERNANDEZ 7835f7aa907SGabriel FERNANDEZ static int quadfs_fsynth_is_enabled(struct clk_hw *hw) 7845f7aa907SGabriel FERNANDEZ { 7855f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 7865f7aa907SGabriel FERNANDEZ u32 nsb = CLKGEN_READ(fs, nsb[fs->chan]); 7875f7aa907SGabriel FERNANDEZ 7885f7aa907SGabriel FERNANDEZ pr_debug("%s: %s enable bit = 0x%x\n", 7895f7aa907SGabriel FERNANDEZ __func__, __clk_get_name(hw->clk), nsb); 7905f7aa907SGabriel FERNANDEZ 7918f26df84SGabriel FERNANDEZ return fs->data->standby_polarity ? !nsb : !!nsb; 7925f7aa907SGabriel FERNANDEZ } 7935f7aa907SGabriel FERNANDEZ 7945f7aa907SGabriel FERNANDEZ #define P15 (uint64_t)(1 << 15) 7955f7aa907SGabriel FERNANDEZ 7964abb1b40SGabriel FERNANDEZ static int clk_fs216c65_get_rate(unsigned long input, const struct stm_fs *fs, 7975f7aa907SGabriel FERNANDEZ unsigned long *rate) 7985f7aa907SGabriel FERNANDEZ { 7995f7aa907SGabriel FERNANDEZ uint64_t res; 8005f7aa907SGabriel FERNANDEZ unsigned long ns; 8015f7aa907SGabriel FERNANDEZ unsigned long nd = 8; /* ndiv stuck at 0 => val = 8 */ 8025f7aa907SGabriel FERNANDEZ unsigned long s; 8035f7aa907SGabriel FERNANDEZ long m; 8045f7aa907SGabriel FERNANDEZ 8055f7aa907SGabriel FERNANDEZ m = fs->mdiv - 32; 8065f7aa907SGabriel FERNANDEZ s = 1 << (fs->sdiv + 1); 8075f7aa907SGabriel FERNANDEZ ns = (fs->nsdiv ? 1 : 3); 8085f7aa907SGabriel FERNANDEZ 8095f7aa907SGabriel FERNANDEZ res = (uint64_t)(s * ns * P15 * (uint64_t)(m + 33)); 8105f7aa907SGabriel FERNANDEZ res = res - (s * ns * fs->pe); 8115f7aa907SGabriel FERNANDEZ *rate = div64_u64(P15 * nd * input * 32, res); 8125f7aa907SGabriel FERNANDEZ 8135f7aa907SGabriel FERNANDEZ return 0; 8145f7aa907SGabriel FERNANDEZ } 8155f7aa907SGabriel FERNANDEZ 8164abb1b40SGabriel FERNANDEZ static int clk_fs432c65_get_rate(unsigned long input, const struct stm_fs *fs, 8175f7aa907SGabriel FERNANDEZ unsigned long *rate) 8185f7aa907SGabriel FERNANDEZ { 8195f7aa907SGabriel FERNANDEZ uint64_t res; 8205f7aa907SGabriel FERNANDEZ unsigned long nd = 16; /* ndiv value; stuck at 0 (30Mhz input) */ 8215f7aa907SGabriel FERNANDEZ long m; 8225f7aa907SGabriel FERNANDEZ unsigned long sd; 8235f7aa907SGabriel FERNANDEZ unsigned long ns; 8245f7aa907SGabriel FERNANDEZ 8255f7aa907SGabriel FERNANDEZ m = fs->mdiv - 32; 8265f7aa907SGabriel FERNANDEZ sd = 1 << (fs->sdiv + 1); 8275f7aa907SGabriel FERNANDEZ ns = (fs->nsdiv ? 1 : 3); 8285f7aa907SGabriel FERNANDEZ 8295f7aa907SGabriel FERNANDEZ res = (uint64_t)(sd * ns * P15 * (uint64_t)(m + 33)); 8305f7aa907SGabriel FERNANDEZ res = res - (sd * ns * fs->pe); 8315f7aa907SGabriel FERNANDEZ *rate = div64_u64(P15 * nd * input * 32, res); 8325f7aa907SGabriel FERNANDEZ 8335f7aa907SGabriel FERNANDEZ return 0; 8345f7aa907SGabriel FERNANDEZ } 8355f7aa907SGabriel FERNANDEZ 8365f7aa907SGabriel FERNANDEZ #define P20 (uint64_t)(1 << 20) 8375f7aa907SGabriel FERNANDEZ 8385f7aa907SGabriel FERNANDEZ static int clk_fs660c32_dig_get_rate(unsigned long input, 8394abb1b40SGabriel FERNANDEZ const struct stm_fs *fs, unsigned long *rate) 8405f7aa907SGabriel FERNANDEZ { 8415f7aa907SGabriel FERNANDEZ unsigned long s = (1 << fs->sdiv); 8425f7aa907SGabriel FERNANDEZ unsigned long ns; 8435f7aa907SGabriel FERNANDEZ uint64_t res; 8445f7aa907SGabriel FERNANDEZ 8455f7aa907SGabriel FERNANDEZ /* 8465f7aa907SGabriel FERNANDEZ * 'nsdiv' is a register value ('BIN') which is translated 8475f7aa907SGabriel FERNANDEZ * to a decimal value according to following rules. 8485f7aa907SGabriel FERNANDEZ * 8495f7aa907SGabriel FERNANDEZ * nsdiv ns.dec 8505f7aa907SGabriel FERNANDEZ * 0 3 8515f7aa907SGabriel FERNANDEZ * 1 1 8525f7aa907SGabriel FERNANDEZ */ 8535f7aa907SGabriel FERNANDEZ ns = (fs->nsdiv == 1) ? 1 : 3; 8545f7aa907SGabriel FERNANDEZ 8555f7aa907SGabriel FERNANDEZ res = (P20 * (32 + fs->mdiv) + 32 * fs->pe) * s * ns; 8565f7aa907SGabriel FERNANDEZ *rate = (unsigned long)div64_u64(input * P20 * 32, res); 8575f7aa907SGabriel FERNANDEZ 8585f7aa907SGabriel FERNANDEZ return 0; 8595f7aa907SGabriel FERNANDEZ } 8605f7aa907SGabriel FERNANDEZ 8615f7aa907SGabriel FERNANDEZ static int quadfs_fsynt_get_hw_value_for_recalc(struct st_clk_quadfs_fsynth *fs, 8625f7aa907SGabriel FERNANDEZ struct stm_fs *params) 8635f7aa907SGabriel FERNANDEZ { 8645f7aa907SGabriel FERNANDEZ /* 8655f7aa907SGabriel FERNANDEZ * Get the initial hardware values for recalc_rate 8665f7aa907SGabriel FERNANDEZ */ 8675f7aa907SGabriel FERNANDEZ params->mdiv = CLKGEN_READ(fs, mdiv[fs->chan]); 8685f7aa907SGabriel FERNANDEZ params->pe = CLKGEN_READ(fs, pe[fs->chan]); 8695f7aa907SGabriel FERNANDEZ params->sdiv = CLKGEN_READ(fs, sdiv[fs->chan]); 8705f7aa907SGabriel FERNANDEZ 8715f7aa907SGabriel FERNANDEZ if (fs->data->nsdiv_present) 8725f7aa907SGabriel FERNANDEZ params->nsdiv = CLKGEN_READ(fs, nsdiv[fs->chan]); 8735f7aa907SGabriel FERNANDEZ else 8745f7aa907SGabriel FERNANDEZ params->nsdiv = 1; 8755f7aa907SGabriel FERNANDEZ 8765f7aa907SGabriel FERNANDEZ /* 8775f7aa907SGabriel FERNANDEZ * If All are NULL then assume no clock rate is programmed. 8785f7aa907SGabriel FERNANDEZ */ 8795f7aa907SGabriel FERNANDEZ if (!params->mdiv && !params->pe && !params->sdiv) 8805f7aa907SGabriel FERNANDEZ return 1; 8815f7aa907SGabriel FERNANDEZ 8825f7aa907SGabriel FERNANDEZ fs->md = params->mdiv; 8835f7aa907SGabriel FERNANDEZ fs->pe = params->pe; 8845f7aa907SGabriel FERNANDEZ fs->sdiv = params->sdiv; 8855f7aa907SGabriel FERNANDEZ fs->nsdiv = params->nsdiv; 8865f7aa907SGabriel FERNANDEZ 8875f7aa907SGabriel FERNANDEZ return 0; 8885f7aa907SGabriel FERNANDEZ } 8895f7aa907SGabriel FERNANDEZ 8905f7aa907SGabriel FERNANDEZ static long quadfs_find_best_rate(struct clk_hw *hw, unsigned long drate, 8915f7aa907SGabriel FERNANDEZ unsigned long prate, struct stm_fs *params) 8925f7aa907SGabriel FERNANDEZ { 8935f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 8945f7aa907SGabriel FERNANDEZ int (*clk_fs_get_rate)(unsigned long , 8954abb1b40SGabriel FERNANDEZ const struct stm_fs *, unsigned long *); 8965f7aa907SGabriel FERNANDEZ struct stm_fs prev_params; 8975f7aa907SGabriel FERNANDEZ unsigned long prev_rate, rate = 0; 8985f7aa907SGabriel FERNANDEZ unsigned long diff_rate, prev_diff_rate = ~0; 8995f7aa907SGabriel FERNANDEZ int index; 9005f7aa907SGabriel FERNANDEZ 9015f7aa907SGabriel FERNANDEZ clk_fs_get_rate = fs->data->get_rate; 9025f7aa907SGabriel FERNANDEZ 9035f7aa907SGabriel FERNANDEZ for (index = 0; index < fs->data->rtbl_cnt; index++) { 9045f7aa907SGabriel FERNANDEZ prev_rate = rate; 9055f7aa907SGabriel FERNANDEZ 9065f7aa907SGabriel FERNANDEZ *params = fs->data->rtbl[index]; 9075f7aa907SGabriel FERNANDEZ prev_params = *params; 9085f7aa907SGabriel FERNANDEZ 9095f7aa907SGabriel FERNANDEZ clk_fs_get_rate(prate, &fs->data->rtbl[index], &rate); 9105f7aa907SGabriel FERNANDEZ 9115f7aa907SGabriel FERNANDEZ diff_rate = abs(drate - rate); 9125f7aa907SGabriel FERNANDEZ 9135f7aa907SGabriel FERNANDEZ if (diff_rate > prev_diff_rate) { 9145f7aa907SGabriel FERNANDEZ rate = prev_rate; 9155f7aa907SGabriel FERNANDEZ *params = prev_params; 9165f7aa907SGabriel FERNANDEZ break; 9175f7aa907SGabriel FERNANDEZ } 9185f7aa907SGabriel FERNANDEZ 9195f7aa907SGabriel FERNANDEZ prev_diff_rate = diff_rate; 9205f7aa907SGabriel FERNANDEZ 9215f7aa907SGabriel FERNANDEZ if (drate == rate) 9225f7aa907SGabriel FERNANDEZ return rate; 9235f7aa907SGabriel FERNANDEZ } 9245f7aa907SGabriel FERNANDEZ 9255f7aa907SGabriel FERNANDEZ 9265f7aa907SGabriel FERNANDEZ if (index == fs->data->rtbl_cnt) 9275f7aa907SGabriel FERNANDEZ *params = prev_params; 9285f7aa907SGabriel FERNANDEZ 9295f7aa907SGabriel FERNANDEZ return rate; 9305f7aa907SGabriel FERNANDEZ } 9315f7aa907SGabriel FERNANDEZ 9325f7aa907SGabriel FERNANDEZ static unsigned long quadfs_recalc_rate(struct clk_hw *hw, 9335f7aa907SGabriel FERNANDEZ unsigned long parent_rate) 9345f7aa907SGabriel FERNANDEZ { 9355f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 9365f7aa907SGabriel FERNANDEZ unsigned long rate = 0; 9375f7aa907SGabriel FERNANDEZ struct stm_fs params; 9385f7aa907SGabriel FERNANDEZ int (*clk_fs_get_rate)(unsigned long , 9394abb1b40SGabriel FERNANDEZ const struct stm_fs *, unsigned long *); 9405f7aa907SGabriel FERNANDEZ 9415f7aa907SGabriel FERNANDEZ clk_fs_get_rate = fs->data->get_rate; 9425f7aa907SGabriel FERNANDEZ 9435f7aa907SGabriel FERNANDEZ if (quadfs_fsynt_get_hw_value_for_recalc(fs, ¶ms)) 9445f7aa907SGabriel FERNANDEZ return 0; 9455f7aa907SGabriel FERNANDEZ 9465f7aa907SGabriel FERNANDEZ if (clk_fs_get_rate(parent_rate, ¶ms, &rate)) { 9475f7aa907SGabriel FERNANDEZ pr_err("%s:%s error calculating rate\n", 9485f7aa907SGabriel FERNANDEZ __clk_get_name(hw->clk), __func__); 9495f7aa907SGabriel FERNANDEZ } 9505f7aa907SGabriel FERNANDEZ 9515f7aa907SGabriel FERNANDEZ pr_debug("%s:%s rate %lu\n", __clk_get_name(hw->clk), __func__, rate); 9525f7aa907SGabriel FERNANDEZ 9535f7aa907SGabriel FERNANDEZ return rate; 9545f7aa907SGabriel FERNANDEZ } 9555f7aa907SGabriel FERNANDEZ 9565f7aa907SGabriel FERNANDEZ static long quadfs_round_rate(struct clk_hw *hw, unsigned long rate, 9575f7aa907SGabriel FERNANDEZ unsigned long *prate) 9585f7aa907SGabriel FERNANDEZ { 9595f7aa907SGabriel FERNANDEZ struct stm_fs params; 9605f7aa907SGabriel FERNANDEZ 9615f7aa907SGabriel FERNANDEZ rate = quadfs_find_best_rate(hw, rate, *prate, ¶ms); 9625f7aa907SGabriel FERNANDEZ 9635f7aa907SGabriel FERNANDEZ pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n", 9645f7aa907SGabriel FERNANDEZ __func__, __clk_get_name(hw->clk), 9655f7aa907SGabriel FERNANDEZ rate, (unsigned int)params.sdiv, (unsigned int)params.mdiv, 9665f7aa907SGabriel FERNANDEZ (unsigned int)params.pe, (unsigned int)params.nsdiv); 9675f7aa907SGabriel FERNANDEZ 9685f7aa907SGabriel FERNANDEZ return rate; 9695f7aa907SGabriel FERNANDEZ } 9705f7aa907SGabriel FERNANDEZ 9715f7aa907SGabriel FERNANDEZ 9725f7aa907SGabriel FERNANDEZ static void quadfs_program_and_enable(struct st_clk_quadfs_fsynth *fs, 9735f7aa907SGabriel FERNANDEZ struct stm_fs *params) 9745f7aa907SGabriel FERNANDEZ { 9755f7aa907SGabriel FERNANDEZ fs->md = params->mdiv; 9765f7aa907SGabriel FERNANDEZ fs->pe = params->pe; 9775f7aa907SGabriel FERNANDEZ fs->sdiv = params->sdiv; 9785f7aa907SGabriel FERNANDEZ fs->nsdiv = params->nsdiv; 9795f7aa907SGabriel FERNANDEZ 9805f7aa907SGabriel FERNANDEZ /* 9815f7aa907SGabriel FERNANDEZ * In some integrations you can only change the fsynth programming when 9825f7aa907SGabriel FERNANDEZ * the parent entity containing it is enabled. 9835f7aa907SGabriel FERNANDEZ */ 9845f7aa907SGabriel FERNANDEZ quadfs_fsynth_program_rate(fs); 9855f7aa907SGabriel FERNANDEZ quadfs_fsynth_program_enable(fs); 9865f7aa907SGabriel FERNANDEZ } 9875f7aa907SGabriel FERNANDEZ 9885f7aa907SGabriel FERNANDEZ static int quadfs_set_rate(struct clk_hw *hw, unsigned long rate, 9895f7aa907SGabriel FERNANDEZ unsigned long parent_rate) 9905f7aa907SGabriel FERNANDEZ { 9915f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs = to_quadfs_fsynth(hw); 9925f7aa907SGabriel FERNANDEZ struct stm_fs params; 9935f7aa907SGabriel FERNANDEZ long hwrate; 9945f7aa907SGabriel FERNANDEZ int uninitialized_var(i); 9955f7aa907SGabriel FERNANDEZ 9965f7aa907SGabriel FERNANDEZ if (!rate || !parent_rate) 9975f7aa907SGabriel FERNANDEZ return -EINVAL; 9985f7aa907SGabriel FERNANDEZ 9995f7aa907SGabriel FERNANDEZ memset(¶ms, 0, sizeof(struct stm_fs)); 10005f7aa907SGabriel FERNANDEZ 10015f7aa907SGabriel FERNANDEZ hwrate = quadfs_find_best_rate(hw, rate, parent_rate, ¶ms); 10025f7aa907SGabriel FERNANDEZ if (!hwrate) 10035f7aa907SGabriel FERNANDEZ return -EINVAL; 10045f7aa907SGabriel FERNANDEZ 10055f7aa907SGabriel FERNANDEZ quadfs_program_and_enable(fs, ¶ms); 10065f7aa907SGabriel FERNANDEZ 10075f7aa907SGabriel FERNANDEZ return 0; 10085f7aa907SGabriel FERNANDEZ } 10095f7aa907SGabriel FERNANDEZ 10105f7aa907SGabriel FERNANDEZ 10115f7aa907SGabriel FERNANDEZ 10125f7aa907SGabriel FERNANDEZ static const struct clk_ops st_quadfs_ops = { 10135f7aa907SGabriel FERNANDEZ .enable = quadfs_fsynth_enable, 10145f7aa907SGabriel FERNANDEZ .disable = quadfs_fsynth_disable, 10155f7aa907SGabriel FERNANDEZ .is_enabled = quadfs_fsynth_is_enabled, 10165f7aa907SGabriel FERNANDEZ .round_rate = quadfs_round_rate, 10175f7aa907SGabriel FERNANDEZ .set_rate = quadfs_set_rate, 10185f7aa907SGabriel FERNANDEZ .recalc_rate = quadfs_recalc_rate, 10195f7aa907SGabriel FERNANDEZ }; 10205f7aa907SGabriel FERNANDEZ 10215f7aa907SGabriel FERNANDEZ static struct clk * __init st_clk_register_quadfs_fsynth( 10225f7aa907SGabriel FERNANDEZ const char *name, const char *parent_name, 10235f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *quadfs, void __iomem *reg, u32 chan, 10245f7aa907SGabriel FERNANDEZ spinlock_t *lock) 10255f7aa907SGabriel FERNANDEZ { 10265f7aa907SGabriel FERNANDEZ struct st_clk_quadfs_fsynth *fs; 10275f7aa907SGabriel FERNANDEZ struct clk *clk; 10285f7aa907SGabriel FERNANDEZ struct clk_init_data init; 10295f7aa907SGabriel FERNANDEZ 10305f7aa907SGabriel FERNANDEZ /* 10315f7aa907SGabriel FERNANDEZ * Sanity check required pointers, note that nsdiv3 is optional. 10325f7aa907SGabriel FERNANDEZ */ 10335f7aa907SGabriel FERNANDEZ if (WARN_ON(!name || !parent_name)) 10345f7aa907SGabriel FERNANDEZ return ERR_PTR(-EINVAL); 10355f7aa907SGabriel FERNANDEZ 10365f7aa907SGabriel FERNANDEZ fs = kzalloc(sizeof(*fs), GFP_KERNEL); 10375f7aa907SGabriel FERNANDEZ if (!fs) 10385f7aa907SGabriel FERNANDEZ return ERR_PTR(-ENOMEM); 10395f7aa907SGabriel FERNANDEZ 10405f7aa907SGabriel FERNANDEZ init.name = name; 10415f7aa907SGabriel FERNANDEZ init.ops = &st_quadfs_ops; 10425f7aa907SGabriel FERNANDEZ init.flags = CLK_GET_RATE_NOCACHE | CLK_IS_BASIC; 10435f7aa907SGabriel FERNANDEZ init.parent_names = &parent_name; 10445f7aa907SGabriel FERNANDEZ init.num_parents = 1; 10455f7aa907SGabriel FERNANDEZ 10465f7aa907SGabriel FERNANDEZ fs->data = quadfs; 10475f7aa907SGabriel FERNANDEZ fs->regs_base = reg; 10485f7aa907SGabriel FERNANDEZ fs->chan = chan; 10495f7aa907SGabriel FERNANDEZ fs->lock = lock; 10505f7aa907SGabriel FERNANDEZ fs->hw.init = &init; 10515f7aa907SGabriel FERNANDEZ 10525f7aa907SGabriel FERNANDEZ clk = clk_register(NULL, &fs->hw); 10535f7aa907SGabriel FERNANDEZ 10545f7aa907SGabriel FERNANDEZ if (IS_ERR(clk)) 10555f7aa907SGabriel FERNANDEZ kfree(fs); 10565f7aa907SGabriel FERNANDEZ 10575f7aa907SGabriel FERNANDEZ return clk; 10585f7aa907SGabriel FERNANDEZ } 10595f7aa907SGabriel FERNANDEZ 1060f375573cSFabian Frederick static const struct of_device_id quadfs_of_match[] = { 10615f7aa907SGabriel FERNANDEZ { 10625f7aa907SGabriel FERNANDEZ .compatible = "st,stih416-quadfs216", 106379bb8aa1SGabriel FERNANDEZ .data = &st_fs216c65_416 10645f7aa907SGabriel FERNANDEZ }, 10655f7aa907SGabriel FERNANDEZ { 10665f7aa907SGabriel FERNANDEZ .compatible = "st,stih416-quadfs432", 106779bb8aa1SGabriel FERNANDEZ .data = &st_fs432c65_416 10685f7aa907SGabriel FERNANDEZ }, 10695f7aa907SGabriel FERNANDEZ { 10705f7aa907SGabriel FERNANDEZ .compatible = "st,stih416-quadfs660-E", 107179bb8aa1SGabriel FERNANDEZ .data = &st_fs660c32_E_416 10725f7aa907SGabriel FERNANDEZ }, 10735f7aa907SGabriel FERNANDEZ { 10745f7aa907SGabriel FERNANDEZ .compatible = "st,stih416-quadfs660-F", 107579bb8aa1SGabriel FERNANDEZ .data = &st_fs660c32_F_416 10765f7aa907SGabriel FERNANDEZ }, 107751306d56SGabriel FERNANDEZ { 107851306d56SGabriel FERNANDEZ .compatible = "st,stih407-quadfs660-C", 107951306d56SGabriel FERNANDEZ .data = &st_fs660c32_C_407 108051306d56SGabriel FERNANDEZ }, 108151306d56SGabriel FERNANDEZ { 108251306d56SGabriel FERNANDEZ .compatible = "st,stih407-quadfs660-D", 108351306d56SGabriel FERNANDEZ .data = &st_fs660c32_D_407 108451306d56SGabriel FERNANDEZ }, 108558de9b8eSGabriel FERNANDEZ { 108658de9b8eSGabriel FERNANDEZ .compatible = "st,stih407-quadfs660-D", 108758de9b8eSGabriel FERNANDEZ .data = (void *)&st_fs660c32_D_407 108858de9b8eSGabriel FERNANDEZ }, 10895f7aa907SGabriel FERNANDEZ {} 10905f7aa907SGabriel FERNANDEZ }; 10915f7aa907SGabriel FERNANDEZ 10925f7aa907SGabriel FERNANDEZ static void __init st_of_create_quadfs_fsynths( 10935f7aa907SGabriel FERNANDEZ struct device_node *np, const char *pll_name, 10945f7aa907SGabriel FERNANDEZ struct clkgen_quadfs_data *quadfs, void __iomem *reg, 10955f7aa907SGabriel FERNANDEZ spinlock_t *lock) 10965f7aa907SGabriel FERNANDEZ { 10975f7aa907SGabriel FERNANDEZ struct clk_onecell_data *clk_data; 10985f7aa907SGabriel FERNANDEZ int fschan; 10995f7aa907SGabriel FERNANDEZ 11005f7aa907SGabriel FERNANDEZ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 11015f7aa907SGabriel FERNANDEZ if (!clk_data) 11025f7aa907SGabriel FERNANDEZ return; 11035f7aa907SGabriel FERNANDEZ 11045f7aa907SGabriel FERNANDEZ clk_data->clk_num = QUADFS_MAX_CHAN; 11055f7aa907SGabriel FERNANDEZ clk_data->clks = kzalloc(QUADFS_MAX_CHAN * sizeof(struct clk *), 11065f7aa907SGabriel FERNANDEZ GFP_KERNEL); 11075f7aa907SGabriel FERNANDEZ 11085f7aa907SGabriel FERNANDEZ if (!clk_data->clks) { 11095f7aa907SGabriel FERNANDEZ kfree(clk_data); 11105f7aa907SGabriel FERNANDEZ return; 11115f7aa907SGabriel FERNANDEZ } 11125f7aa907SGabriel FERNANDEZ 11135f7aa907SGabriel FERNANDEZ for (fschan = 0; fschan < QUADFS_MAX_CHAN; fschan++) { 11145f7aa907SGabriel FERNANDEZ struct clk *clk; 11155f7aa907SGabriel FERNANDEZ const char *clk_name; 11165f7aa907SGabriel FERNANDEZ 11175f7aa907SGabriel FERNANDEZ if (of_property_read_string_index(np, "clock-output-names", 11185f7aa907SGabriel FERNANDEZ fschan, &clk_name)) { 11195f7aa907SGabriel FERNANDEZ break; 11205f7aa907SGabriel FERNANDEZ } 11215f7aa907SGabriel FERNANDEZ 11225f7aa907SGabriel FERNANDEZ /* 11235f7aa907SGabriel FERNANDEZ * If we read an empty clock name then the channel is unused 11245f7aa907SGabriel FERNANDEZ */ 11255f7aa907SGabriel FERNANDEZ if (*clk_name == '\0') 11265f7aa907SGabriel FERNANDEZ continue; 11275f7aa907SGabriel FERNANDEZ 11285f7aa907SGabriel FERNANDEZ clk = st_clk_register_quadfs_fsynth(clk_name, pll_name, 11295f7aa907SGabriel FERNANDEZ quadfs, reg, fschan, lock); 11305f7aa907SGabriel FERNANDEZ 11315f7aa907SGabriel FERNANDEZ /* 11325f7aa907SGabriel FERNANDEZ * If there was an error registering this clock output, clean 11335f7aa907SGabriel FERNANDEZ * up and move on to the next one. 11345f7aa907SGabriel FERNANDEZ */ 11355f7aa907SGabriel FERNANDEZ if (!IS_ERR(clk)) { 11365f7aa907SGabriel FERNANDEZ clk_data->clks[fschan] = clk; 11375f7aa907SGabriel FERNANDEZ pr_debug("%s: parent %s rate %u\n", 11385f7aa907SGabriel FERNANDEZ __clk_get_name(clk), 11395f7aa907SGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 11405f7aa907SGabriel FERNANDEZ (unsigned int)clk_get_rate(clk)); 11415f7aa907SGabriel FERNANDEZ } 11425f7aa907SGabriel FERNANDEZ } 11435f7aa907SGabriel FERNANDEZ 11445f7aa907SGabriel FERNANDEZ of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); 11455f7aa907SGabriel FERNANDEZ } 11465f7aa907SGabriel FERNANDEZ 11475f7aa907SGabriel FERNANDEZ static void __init st_of_quadfs_setup(struct device_node *np) 11485f7aa907SGabriel FERNANDEZ { 11495f7aa907SGabriel FERNANDEZ const struct of_device_id *match; 11505f7aa907SGabriel FERNANDEZ struct clk *clk; 11515f7aa907SGabriel FERNANDEZ const char *pll_name, *clk_parent_name; 11525f7aa907SGabriel FERNANDEZ void __iomem *reg; 11535f7aa907SGabriel FERNANDEZ spinlock_t *lock; 11545f7aa907SGabriel FERNANDEZ 11555f7aa907SGabriel FERNANDEZ match = of_match_node(quadfs_of_match, np); 11565f7aa907SGabriel FERNANDEZ if (WARN_ON(!match)) 11575f7aa907SGabriel FERNANDEZ return; 11585f7aa907SGabriel FERNANDEZ 11595f7aa907SGabriel FERNANDEZ reg = of_iomap(np, 0); 11605f7aa907SGabriel FERNANDEZ if (!reg) 11615f7aa907SGabriel FERNANDEZ return; 11625f7aa907SGabriel FERNANDEZ 11635f7aa907SGabriel FERNANDEZ clk_parent_name = of_clk_get_parent_name(np, 0); 11645f7aa907SGabriel FERNANDEZ if (!clk_parent_name) 11655f7aa907SGabriel FERNANDEZ return; 11665f7aa907SGabriel FERNANDEZ 11675f7aa907SGabriel FERNANDEZ pll_name = kasprintf(GFP_KERNEL, "%s.pll", np->name); 11685f7aa907SGabriel FERNANDEZ if (!pll_name) 11695f7aa907SGabriel FERNANDEZ return; 11705f7aa907SGabriel FERNANDEZ 11715f7aa907SGabriel FERNANDEZ lock = kzalloc(sizeof(*lock), GFP_KERNEL); 11725f7aa907SGabriel FERNANDEZ if (!lock) 11735f7aa907SGabriel FERNANDEZ goto err_exit; 11745f7aa907SGabriel FERNANDEZ 11755f7aa907SGabriel FERNANDEZ spin_lock_init(lock); 11765f7aa907SGabriel FERNANDEZ 11775f7aa907SGabriel FERNANDEZ clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, 11785f7aa907SGabriel FERNANDEZ (struct clkgen_quadfs_data *) match->data, reg, lock); 11795f7aa907SGabriel FERNANDEZ if (IS_ERR(clk)) 11805f7aa907SGabriel FERNANDEZ goto err_exit; 11815f7aa907SGabriel FERNANDEZ else 11825f7aa907SGabriel FERNANDEZ pr_debug("%s: parent %s rate %u\n", 11835f7aa907SGabriel FERNANDEZ __clk_get_name(clk), 11845f7aa907SGabriel FERNANDEZ __clk_get_name(clk_get_parent(clk)), 11855f7aa907SGabriel FERNANDEZ (unsigned int)clk_get_rate(clk)); 11865f7aa907SGabriel FERNANDEZ 11875f7aa907SGabriel FERNANDEZ st_of_create_quadfs_fsynths(np, pll_name, 11885f7aa907SGabriel FERNANDEZ (struct clkgen_quadfs_data *)match->data, 11895f7aa907SGabriel FERNANDEZ reg, lock); 11905f7aa907SGabriel FERNANDEZ 11915f7aa907SGabriel FERNANDEZ err_exit: 11925f7aa907SGabriel FERNANDEZ kfree(pll_name); /* No longer need local copy of the PLL name */ 11935f7aa907SGabriel FERNANDEZ } 11945f7aa907SGabriel FERNANDEZ CLK_OF_DECLARE(quadfs, "st,quadfs", st_of_quadfs_setup); 1195