16e9aff55SBiju Das // SPDX-License-Identifier: GPL-2.0+
26e9aff55SBiju Das /*
36e9aff55SBiju Das * Driver for Renesas Versaclock 3
46e9aff55SBiju Das *
56e9aff55SBiju Das * Copyright (C) 2023 Renesas Electronics Corp.
66e9aff55SBiju Das */
76e9aff55SBiju Das
86e9aff55SBiju Das #include <linux/clk-provider.h>
96e9aff55SBiju Das #include <linux/i2c.h>
106e9aff55SBiju Das #include <linux/limits.h>
116e9aff55SBiju Das #include <linux/module.h>
126e9aff55SBiju Das #include <linux/regmap.h>
136e9aff55SBiju Das
146e9aff55SBiju Das #define NUM_CONFIG_REGISTERS 37
156e9aff55SBiju Das
166e9aff55SBiju Das #define VC3_GENERAL_CTR 0x0
176e9aff55SBiju Das #define VC3_GENERAL_CTR_DIV1_SRC_SEL BIT(3)
186e9aff55SBiju Das #define VC3_GENERAL_CTR_PLL3_REFIN_SEL BIT(2)
196e9aff55SBiju Das
206e9aff55SBiju Das #define VC3_PLL3_M_DIVIDER 0x3
216e9aff55SBiju Das #define VC3_PLL3_M_DIV1 BIT(7)
226e9aff55SBiju Das #define VC3_PLL3_M_DIV2 BIT(6)
236e9aff55SBiju Das #define VC3_PLL3_M_DIV(n) ((n) & GENMASK(5, 0))
246e9aff55SBiju Das
256e9aff55SBiju Das #define VC3_PLL3_N_DIVIDER 0x4
266e9aff55SBiju Das #define VC3_PLL3_LOOP_FILTER_N_DIV_MSB 0x5
276e9aff55SBiju Das
286e9aff55SBiju Das #define VC3_PLL3_CHARGE_PUMP_CTRL 0x6
296e9aff55SBiju Das #define VC3_PLL3_CHARGE_PUMP_CTRL_OUTDIV3_SRC_SEL BIT(7)
306e9aff55SBiju Das
316e9aff55SBiju Das #define VC3_PLL1_CTRL_OUTDIV5 0x7
326e9aff55SBiju Das #define VC3_PLL1_CTRL_OUTDIV5_PLL1_MDIV_DOUBLER BIT(7)
336e9aff55SBiju Das
346e9aff55SBiju Das #define VC3_PLL1_M_DIVIDER 0x8
356e9aff55SBiju Das #define VC3_PLL1_M_DIV1 BIT(7)
366e9aff55SBiju Das #define VC3_PLL1_M_DIV2 BIT(6)
376e9aff55SBiju Das #define VC3_PLL1_M_DIV(n) ((n) & GENMASK(5, 0))
386e9aff55SBiju Das
396e9aff55SBiju Das #define VC3_PLL1_VCO_N_DIVIDER 0x9
406e9aff55SBiju Das #define VC3_PLL1_LOOP_FILTER_N_DIV_MSB 0x0a
416e9aff55SBiju Das
426e9aff55SBiju Das #define VC3_OUT_DIV1_DIV2_CTRL 0xf
436e9aff55SBiju Das
446e9aff55SBiju Das #define VC3_PLL2_FB_INT_DIV_MSB 0x10
456e9aff55SBiju Das #define VC3_PLL2_FB_INT_DIV_LSB 0x11
466e9aff55SBiju Das #define VC3_PLL2_FB_FRC_DIV_MSB 0x12
476e9aff55SBiju Das #define VC3_PLL2_FB_FRC_DIV_LSB 0x13
486e9aff55SBiju Das
496e9aff55SBiju Das #define VC3_PLL2_M_DIVIDER 0x1a
506e9aff55SBiju Das #define VC3_PLL2_MDIV_DOUBLER BIT(7)
516e9aff55SBiju Das #define VC3_PLL2_M_DIV1 BIT(6)
526e9aff55SBiju Das #define VC3_PLL2_M_DIV2 BIT(5)
536e9aff55SBiju Das #define VC3_PLL2_M_DIV(n) ((n) & GENMASK(4, 0))
546e9aff55SBiju Das
556e9aff55SBiju Das #define VC3_OUT_DIV3_DIV4_CTRL 0x1b
566e9aff55SBiju Das
576e9aff55SBiju Das #define VC3_PLL_OP_CTRL 0x1c
586e9aff55SBiju Das #define VC3_PLL_OP_CTRL_PLL2_REFIN_SEL 6
596e9aff55SBiju Das
606e9aff55SBiju Das #define VC3_OUTPUT_CTR 0x1d
616e9aff55SBiju Das #define VC3_OUTPUT_CTR_DIV4_SRC_SEL BIT(3)
626e9aff55SBiju Das
636e9aff55SBiju Das #define VC3_SE2_CTRL_REG0 0x1f
646e9aff55SBiju Das #define VC3_SE2_CTRL_REG0_SE2_CLK_SEL BIT(6)
656e9aff55SBiju Das
666e9aff55SBiju Das #define VC3_SE3_DIFF1_CTRL_REG 0x21
676e9aff55SBiju Das #define VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL BIT(6)
686e9aff55SBiju Das
696e9aff55SBiju Das #define VC3_DIFF1_CTRL_REG 0x22
706e9aff55SBiju Das #define VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL BIT(7)
716e9aff55SBiju Das
726e9aff55SBiju Das #define VC3_DIFF2_CTRL_REG 0x23
736e9aff55SBiju Das #define VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL BIT(7)
746e9aff55SBiju Das
756e9aff55SBiju Das #define VC3_SE1_DIV4_CTRL 0x24
766e9aff55SBiju Das #define VC3_SE1_DIV4_CTRL_SE1_CLK_SEL BIT(3)
776e9aff55SBiju Das
786e9aff55SBiju Das #define VC3_PLL1_VCO_MIN 300000000UL
796e9aff55SBiju Das #define VC3_PLL1_VCO_MAX 600000000UL
806e9aff55SBiju Das
816e9aff55SBiju Das #define VC3_PLL2_VCO_MIN 400000000UL
826e9aff55SBiju Das #define VC3_PLL2_VCO_MAX 1200000000UL
836e9aff55SBiju Das
846e9aff55SBiju Das #define VC3_PLL3_VCO_MIN 300000000UL
856e9aff55SBiju Das #define VC3_PLL3_VCO_MAX 800000000UL
866e9aff55SBiju Das
876e9aff55SBiju Das #define VC3_2_POW_16 (U16_MAX + 1)
886e9aff55SBiju Das #define VC3_DIV_MASK(width) ((1 << (width)) - 1)
896e9aff55SBiju Das
906e9aff55SBiju Das enum vc3_pfd_mux {
916e9aff55SBiju Das VC3_PFD2_MUX,
926e9aff55SBiju Das VC3_PFD3_MUX,
936e9aff55SBiju Das };
946e9aff55SBiju Das
956e9aff55SBiju Das enum vc3_pfd {
966e9aff55SBiju Das VC3_PFD1,
976e9aff55SBiju Das VC3_PFD2,
986e9aff55SBiju Das VC3_PFD3,
996e9aff55SBiju Das };
1006e9aff55SBiju Das
1016e9aff55SBiju Das enum vc3_pll {
1026e9aff55SBiju Das VC3_PLL1,
1036e9aff55SBiju Das VC3_PLL2,
1046e9aff55SBiju Das VC3_PLL3,
1056e9aff55SBiju Das };
1066e9aff55SBiju Das
1076e9aff55SBiju Das enum vc3_div_mux {
1086e9aff55SBiju Das VC3_DIV1_MUX,
1096e9aff55SBiju Das VC3_DIV3_MUX,
1106e9aff55SBiju Das VC3_DIV4_MUX,
1116e9aff55SBiju Das };
1126e9aff55SBiju Das
1136e9aff55SBiju Das enum vc3_div {
1146e9aff55SBiju Das VC3_DIV1,
1156e9aff55SBiju Das VC3_DIV2,
1166e9aff55SBiju Das VC3_DIV3,
1176e9aff55SBiju Das VC3_DIV4,
1186e9aff55SBiju Das VC3_DIV5,
1196e9aff55SBiju Das };
1206e9aff55SBiju Das
1216e9aff55SBiju Das enum vc3_clk {
1226e9aff55SBiju Das VC3_REF,
1236dcf03bcSBiju Das VC3_SE1,
1246dcf03bcSBiju Das VC3_SE2,
1256dcf03bcSBiju Das VC3_SE3,
1266dcf03bcSBiju Das VC3_DIFF1,
1276dcf03bcSBiju Das VC3_DIFF2,
1286e9aff55SBiju Das };
1296e9aff55SBiju Das
130*eec11486SBiju Das enum vc3_clk_mux {
131*eec11486SBiju Das VC3_SE1_MUX = VC3_SE1 - 1,
132*eec11486SBiju Das VC3_SE2_MUX = VC3_SE2 - 1,
133*eec11486SBiju Das VC3_SE3_MUX = VC3_SE3 - 1,
134*eec11486SBiju Das VC3_DIFF1_MUX = VC3_DIFF1 - 1,
135*eec11486SBiju Das VC3_DIFF2_MUX = VC3_DIFF2 - 1,
136*eec11486SBiju Das };
137*eec11486SBiju Das
1386e9aff55SBiju Das struct vc3_clk_data {
1396e9aff55SBiju Das u8 offs;
1406e9aff55SBiju Das u8 bitmsk;
1416e9aff55SBiju Das };
1426e9aff55SBiju Das
1436e9aff55SBiju Das struct vc3_pfd_data {
1446e9aff55SBiju Das u8 num;
1456e9aff55SBiju Das u8 offs;
1466e9aff55SBiju Das u8 mdiv1_bitmsk;
1476e9aff55SBiju Das u8 mdiv2_bitmsk;
1486e9aff55SBiju Das };
1496e9aff55SBiju Das
1506e9aff55SBiju Das struct vc3_pll_data {
1516e9aff55SBiju Das u8 num;
1526e9aff55SBiju Das u8 int_div_msb_offs;
1536e9aff55SBiju Das u8 int_div_lsb_offs;
1546e9aff55SBiju Das unsigned long vco_min;
1556e9aff55SBiju Das unsigned long vco_max;
1566e9aff55SBiju Das };
1576e9aff55SBiju Das
1586e9aff55SBiju Das struct vc3_div_data {
1596e9aff55SBiju Das u8 offs;
1606e9aff55SBiju Das const struct clk_div_table *table;
1616e9aff55SBiju Das u8 shift;
1626e9aff55SBiju Das u8 width;
1636e9aff55SBiju Das u8 flags;
1646e9aff55SBiju Das };
1656e9aff55SBiju Das
1666e9aff55SBiju Das struct vc3_hw_data {
1676e9aff55SBiju Das struct clk_hw hw;
1686e9aff55SBiju Das struct regmap *regmap;
1696e9aff55SBiju Das const void *data;
1706e9aff55SBiju Das
1716e9aff55SBiju Das u32 div_int;
1726e9aff55SBiju Das u32 div_frc;
1736e9aff55SBiju Das };
1746e9aff55SBiju Das
1756e9aff55SBiju Das static const struct clk_div_table div1_divs[] = {
1766e9aff55SBiju Das { .val = 0, .div = 1, }, { .val = 1, .div = 4, },
1776e9aff55SBiju Das { .val = 2, .div = 5, }, { .val = 3, .div = 6, },
1786e9aff55SBiju Das { .val = 4, .div = 2, }, { .val = 5, .div = 8, },
1796e9aff55SBiju Das { .val = 6, .div = 10, }, { .val = 7, .div = 12, },
1806e9aff55SBiju Das { .val = 8, .div = 4, }, { .val = 9, .div = 16, },
1816e9aff55SBiju Das { .val = 10, .div = 20, }, { .val = 11, .div = 24, },
1826e9aff55SBiju Das { .val = 12, .div = 8, }, { .val = 13, .div = 32, },
1836e9aff55SBiju Das { .val = 14, .div = 40, }, { .val = 15, .div = 48, },
1846e9aff55SBiju Das {}
1856e9aff55SBiju Das };
1866e9aff55SBiju Das
1876e9aff55SBiju Das static const struct clk_div_table div245_divs[] = {
1886e9aff55SBiju Das { .val = 0, .div = 1, }, { .val = 1, .div = 3, },
1896e9aff55SBiju Das { .val = 2, .div = 5, }, { .val = 3, .div = 10, },
1906e9aff55SBiju Das { .val = 4, .div = 2, }, { .val = 5, .div = 6, },
1916e9aff55SBiju Das { .val = 6, .div = 10, }, { .val = 7, .div = 20, },
1926e9aff55SBiju Das { .val = 8, .div = 4, }, { .val = 9, .div = 12, },
1936e9aff55SBiju Das { .val = 10, .div = 20, }, { .val = 11, .div = 40, },
1946e9aff55SBiju Das { .val = 12, .div = 5, }, { .val = 13, .div = 15, },
1956e9aff55SBiju Das { .val = 14, .div = 25, }, { .val = 15, .div = 50, },
1966e9aff55SBiju Das {}
1976e9aff55SBiju Das };
1986e9aff55SBiju Das
1996e9aff55SBiju Das static const struct clk_div_table div3_divs[] = {
2006e9aff55SBiju Das { .val = 0, .div = 1, }, { .val = 1, .div = 3, },
2016e9aff55SBiju Das { .val = 2, .div = 5, }, { .val = 3, .div = 10, },
2026e9aff55SBiju Das { .val = 4, .div = 2, }, { .val = 5, .div = 6, },
2036e9aff55SBiju Das { .val = 6, .div = 10, }, { .val = 7, .div = 20, },
2046e9aff55SBiju Das { .val = 8, .div = 4, }, { .val = 9, .div = 12, },
2056e9aff55SBiju Das { .val = 10, .div = 20, }, { .val = 11, .div = 40, },
2066e9aff55SBiju Das { .val = 12, .div = 8, }, { .val = 13, .div = 24, },
2076e9aff55SBiju Das { .val = 14, .div = 40, }, { .val = 15, .div = 80, },
2086e9aff55SBiju Das {}
2096e9aff55SBiju Das };
2106e9aff55SBiju Das
2116e9aff55SBiju Das static struct clk_hw *clk_out[6];
2126e9aff55SBiju Das
vc3_pfd_mux_get_parent(struct clk_hw * hw)2136e9aff55SBiju Das static unsigned char vc3_pfd_mux_get_parent(struct clk_hw *hw)
2146e9aff55SBiju Das {
2156e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
2166e9aff55SBiju Das const struct vc3_clk_data *pfd_mux = vc3->data;
2176e9aff55SBiju Das u32 src;
2186e9aff55SBiju Das
2196e9aff55SBiju Das regmap_read(vc3->regmap, pfd_mux->offs, &src);
2206e9aff55SBiju Das
2216e9aff55SBiju Das return !!(src & pfd_mux->bitmsk);
2226e9aff55SBiju Das }
2236e9aff55SBiju Das
vc3_pfd_mux_set_parent(struct clk_hw * hw,u8 index)2246e9aff55SBiju Das static int vc3_pfd_mux_set_parent(struct clk_hw *hw, u8 index)
2256e9aff55SBiju Das {
2266e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
2276e9aff55SBiju Das const struct vc3_clk_data *pfd_mux = vc3->data;
2286e9aff55SBiju Das
2296e9aff55SBiju Das regmap_update_bits(vc3->regmap, pfd_mux->offs, pfd_mux->bitmsk,
2306e9aff55SBiju Das index ? pfd_mux->bitmsk : 0);
2316e9aff55SBiju Das return 0;
2326e9aff55SBiju Das }
2336e9aff55SBiju Das
2346e9aff55SBiju Das static const struct clk_ops vc3_pfd_mux_ops = {
2356e9aff55SBiju Das .determine_rate = clk_hw_determine_rate_no_reparent,
2366e9aff55SBiju Das .set_parent = vc3_pfd_mux_set_parent,
2376e9aff55SBiju Das .get_parent = vc3_pfd_mux_get_parent,
2386e9aff55SBiju Das };
2396e9aff55SBiju Das
vc3_pfd_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)2406e9aff55SBiju Das static unsigned long vc3_pfd_recalc_rate(struct clk_hw *hw,
2416e9aff55SBiju Das unsigned long parent_rate)
2426e9aff55SBiju Das {
2436e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
2446e9aff55SBiju Das const struct vc3_pfd_data *pfd = vc3->data;
2456e9aff55SBiju Das unsigned int prediv, premul;
2466e9aff55SBiju Das unsigned long rate;
2476e9aff55SBiju Das u8 mdiv;
2486e9aff55SBiju Das
2496e9aff55SBiju Das regmap_read(vc3->regmap, pfd->offs, &prediv);
2506e9aff55SBiju Das if (pfd->num == VC3_PFD1) {
2516e9aff55SBiju Das /* The bypass_prediv is set, PLL fed from Ref_in directly. */
2526e9aff55SBiju Das if (prediv & pfd->mdiv1_bitmsk) {
2536e9aff55SBiju Das /* check doubler is set or not */
2546e9aff55SBiju Das regmap_read(vc3->regmap, VC3_PLL1_CTRL_OUTDIV5, &premul);
2556e9aff55SBiju Das if (premul & VC3_PLL1_CTRL_OUTDIV5_PLL1_MDIV_DOUBLER)
2566e9aff55SBiju Das parent_rate *= 2;
2576e9aff55SBiju Das return parent_rate;
2586e9aff55SBiju Das }
2596e9aff55SBiju Das mdiv = VC3_PLL1_M_DIV(prediv);
2606e9aff55SBiju Das } else if (pfd->num == VC3_PFD2) {
2616e9aff55SBiju Das /* The bypass_prediv is set, PLL fed from Ref_in directly. */
2626e9aff55SBiju Das if (prediv & pfd->mdiv1_bitmsk) {
2636e9aff55SBiju Das regmap_read(vc3->regmap, VC3_PLL2_M_DIVIDER, &premul);
2646e9aff55SBiju Das /* check doubler is set or not */
2656e9aff55SBiju Das if (premul & VC3_PLL2_MDIV_DOUBLER)
2666e9aff55SBiju Das parent_rate *= 2;
2676e9aff55SBiju Das return parent_rate;
2686e9aff55SBiju Das }
2696e9aff55SBiju Das
2706e9aff55SBiju Das mdiv = VC3_PLL2_M_DIV(prediv);
2716e9aff55SBiju Das } else {
2726e9aff55SBiju Das /* The bypass_prediv is set, PLL fed from Ref_in directly. */
2736e9aff55SBiju Das if (prediv & pfd->mdiv1_bitmsk)
2746e9aff55SBiju Das return parent_rate;
2756e9aff55SBiju Das
2766e9aff55SBiju Das mdiv = VC3_PLL3_M_DIV(prediv);
2776e9aff55SBiju Das }
2786e9aff55SBiju Das
2796e9aff55SBiju Das if (prediv & pfd->mdiv2_bitmsk)
2806e9aff55SBiju Das rate = parent_rate / 2;
2816e9aff55SBiju Das else
2826e9aff55SBiju Das rate = parent_rate / mdiv;
2836e9aff55SBiju Das
2846e9aff55SBiju Das return rate;
2856e9aff55SBiju Das }
2866e9aff55SBiju Das
vc3_pfd_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)2876e9aff55SBiju Das static long vc3_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
2886e9aff55SBiju Das unsigned long *parent_rate)
2896e9aff55SBiju Das {
2906e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
2916e9aff55SBiju Das const struct vc3_pfd_data *pfd = vc3->data;
2926e9aff55SBiju Das unsigned long idiv;
2936e9aff55SBiju Das
2946e9aff55SBiju Das /* PLL cannot operate with input clock above 50 MHz. */
2956e9aff55SBiju Das if (rate > 50000000)
2966e9aff55SBiju Das return -EINVAL;
2976e9aff55SBiju Das
2986e9aff55SBiju Das /* CLKIN within range of PLL input, feed directly to PLL. */
2996e9aff55SBiju Das if (*parent_rate <= 50000000)
3006e9aff55SBiju Das return *parent_rate;
3016e9aff55SBiju Das
3026e9aff55SBiju Das idiv = DIV_ROUND_UP(*parent_rate, rate);
3036e9aff55SBiju Das if (pfd->num == VC3_PFD1 || pfd->num == VC3_PFD3) {
3046e9aff55SBiju Das if (idiv > 63)
3056e9aff55SBiju Das return -EINVAL;
3066e9aff55SBiju Das } else {
3076e9aff55SBiju Das if (idiv > 31)
3086e9aff55SBiju Das return -EINVAL;
3096e9aff55SBiju Das }
3106e9aff55SBiju Das
3116e9aff55SBiju Das return *parent_rate / idiv;
3126e9aff55SBiju Das }
3136e9aff55SBiju Das
vc3_pfd_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)3146e9aff55SBiju Das static int vc3_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
3156e9aff55SBiju Das unsigned long parent_rate)
3166e9aff55SBiju Das {
3176e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
3186e9aff55SBiju Das const struct vc3_pfd_data *pfd = vc3->data;
3196e9aff55SBiju Das unsigned long idiv;
3206e9aff55SBiju Das u8 div;
3216e9aff55SBiju Das
3226e9aff55SBiju Das /* CLKIN within range of PLL input, feed directly to PLL. */
3236e9aff55SBiju Das if (parent_rate <= 50000000) {
3246e9aff55SBiju Das regmap_update_bits(vc3->regmap, pfd->offs, pfd->mdiv1_bitmsk,
3256e9aff55SBiju Das pfd->mdiv1_bitmsk);
3266e9aff55SBiju Das regmap_update_bits(vc3->regmap, pfd->offs, pfd->mdiv2_bitmsk, 0);
3276e9aff55SBiju Das return 0;
3286e9aff55SBiju Das }
3296e9aff55SBiju Das
3306e9aff55SBiju Das idiv = DIV_ROUND_UP(parent_rate, rate);
3316e9aff55SBiju Das /* We have dedicated div-2 predivider. */
3326e9aff55SBiju Das if (idiv == 2) {
3336e9aff55SBiju Das regmap_update_bits(vc3->regmap, pfd->offs, pfd->mdiv2_bitmsk,
3346e9aff55SBiju Das pfd->mdiv2_bitmsk);
3356e9aff55SBiju Das regmap_update_bits(vc3->regmap, pfd->offs, pfd->mdiv1_bitmsk, 0);
3366e9aff55SBiju Das } else {
3376e9aff55SBiju Das if (pfd->num == VC3_PFD1)
3386e9aff55SBiju Das div = VC3_PLL1_M_DIV(idiv);
3396e9aff55SBiju Das else if (pfd->num == VC3_PFD2)
3406e9aff55SBiju Das div = VC3_PLL2_M_DIV(idiv);
3416e9aff55SBiju Das else
3426e9aff55SBiju Das div = VC3_PLL3_M_DIV(idiv);
3436e9aff55SBiju Das
3446e9aff55SBiju Das regmap_write(vc3->regmap, pfd->offs, div);
3456e9aff55SBiju Das }
3466e9aff55SBiju Das
3476e9aff55SBiju Das return 0;
3486e9aff55SBiju Das }
3496e9aff55SBiju Das
3506e9aff55SBiju Das static const struct clk_ops vc3_pfd_ops = {
3516e9aff55SBiju Das .recalc_rate = vc3_pfd_recalc_rate,
3526e9aff55SBiju Das .round_rate = vc3_pfd_round_rate,
3536e9aff55SBiju Das .set_rate = vc3_pfd_set_rate,
3546e9aff55SBiju Das };
3556e9aff55SBiju Das
vc3_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)3566e9aff55SBiju Das static unsigned long vc3_pll_recalc_rate(struct clk_hw *hw,
3576e9aff55SBiju Das unsigned long parent_rate)
3586e9aff55SBiju Das {
3596e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
3606e9aff55SBiju Das const struct vc3_pll_data *pll = vc3->data;
3616e9aff55SBiju Das u32 div_int, div_frc, val;
3626e9aff55SBiju Das unsigned long rate;
3636e9aff55SBiju Das
3646e9aff55SBiju Das regmap_read(vc3->regmap, pll->int_div_msb_offs, &val);
3656e9aff55SBiju Das div_int = (val & GENMASK(2, 0)) << 8;
3666e9aff55SBiju Das regmap_read(vc3->regmap, pll->int_div_lsb_offs, &val);
3676e9aff55SBiju Das div_int |= val;
3686e9aff55SBiju Das
3696e9aff55SBiju Das if (pll->num == VC3_PLL2) {
3706e9aff55SBiju Das regmap_read(vc3->regmap, VC3_PLL2_FB_FRC_DIV_MSB, &val);
3716e9aff55SBiju Das div_frc = val << 8;
3726e9aff55SBiju Das regmap_read(vc3->regmap, VC3_PLL2_FB_FRC_DIV_LSB, &val);
3736e9aff55SBiju Das div_frc |= val;
3746e9aff55SBiju Das rate = (parent_rate *
3756e9aff55SBiju Das (div_int * VC3_2_POW_16 + div_frc) / VC3_2_POW_16);
3766e9aff55SBiju Das } else {
3776e9aff55SBiju Das rate = parent_rate * div_int;
3786e9aff55SBiju Das }
3796e9aff55SBiju Das
3806e9aff55SBiju Das return rate;
3816e9aff55SBiju Das }
3826e9aff55SBiju Das
vc3_pll_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)3836e9aff55SBiju Das static long vc3_pll_round_rate(struct clk_hw *hw, unsigned long rate,
3846e9aff55SBiju Das unsigned long *parent_rate)
3856e9aff55SBiju Das {
3866e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
3876e9aff55SBiju Das const struct vc3_pll_data *pll = vc3->data;
3886e9aff55SBiju Das u64 div_frc;
3896e9aff55SBiju Das
3906e9aff55SBiju Das if (rate < pll->vco_min)
3916e9aff55SBiju Das rate = pll->vco_min;
3926e9aff55SBiju Das if (rate > pll->vco_max)
3936e9aff55SBiju Das rate = pll->vco_max;
3946e9aff55SBiju Das
3956e9aff55SBiju Das vc3->div_int = rate / *parent_rate;
3966e9aff55SBiju Das
3976e9aff55SBiju Das if (pll->num == VC3_PLL2) {
3986e9aff55SBiju Das if (vc3->div_int > 0x7ff)
3996e9aff55SBiju Das rate = *parent_rate * 0x7ff;
4006e9aff55SBiju Das
4016e9aff55SBiju Das /* Determine best fractional part, which is 16 bit wide */
4026e9aff55SBiju Das div_frc = rate % *parent_rate;
4036e9aff55SBiju Das div_frc *= BIT(16) - 1;
4046e9aff55SBiju Das
405576418e3SBiju Das vc3->div_frc = min_t(u64, div64_ul(div_frc, *parent_rate), U16_MAX);
4066e9aff55SBiju Das rate = (*parent_rate *
407576418e3SBiju Das (vc3->div_int * VC3_2_POW_16 + vc3->div_frc) / VC3_2_POW_16);
4086e9aff55SBiju Das } else {
4096e9aff55SBiju Das rate = *parent_rate * vc3->div_int;
4106e9aff55SBiju Das }
4116e9aff55SBiju Das
4126e9aff55SBiju Das return rate;
4136e9aff55SBiju Das }
4146e9aff55SBiju Das
vc3_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)4156e9aff55SBiju Das static int vc3_pll_set_rate(struct clk_hw *hw, unsigned long rate,
4166e9aff55SBiju Das unsigned long parent_rate)
4176e9aff55SBiju Das {
4186e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
4196e9aff55SBiju Das const struct vc3_pll_data *pll = vc3->data;
4206e9aff55SBiju Das u32 val;
4216e9aff55SBiju Das
4226e9aff55SBiju Das regmap_read(vc3->regmap, pll->int_div_msb_offs, &val);
4236e9aff55SBiju Das val = (val & 0xf8) | ((vc3->div_int >> 8) & 0x7);
4246e9aff55SBiju Das regmap_write(vc3->regmap, pll->int_div_msb_offs, val);
4256e9aff55SBiju Das regmap_write(vc3->regmap, pll->int_div_lsb_offs, vc3->div_int & 0xff);
4266e9aff55SBiju Das
4276e9aff55SBiju Das if (pll->num == VC3_PLL2) {
4286e9aff55SBiju Das regmap_write(vc3->regmap, VC3_PLL2_FB_FRC_DIV_MSB,
4296e9aff55SBiju Das vc3->div_frc >> 8);
4306e9aff55SBiju Das regmap_write(vc3->regmap, VC3_PLL2_FB_FRC_DIV_LSB,
4316e9aff55SBiju Das vc3->div_frc & 0xff);
4326e9aff55SBiju Das }
4336e9aff55SBiju Das
4346e9aff55SBiju Das return 0;
4356e9aff55SBiju Das }
4366e9aff55SBiju Das
4376e9aff55SBiju Das static const struct clk_ops vc3_pll_ops = {
4386e9aff55SBiju Das .recalc_rate = vc3_pll_recalc_rate,
4396e9aff55SBiju Das .round_rate = vc3_pll_round_rate,
4406e9aff55SBiju Das .set_rate = vc3_pll_set_rate,
4416e9aff55SBiju Das };
4426e9aff55SBiju Das
vc3_div_mux_get_parent(struct clk_hw * hw)4436e9aff55SBiju Das static unsigned char vc3_div_mux_get_parent(struct clk_hw *hw)
4446e9aff55SBiju Das {
4456e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
4466e9aff55SBiju Das const struct vc3_clk_data *div_mux = vc3->data;
4476e9aff55SBiju Das u32 src;
4486e9aff55SBiju Das
4496e9aff55SBiju Das regmap_read(vc3->regmap, div_mux->offs, &src);
4506e9aff55SBiju Das
4516e9aff55SBiju Das return !!(src & div_mux->bitmsk);
4526e9aff55SBiju Das }
4536e9aff55SBiju Das
vc3_div_mux_set_parent(struct clk_hw * hw,u8 index)4546e9aff55SBiju Das static int vc3_div_mux_set_parent(struct clk_hw *hw, u8 index)
4556e9aff55SBiju Das {
4566e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
4576e9aff55SBiju Das const struct vc3_clk_data *div_mux = vc3->data;
4586e9aff55SBiju Das
4596e9aff55SBiju Das regmap_update_bits(vc3->regmap, div_mux->offs, div_mux->bitmsk,
4606e9aff55SBiju Das index ? div_mux->bitmsk : 0);
4616e9aff55SBiju Das
4626e9aff55SBiju Das return 0;
4636e9aff55SBiju Das }
4646e9aff55SBiju Das
4656e9aff55SBiju Das static const struct clk_ops vc3_div_mux_ops = {
4666e9aff55SBiju Das .determine_rate = clk_hw_determine_rate_no_reparent,
4676e9aff55SBiju Das .set_parent = vc3_div_mux_set_parent,
4686e9aff55SBiju Das .get_parent = vc3_div_mux_get_parent,
4696e9aff55SBiju Das };
4706e9aff55SBiju Das
vc3_get_div(const struct clk_div_table * table,unsigned int val,unsigned long flag)4716e9aff55SBiju Das static unsigned int vc3_get_div(const struct clk_div_table *table,
4726e9aff55SBiju Das unsigned int val, unsigned long flag)
4736e9aff55SBiju Das {
4746e9aff55SBiju Das const struct clk_div_table *clkt;
4756e9aff55SBiju Das
4766e9aff55SBiju Das for (clkt = table; clkt->div; clkt++)
4776e9aff55SBiju Das if (clkt->val == val)
4786e9aff55SBiju Das return clkt->div;
4796e9aff55SBiju Das
4806e9aff55SBiju Das return 0;
4816e9aff55SBiju Das }
4826e9aff55SBiju Das
vc3_div_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)4836e9aff55SBiju Das static unsigned long vc3_div_recalc_rate(struct clk_hw *hw,
4846e9aff55SBiju Das unsigned long parent_rate)
4856e9aff55SBiju Das {
4866e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
4876e9aff55SBiju Das const struct vc3_div_data *div_data = vc3->data;
4886e9aff55SBiju Das unsigned int val;
4896e9aff55SBiju Das
4906e9aff55SBiju Das regmap_read(vc3->regmap, div_data->offs, &val);
4916e9aff55SBiju Das val >>= div_data->shift;
4926e9aff55SBiju Das val &= VC3_DIV_MASK(div_data->width);
4936e9aff55SBiju Das
4946e9aff55SBiju Das return divider_recalc_rate(hw, parent_rate, val, div_data->table,
4956e9aff55SBiju Das div_data->flags, div_data->width);
4966e9aff55SBiju Das }
4976e9aff55SBiju Das
vc3_div_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * parent_rate)4986e9aff55SBiju Das static long vc3_div_round_rate(struct clk_hw *hw, unsigned long rate,
4996e9aff55SBiju Das unsigned long *parent_rate)
5006e9aff55SBiju Das {
5016e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
5026e9aff55SBiju Das const struct vc3_div_data *div_data = vc3->data;
5036e9aff55SBiju Das unsigned int bestdiv;
5046e9aff55SBiju Das
5056e9aff55SBiju Das /* if read only, just return current value */
5066e9aff55SBiju Das if (div_data->flags & CLK_DIVIDER_READ_ONLY) {
5076e9aff55SBiju Das regmap_read(vc3->regmap, div_data->offs, &bestdiv);
5086e9aff55SBiju Das bestdiv >>= div_data->shift;
5096e9aff55SBiju Das bestdiv &= VC3_DIV_MASK(div_data->width);
5106e9aff55SBiju Das bestdiv = vc3_get_div(div_data->table, bestdiv, div_data->flags);
5116e9aff55SBiju Das return DIV_ROUND_UP(*parent_rate, bestdiv);
5126e9aff55SBiju Das }
5136e9aff55SBiju Das
5146e9aff55SBiju Das return divider_round_rate(hw, rate, parent_rate, div_data->table,
5156e9aff55SBiju Das div_data->width, div_data->flags);
5166e9aff55SBiju Das }
5176e9aff55SBiju Das
vc3_div_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)5186e9aff55SBiju Das static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate,
5196e9aff55SBiju Das unsigned long parent_rate)
5206e9aff55SBiju Das {
5216e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
5226e9aff55SBiju Das const struct vc3_div_data *div_data = vc3->data;
5236e9aff55SBiju Das unsigned int value;
5246e9aff55SBiju Das
5256e9aff55SBiju Das value = divider_get_val(rate, parent_rate, div_data->table,
5266e9aff55SBiju Das div_data->width, div_data->flags);
5276e9aff55SBiju Das regmap_update_bits(vc3->regmap, div_data->offs,
5286e9aff55SBiju Das VC3_DIV_MASK(div_data->width) << div_data->shift,
5296e9aff55SBiju Das value << div_data->shift);
5306e9aff55SBiju Das return 0;
5316e9aff55SBiju Das }
5326e9aff55SBiju Das
5336e9aff55SBiju Das static const struct clk_ops vc3_div_ops = {
5346e9aff55SBiju Das .recalc_rate = vc3_div_recalc_rate,
5356e9aff55SBiju Das .round_rate = vc3_div_round_rate,
5366e9aff55SBiju Das .set_rate = vc3_div_set_rate,
5376e9aff55SBiju Das };
5386e9aff55SBiju Das
vc3_clk_mux_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)5396e9aff55SBiju Das static int vc3_clk_mux_determine_rate(struct clk_hw *hw,
5406e9aff55SBiju Das struct clk_rate_request *req)
5416e9aff55SBiju Das {
5426e9aff55SBiju Das int ret;
5436e9aff55SBiju Das int frc;
5446e9aff55SBiju Das
5456e9aff55SBiju Das ret = clk_mux_determine_rate_flags(hw, req, CLK_SET_RATE_PARENT);
5466e9aff55SBiju Das if (ret) {
5476e9aff55SBiju Das /* The below check is equivalent to (best_parent_rate/rate) */
5486e9aff55SBiju Das if (req->best_parent_rate >= req->rate) {
5496e9aff55SBiju Das frc = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate,
5506e9aff55SBiju Das req->rate);
5516e9aff55SBiju Das req->rate *= frc;
5526e9aff55SBiju Das return clk_mux_determine_rate_flags(hw, req,
5536e9aff55SBiju Das CLK_SET_RATE_PARENT);
5546e9aff55SBiju Das }
5556e9aff55SBiju Das ret = 0;
5566e9aff55SBiju Das }
5576e9aff55SBiju Das
5586e9aff55SBiju Das return ret;
5596e9aff55SBiju Das }
5606e9aff55SBiju Das
vc3_clk_mux_get_parent(struct clk_hw * hw)5616e9aff55SBiju Das static unsigned char vc3_clk_mux_get_parent(struct clk_hw *hw)
5626e9aff55SBiju Das {
5636e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
5646e9aff55SBiju Das const struct vc3_clk_data *clk_mux = vc3->data;
5656e9aff55SBiju Das u32 val;
5666e9aff55SBiju Das
5676e9aff55SBiju Das regmap_read(vc3->regmap, clk_mux->offs, &val);
5686e9aff55SBiju Das
5696e9aff55SBiju Das return !!(val & clk_mux->bitmsk);
5706e9aff55SBiju Das }
5716e9aff55SBiju Das
vc3_clk_mux_set_parent(struct clk_hw * hw,u8 index)5726e9aff55SBiju Das static int vc3_clk_mux_set_parent(struct clk_hw *hw, u8 index)
5736e9aff55SBiju Das {
5746e9aff55SBiju Das struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
5756e9aff55SBiju Das const struct vc3_clk_data *clk_mux = vc3->data;
5766e9aff55SBiju Das
5776e9aff55SBiju Das regmap_update_bits(vc3->regmap, clk_mux->offs,
5786e9aff55SBiju Das clk_mux->bitmsk, index ? clk_mux->bitmsk : 0);
5796e9aff55SBiju Das return 0;
5806e9aff55SBiju Das }
5816e9aff55SBiju Das
5826e9aff55SBiju Das static const struct clk_ops vc3_clk_mux_ops = {
5836e9aff55SBiju Das .determine_rate = vc3_clk_mux_determine_rate,
5846e9aff55SBiju Das .set_parent = vc3_clk_mux_set_parent,
5856e9aff55SBiju Das .get_parent = vc3_clk_mux_get_parent,
5866e9aff55SBiju Das };
5876e9aff55SBiju Das
vc3_regmap_is_writeable(struct device * dev,unsigned int reg)5886e9aff55SBiju Das static bool vc3_regmap_is_writeable(struct device *dev, unsigned int reg)
5896e9aff55SBiju Das {
5906e9aff55SBiju Das return true;
5916e9aff55SBiju Das }
5926e9aff55SBiju Das
5936e9aff55SBiju Das static const struct regmap_config vc3_regmap_config = {
5946e9aff55SBiju Das .reg_bits = 8,
5956e9aff55SBiju Das .val_bits = 8,
5966e9aff55SBiju Das .cache_type = REGCACHE_RBTREE,
5976e9aff55SBiju Das .max_register = 0x24,
5986e9aff55SBiju Das .writeable_reg = vc3_regmap_is_writeable,
5996e9aff55SBiju Das };
6006e9aff55SBiju Das
6016e9aff55SBiju Das static struct vc3_hw_data clk_div[5];
6026e9aff55SBiju Das
6036e9aff55SBiju Das static const struct clk_parent_data pfd_mux_parent_data[] = {
6046e9aff55SBiju Das { .index = 0, },
6056e9aff55SBiju Das { .hw = &clk_div[VC3_DIV2].hw }
6066e9aff55SBiju Das };
6076e9aff55SBiju Das
6086e9aff55SBiju Das static struct vc3_hw_data clk_pfd_mux[] = {
6096e9aff55SBiju Das [VC3_PFD2_MUX] = {
6106e9aff55SBiju Das .data = &(struct vc3_clk_data) {
6116e9aff55SBiju Das .offs = VC3_PLL_OP_CTRL,
6126e9aff55SBiju Das .bitmsk = BIT(VC3_PLL_OP_CTRL_PLL2_REFIN_SEL)
6136e9aff55SBiju Das },
6146e9aff55SBiju Das .hw.init = &(struct clk_init_data){
6156e9aff55SBiju Das .name = "pfd2_mux",
6166e9aff55SBiju Das .ops = &vc3_pfd_mux_ops,
6176e9aff55SBiju Das .parent_data = pfd_mux_parent_data,
6186e9aff55SBiju Das .num_parents = 2,
6196e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
6206e9aff55SBiju Das }
6216e9aff55SBiju Das },
6226e9aff55SBiju Das [VC3_PFD3_MUX] = {
6236e9aff55SBiju Das .data = &(struct vc3_clk_data) {
6246e9aff55SBiju Das .offs = VC3_GENERAL_CTR,
6256e9aff55SBiju Das .bitmsk = BIT(VC3_GENERAL_CTR_PLL3_REFIN_SEL)
6266e9aff55SBiju Das },
6276e9aff55SBiju Das .hw.init = &(struct clk_init_data){
6286e9aff55SBiju Das .name = "pfd3_mux",
6296e9aff55SBiju Das .ops = &vc3_pfd_mux_ops,
6306e9aff55SBiju Das .parent_data = pfd_mux_parent_data,
6316e9aff55SBiju Das .num_parents = 2,
6326e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
6336e9aff55SBiju Das }
6346e9aff55SBiju Das }
6356e9aff55SBiju Das };
6366e9aff55SBiju Das
6376e9aff55SBiju Das static struct vc3_hw_data clk_pfd[] = {
6386e9aff55SBiju Das [VC3_PFD1] = {
6396e9aff55SBiju Das .data = &(struct vc3_pfd_data) {
6406e9aff55SBiju Das .num = VC3_PFD1,
6416e9aff55SBiju Das .offs = VC3_PLL1_M_DIVIDER,
6426e9aff55SBiju Das .mdiv1_bitmsk = VC3_PLL1_M_DIV1,
6436e9aff55SBiju Das .mdiv2_bitmsk = VC3_PLL1_M_DIV2
6446e9aff55SBiju Das },
6456e9aff55SBiju Das .hw.init = &(struct clk_init_data){
6466e9aff55SBiju Das .name = "pfd1",
6476e9aff55SBiju Das .ops = &vc3_pfd_ops,
6486e9aff55SBiju Das .parent_data = &(const struct clk_parent_data) {
6496e9aff55SBiju Das .index = 0
6506e9aff55SBiju Das },
6516e9aff55SBiju Das .num_parents = 1,
6526e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
6536e9aff55SBiju Das }
6546e9aff55SBiju Das },
6556e9aff55SBiju Das [VC3_PFD2] = {
6566e9aff55SBiju Das .data = &(struct vc3_pfd_data) {
6576e9aff55SBiju Das .num = VC3_PFD2,
6586e9aff55SBiju Das .offs = VC3_PLL2_M_DIVIDER,
6596e9aff55SBiju Das .mdiv1_bitmsk = VC3_PLL2_M_DIV1,
6606e9aff55SBiju Das .mdiv2_bitmsk = VC3_PLL2_M_DIV2
6616e9aff55SBiju Das },
6626e9aff55SBiju Das .hw.init = &(struct clk_init_data){
6636e9aff55SBiju Das .name = "pfd2",
6646e9aff55SBiju Das .ops = &vc3_pfd_ops,
6656e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
6666e9aff55SBiju Das &clk_pfd_mux[VC3_PFD2_MUX].hw
6676e9aff55SBiju Das },
6686e9aff55SBiju Das .num_parents = 1,
6696e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
6706e9aff55SBiju Das }
6716e9aff55SBiju Das },
6726e9aff55SBiju Das [VC3_PFD3] = {
6736e9aff55SBiju Das .data = &(struct vc3_pfd_data) {
6746e9aff55SBiju Das .num = VC3_PFD3,
6756e9aff55SBiju Das .offs = VC3_PLL3_M_DIVIDER,
6766e9aff55SBiju Das .mdiv1_bitmsk = VC3_PLL3_M_DIV1,
6776e9aff55SBiju Das .mdiv2_bitmsk = VC3_PLL3_M_DIV2
6786e9aff55SBiju Das },
6796e9aff55SBiju Das .hw.init = &(struct clk_init_data){
6806e9aff55SBiju Das .name = "pfd3",
6816e9aff55SBiju Das .ops = &vc3_pfd_ops,
6826e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
6836e9aff55SBiju Das &clk_pfd_mux[VC3_PFD3_MUX].hw
6846e9aff55SBiju Das },
6856e9aff55SBiju Das .num_parents = 1,
6866e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
6876e9aff55SBiju Das }
6886e9aff55SBiju Das }
6896e9aff55SBiju Das };
6906e9aff55SBiju Das
6916e9aff55SBiju Das static struct vc3_hw_data clk_pll[] = {
6926e9aff55SBiju Das [VC3_PLL1] = {
6936e9aff55SBiju Das .data = &(struct vc3_pll_data) {
6946e9aff55SBiju Das .num = VC3_PLL1,
6956e9aff55SBiju Das .int_div_msb_offs = VC3_PLL1_LOOP_FILTER_N_DIV_MSB,
6966e9aff55SBiju Das .int_div_lsb_offs = VC3_PLL1_VCO_N_DIVIDER,
6976e9aff55SBiju Das .vco_min = VC3_PLL1_VCO_MIN,
6986e9aff55SBiju Das .vco_max = VC3_PLL1_VCO_MAX
6996e9aff55SBiju Das },
7006e9aff55SBiju Das .hw.init = &(struct clk_init_data){
7016e9aff55SBiju Das .name = "pll1",
7026e9aff55SBiju Das .ops = &vc3_pll_ops,
7036e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
7046e9aff55SBiju Das &clk_pfd[VC3_PFD1].hw
7056e9aff55SBiju Das },
7066e9aff55SBiju Das .num_parents = 1,
7076e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
7086e9aff55SBiju Das }
7096e9aff55SBiju Das },
7106e9aff55SBiju Das [VC3_PLL2] = {
7116e9aff55SBiju Das .data = &(struct vc3_pll_data) {
7126e9aff55SBiju Das .num = VC3_PLL2,
7136e9aff55SBiju Das .int_div_msb_offs = VC3_PLL2_FB_INT_DIV_MSB,
7146e9aff55SBiju Das .int_div_lsb_offs = VC3_PLL2_FB_INT_DIV_LSB,
7156e9aff55SBiju Das .vco_min = VC3_PLL2_VCO_MIN,
7166e9aff55SBiju Das .vco_max = VC3_PLL2_VCO_MAX
7176e9aff55SBiju Das },
7186e9aff55SBiju Das .hw.init = &(struct clk_init_data){
7196e9aff55SBiju Das .name = "pll2",
7206e9aff55SBiju Das .ops = &vc3_pll_ops,
7216e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
7226e9aff55SBiju Das &clk_pfd[VC3_PFD2].hw
7236e9aff55SBiju Das },
7246e9aff55SBiju Das .num_parents = 1,
7256e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
7266e9aff55SBiju Das }
7276e9aff55SBiju Das },
7286e9aff55SBiju Das [VC3_PLL3] = {
7296e9aff55SBiju Das .data = &(struct vc3_pll_data) {
7306e9aff55SBiju Das .num = VC3_PLL3,
7316e9aff55SBiju Das .int_div_msb_offs = VC3_PLL3_LOOP_FILTER_N_DIV_MSB,
7326e9aff55SBiju Das .int_div_lsb_offs = VC3_PLL3_N_DIVIDER,
7336e9aff55SBiju Das .vco_min = VC3_PLL3_VCO_MIN,
7346e9aff55SBiju Das .vco_max = VC3_PLL3_VCO_MAX
7356e9aff55SBiju Das },
7366e9aff55SBiju Das .hw.init = &(struct clk_init_data){
7376e9aff55SBiju Das .name = "pll3",
7386e9aff55SBiju Das .ops = &vc3_pll_ops,
7396e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
7406e9aff55SBiju Das &clk_pfd[VC3_PFD3].hw
7416e9aff55SBiju Das },
7426e9aff55SBiju Das .num_parents = 1,
7436e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
7446e9aff55SBiju Das }
7456e9aff55SBiju Das }
7466e9aff55SBiju Das };
7476e9aff55SBiju Das
7486e9aff55SBiju Das static const struct clk_parent_data div_mux_parent_data[][2] = {
7496e9aff55SBiju Das [VC3_DIV1_MUX] = {
7506e9aff55SBiju Das { .hw = &clk_pll[VC3_PLL1].hw },
7516e9aff55SBiju Das { .index = 0 }
7526e9aff55SBiju Das },
7536e9aff55SBiju Das [VC3_DIV3_MUX] = {
7546e9aff55SBiju Das { .hw = &clk_pll[VC3_PLL2].hw },
7556e9aff55SBiju Das { .hw = &clk_pll[VC3_PLL3].hw }
7566e9aff55SBiju Das },
7576e9aff55SBiju Das [VC3_DIV4_MUX] = {
7586e9aff55SBiju Das { .hw = &clk_pll[VC3_PLL2].hw },
7596e9aff55SBiju Das { .index = 0 }
7606e9aff55SBiju Das }
7616e9aff55SBiju Das };
7626e9aff55SBiju Das
7636e9aff55SBiju Das static struct vc3_hw_data clk_div_mux[] = {
7646e9aff55SBiju Das [VC3_DIV1_MUX] = {
7656e9aff55SBiju Das .data = &(struct vc3_clk_data) {
7666e9aff55SBiju Das .offs = VC3_GENERAL_CTR,
7676e9aff55SBiju Das .bitmsk = VC3_GENERAL_CTR_DIV1_SRC_SEL
7686e9aff55SBiju Das },
7696e9aff55SBiju Das .hw.init = &(struct clk_init_data){
7706e9aff55SBiju Das .name = "div1_mux",
7716e9aff55SBiju Das .ops = &vc3_div_mux_ops,
7726e9aff55SBiju Das .parent_data = div_mux_parent_data[VC3_DIV1_MUX],
7736e9aff55SBiju Das .num_parents = 2,
7746e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
7756e9aff55SBiju Das }
7766e9aff55SBiju Das },
7776e9aff55SBiju Das [VC3_DIV3_MUX] = {
7786e9aff55SBiju Das .data = &(struct vc3_clk_data) {
7796e9aff55SBiju Das .offs = VC3_PLL3_CHARGE_PUMP_CTRL,
7806e9aff55SBiju Das .bitmsk = VC3_PLL3_CHARGE_PUMP_CTRL_OUTDIV3_SRC_SEL
7816e9aff55SBiju Das },
7826e9aff55SBiju Das .hw.init = &(struct clk_init_data){
7836e9aff55SBiju Das .name = "div3_mux",
7846e9aff55SBiju Das .ops = &vc3_div_mux_ops,
7856e9aff55SBiju Das .parent_data = div_mux_parent_data[VC3_DIV3_MUX],
7866e9aff55SBiju Das .num_parents = 2,
7876e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
7886e9aff55SBiju Das }
7896e9aff55SBiju Das },
7906e9aff55SBiju Das [VC3_DIV4_MUX] = {
7916e9aff55SBiju Das .data = &(struct vc3_clk_data) {
7926e9aff55SBiju Das .offs = VC3_OUTPUT_CTR,
7936e9aff55SBiju Das .bitmsk = VC3_OUTPUT_CTR_DIV4_SRC_SEL
7946e9aff55SBiju Das },
7956e9aff55SBiju Das .hw.init = &(struct clk_init_data){
7966e9aff55SBiju Das .name = "div4_mux",
7976e9aff55SBiju Das .ops = &vc3_div_mux_ops,
7986e9aff55SBiju Das .parent_data = div_mux_parent_data[VC3_DIV4_MUX],
7996e9aff55SBiju Das .num_parents = 2,
8006e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
8016e9aff55SBiju Das }
8026e9aff55SBiju Das }
8036e9aff55SBiju Das };
8046e9aff55SBiju Das
8056e9aff55SBiju Das static struct vc3_hw_data clk_div[] = {
8066e9aff55SBiju Das [VC3_DIV1] = {
8076e9aff55SBiju Das .data = &(struct vc3_div_data) {
8086e9aff55SBiju Das .offs = VC3_OUT_DIV1_DIV2_CTRL,
8096e9aff55SBiju Das .table = div1_divs,
8106e9aff55SBiju Das .shift = 4,
8116e9aff55SBiju Das .width = 4,
8126e9aff55SBiju Das .flags = CLK_DIVIDER_READ_ONLY
8136e9aff55SBiju Das },
8146e9aff55SBiju Das .hw.init = &(struct clk_init_data){
8156e9aff55SBiju Das .name = "div1",
8166e9aff55SBiju Das .ops = &vc3_div_ops,
8176e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
8186e9aff55SBiju Das &clk_div_mux[VC3_DIV1_MUX].hw
8196e9aff55SBiju Das },
8206e9aff55SBiju Das .num_parents = 1,
8216e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
8226e9aff55SBiju Das }
8236e9aff55SBiju Das },
8246e9aff55SBiju Das [VC3_DIV2] = {
8256e9aff55SBiju Das .data = &(struct vc3_div_data) {
8266e9aff55SBiju Das .offs = VC3_OUT_DIV1_DIV2_CTRL,
8276e9aff55SBiju Das .table = div245_divs,
8286e9aff55SBiju Das .shift = 0,
8296e9aff55SBiju Das .width = 4,
8306e9aff55SBiju Das .flags = CLK_DIVIDER_READ_ONLY
8316e9aff55SBiju Das },
8326e9aff55SBiju Das .hw.init = &(struct clk_init_data){
8336e9aff55SBiju Das .name = "div2",
8346e9aff55SBiju Das .ops = &vc3_div_ops,
8356e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
8366e9aff55SBiju Das &clk_pll[VC3_PLL1].hw
8376e9aff55SBiju Das },
8386e9aff55SBiju Das .num_parents = 1,
8396e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
8406e9aff55SBiju Das }
8416e9aff55SBiju Das },
8426e9aff55SBiju Das [VC3_DIV3] = {
8436e9aff55SBiju Das .data = &(struct vc3_div_data) {
8446e9aff55SBiju Das .offs = VC3_OUT_DIV3_DIV4_CTRL,
8456e9aff55SBiju Das .table = div3_divs,
8466e9aff55SBiju Das .shift = 4,
8476e9aff55SBiju Das .width = 4,
8486e9aff55SBiju Das .flags = CLK_DIVIDER_READ_ONLY
8496e9aff55SBiju Das },
8506e9aff55SBiju Das .hw.init = &(struct clk_init_data){
8516e9aff55SBiju Das .name = "div3",
8526e9aff55SBiju Das .ops = &vc3_div_ops,
8536e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
8546e9aff55SBiju Das &clk_div_mux[VC3_DIV3_MUX].hw
8556e9aff55SBiju Das },
8566e9aff55SBiju Das .num_parents = 1,
8576e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
8586e9aff55SBiju Das }
8596e9aff55SBiju Das },
8606e9aff55SBiju Das [VC3_DIV4] = {
8616e9aff55SBiju Das .data = &(struct vc3_div_data) {
8626e9aff55SBiju Das .offs = VC3_OUT_DIV3_DIV4_CTRL,
8636e9aff55SBiju Das .table = div245_divs,
8646e9aff55SBiju Das .shift = 0,
8656e9aff55SBiju Das .width = 4,
8666e9aff55SBiju Das .flags = CLK_DIVIDER_READ_ONLY
8676e9aff55SBiju Das },
8686e9aff55SBiju Das .hw.init = &(struct clk_init_data){
8696e9aff55SBiju Das .name = "div4",
8706e9aff55SBiju Das .ops = &vc3_div_ops,
8716e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
8726e9aff55SBiju Das &clk_div_mux[VC3_DIV4_MUX].hw
8736e9aff55SBiju Das },
8746e9aff55SBiju Das .num_parents = 1,
8756e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
8766e9aff55SBiju Das }
8776e9aff55SBiju Das },
8786e9aff55SBiju Das [VC3_DIV5] = {
8796e9aff55SBiju Das .data = &(struct vc3_div_data) {
8806e9aff55SBiju Das .offs = VC3_PLL1_CTRL_OUTDIV5,
8816e9aff55SBiju Das .table = div245_divs,
8826e9aff55SBiju Das .shift = 0,
8836e9aff55SBiju Das .width = 4,
8846e9aff55SBiju Das .flags = CLK_DIVIDER_READ_ONLY
8856e9aff55SBiju Das },
8866e9aff55SBiju Das .hw.init = &(struct clk_init_data){
8876e9aff55SBiju Das .name = "div5",
8886e9aff55SBiju Das .ops = &vc3_div_ops,
8896e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
8906e9aff55SBiju Das &clk_pll[VC3_PLL3].hw
8916e9aff55SBiju Das },
8926e9aff55SBiju Das .num_parents = 1,
8936e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
8946e9aff55SBiju Das }
8956e9aff55SBiju Das }
8966e9aff55SBiju Das };
8976e9aff55SBiju Das
8986e9aff55SBiju Das static struct vc3_hw_data clk_mux[] = {
8996dcf03bcSBiju Das [VC3_SE1_MUX] = {
9006e9aff55SBiju Das .data = &(struct vc3_clk_data) {
9016dcf03bcSBiju Das .offs = VC3_SE1_DIV4_CTRL,
9026dcf03bcSBiju Das .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL
9036e9aff55SBiju Das },
9046e9aff55SBiju Das .hw.init = &(struct clk_init_data){
9056dcf03bcSBiju Das .name = "se1_mux",
9066e9aff55SBiju Das .ops = &vc3_clk_mux_ops,
9076e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
9086dcf03bcSBiju Das &clk_div[VC3_DIV5].hw,
9096e9aff55SBiju Das &clk_div[VC3_DIV4].hw
9106e9aff55SBiju Das },
9116e9aff55SBiju Das .num_parents = 2,
9126e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
9136e9aff55SBiju Das }
9146e9aff55SBiju Das },
9156e9aff55SBiju Das [VC3_SE2_MUX] = {
9166e9aff55SBiju Das .data = &(struct vc3_clk_data) {
9176e9aff55SBiju Das .offs = VC3_SE2_CTRL_REG0,
9186e9aff55SBiju Das .bitmsk = VC3_SE2_CTRL_REG0_SE2_CLK_SEL
9196e9aff55SBiju Das },
9206e9aff55SBiju Das .hw.init = &(struct clk_init_data){
9216e9aff55SBiju Das .name = "se2_mux",
9226e9aff55SBiju Das .ops = &vc3_clk_mux_ops,
9236e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
9246e9aff55SBiju Das &clk_div[VC3_DIV5].hw,
9256e9aff55SBiju Das &clk_div[VC3_DIV4].hw
9266e9aff55SBiju Das },
9276e9aff55SBiju Das .num_parents = 2,
9286e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
9296e9aff55SBiju Das }
9306e9aff55SBiju Das },
9316dcf03bcSBiju Das [VC3_SE3_MUX] = {
9326e9aff55SBiju Das .data = &(struct vc3_clk_data) {
9336dcf03bcSBiju Das .offs = VC3_SE3_DIFF1_CTRL_REG,
9346dcf03bcSBiju Das .bitmsk = VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL
9356e9aff55SBiju Das },
9366e9aff55SBiju Das .hw.init = &(struct clk_init_data){
9376dcf03bcSBiju Das .name = "se3_mux",
9386e9aff55SBiju Das .ops = &vc3_clk_mux_ops,
9396e9aff55SBiju Das .parent_hws = (const struct clk_hw *[]) {
9406dcf03bcSBiju Das &clk_div[VC3_DIV2].hw,
9416e9aff55SBiju Das &clk_div[VC3_DIV4].hw
9426e9aff55SBiju Das },
9436e9aff55SBiju Das .num_parents = 2,
9446e9aff55SBiju Das .flags = CLK_SET_RATE_PARENT
9456e9aff55SBiju Das }
9466dcf03bcSBiju Das },
9476dcf03bcSBiju Das [VC3_DIFF1_MUX] = {
9486dcf03bcSBiju Das .data = &(struct vc3_clk_data) {
9496dcf03bcSBiju Das .offs = VC3_DIFF1_CTRL_REG,
9506dcf03bcSBiju Das .bitmsk = VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL
9516dcf03bcSBiju Das },
9526dcf03bcSBiju Das .hw.init = &(struct clk_init_data){
9536dcf03bcSBiju Das .name = "diff1_mux",
9546dcf03bcSBiju Das .ops = &vc3_clk_mux_ops,
9556dcf03bcSBiju Das .parent_hws = (const struct clk_hw *[]) {
9566dcf03bcSBiju Das &clk_div[VC3_DIV1].hw,
9576dcf03bcSBiju Das &clk_div[VC3_DIV3].hw
9586dcf03bcSBiju Das },
9596dcf03bcSBiju Das .num_parents = 2,
9606dcf03bcSBiju Das .flags = CLK_SET_RATE_PARENT
9616dcf03bcSBiju Das }
9626dcf03bcSBiju Das },
9636dcf03bcSBiju Das [VC3_DIFF2_MUX] = {
9646dcf03bcSBiju Das .data = &(struct vc3_clk_data) {
9656dcf03bcSBiju Das .offs = VC3_DIFF2_CTRL_REG,
9666dcf03bcSBiju Das .bitmsk = VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL
9676dcf03bcSBiju Das },
9686dcf03bcSBiju Das .hw.init = &(struct clk_init_data){
9696dcf03bcSBiju Das .name = "diff2_mux",
9706dcf03bcSBiju Das .ops = &vc3_clk_mux_ops,
9716dcf03bcSBiju Das .parent_hws = (const struct clk_hw *[]) {
9726dcf03bcSBiju Das &clk_div[VC3_DIV1].hw,
9736dcf03bcSBiju Das &clk_div[VC3_DIV3].hw
9746dcf03bcSBiju Das },
9756dcf03bcSBiju Das .num_parents = 2,
9766dcf03bcSBiju Das .flags = CLK_SET_RATE_PARENT
9776dcf03bcSBiju Das }
9786e9aff55SBiju Das }
9796e9aff55SBiju Das };
9806e9aff55SBiju Das
vc3_of_clk_get(struct of_phandle_args * clkspec,void * data)9816e9aff55SBiju Das static struct clk_hw *vc3_of_clk_get(struct of_phandle_args *clkspec,
9826e9aff55SBiju Das void *data)
9836e9aff55SBiju Das {
9846e9aff55SBiju Das unsigned int idx = clkspec->args[0];
9856e9aff55SBiju Das struct clk_hw **clkout_hw = data;
9866e9aff55SBiju Das
9876e9aff55SBiju Das if (idx >= ARRAY_SIZE(clk_out)) {
9886e9aff55SBiju Das pr_err("invalid clk index %u for provider %pOF\n", idx, clkspec->np);
9896e9aff55SBiju Das return ERR_PTR(-EINVAL);
9906e9aff55SBiju Das }
9916e9aff55SBiju Das
9926e9aff55SBiju Das return clkout_hw[idx];
9936e9aff55SBiju Das }
9946e9aff55SBiju Das
vc3_probe(struct i2c_client * client)9956e9aff55SBiju Das static int vc3_probe(struct i2c_client *client)
9966e9aff55SBiju Das {
9976e9aff55SBiju Das struct device *dev = &client->dev;
9986e9aff55SBiju Das u8 settings[NUM_CONFIG_REGISTERS];
9996e9aff55SBiju Das struct regmap *regmap;
10006e9aff55SBiju Das const char *name;
10016e9aff55SBiju Das int ret, i;
10026e9aff55SBiju Das
10036e9aff55SBiju Das regmap = devm_regmap_init_i2c(client, &vc3_regmap_config);
10046e9aff55SBiju Das if (IS_ERR(regmap))
10056e9aff55SBiju Das return dev_err_probe(dev, PTR_ERR(regmap),
10066e9aff55SBiju Das "failed to allocate register map\n");
10076e9aff55SBiju Das
10086e9aff55SBiju Das ret = of_property_read_u8_array(dev->of_node, "renesas,settings",
10096e9aff55SBiju Das settings, ARRAY_SIZE(settings));
10106e9aff55SBiju Das if (!ret) {
10116e9aff55SBiju Das /*
10126e9aff55SBiju Das * A raw settings array was specified in the DT. Write the
10136e9aff55SBiju Das * settings to the device immediately.
10146e9aff55SBiju Das */
10156e9aff55SBiju Das for (i = 0; i < NUM_CONFIG_REGISTERS; i++) {
10166e9aff55SBiju Das ret = regmap_write(regmap, i, settings[i]);
10176e9aff55SBiju Das if (ret) {
10186e9aff55SBiju Das dev_err(dev, "error writing to chip (%i)\n", ret);
10196e9aff55SBiju Das return ret;
10206e9aff55SBiju Das }
10216e9aff55SBiju Das }
10226e9aff55SBiju Das } else if (ret == -EOVERFLOW) {
10236e9aff55SBiju Das dev_err(&client->dev, "EOVERFLOW reg settings. ARRAY_SIZE: %zu\n",
10246e9aff55SBiju Das ARRAY_SIZE(settings));
10256e9aff55SBiju Das return ret;
10266e9aff55SBiju Das }
10276e9aff55SBiju Das
10286e9aff55SBiju Das /* Register pfd muxes */
10296e9aff55SBiju Das for (i = 0; i < ARRAY_SIZE(clk_pfd_mux); i++) {
10306e9aff55SBiju Das clk_pfd_mux[i].regmap = regmap;
10316e9aff55SBiju Das ret = devm_clk_hw_register(dev, &clk_pfd_mux[i].hw);
10326e9aff55SBiju Das if (ret)
10336e9aff55SBiju Das return dev_err_probe(dev, ret, "%s failed\n",
10346e9aff55SBiju Das clk_pfd_mux[i].hw.init->name);
10356e9aff55SBiju Das }
10366e9aff55SBiju Das
10376e9aff55SBiju Das /* Register pfd's */
10386e9aff55SBiju Das for (i = 0; i < ARRAY_SIZE(clk_pfd); i++) {
10396e9aff55SBiju Das clk_pfd[i].regmap = regmap;
10406e9aff55SBiju Das ret = devm_clk_hw_register(dev, &clk_pfd[i].hw);
10416e9aff55SBiju Das if (ret)
10426e9aff55SBiju Das return dev_err_probe(dev, ret, "%s failed\n",
10436e9aff55SBiju Das clk_pfd[i].hw.init->name);
10446e9aff55SBiju Das }
10456e9aff55SBiju Das
10466e9aff55SBiju Das /* Register pll's */
10476e9aff55SBiju Das for (i = 0; i < ARRAY_SIZE(clk_pll); i++) {
10486e9aff55SBiju Das clk_pll[i].regmap = regmap;
10496e9aff55SBiju Das ret = devm_clk_hw_register(dev, &clk_pll[i].hw);
10506e9aff55SBiju Das if (ret)
10516e9aff55SBiju Das return dev_err_probe(dev, ret, "%s failed\n",
10526e9aff55SBiju Das clk_pll[i].hw.init->name);
10536e9aff55SBiju Das }
10546e9aff55SBiju Das
10556e9aff55SBiju Das /* Register divider muxes */
10566e9aff55SBiju Das for (i = 0; i < ARRAY_SIZE(clk_div_mux); i++) {
10576e9aff55SBiju Das clk_div_mux[i].regmap = regmap;
10586e9aff55SBiju Das ret = devm_clk_hw_register(dev, &clk_div_mux[i].hw);
10596e9aff55SBiju Das if (ret)
10606e9aff55SBiju Das return dev_err_probe(dev, ret, "%s failed\n",
10616e9aff55SBiju Das clk_div_mux[i].hw.init->name);
10626e9aff55SBiju Das }
10636e9aff55SBiju Das
10646e9aff55SBiju Das /* Register dividers */
10656e9aff55SBiju Das for (i = 0; i < ARRAY_SIZE(clk_div); i++) {
10666e9aff55SBiju Das clk_div[i].regmap = regmap;
10676e9aff55SBiju Das ret = devm_clk_hw_register(dev, &clk_div[i].hw);
10686e9aff55SBiju Das if (ret)
10696e9aff55SBiju Das return dev_err_probe(dev, ret, "%s failed\n",
10706e9aff55SBiju Das clk_div[i].hw.init->name);
10716e9aff55SBiju Das }
10726e9aff55SBiju Das
10736e9aff55SBiju Das /* Register clk muxes */
10746e9aff55SBiju Das for (i = 0; i < ARRAY_SIZE(clk_mux); i++) {
10756e9aff55SBiju Das clk_mux[i].regmap = regmap;
10766e9aff55SBiju Das ret = devm_clk_hw_register(dev, &clk_mux[i].hw);
10776e9aff55SBiju Das if (ret)
10786e9aff55SBiju Das return dev_err_probe(dev, ret, "%s failed\n",
10796e9aff55SBiju Das clk_mux[i].hw.init->name);
10806e9aff55SBiju Das }
10816e9aff55SBiju Das
10826e9aff55SBiju Das /* Register clk outputs */
10836e9aff55SBiju Das for (i = 0; i < ARRAY_SIZE(clk_out); i++) {
10846e9aff55SBiju Das switch (i) {
10856e9aff55SBiju Das case VC3_DIFF2:
10866e9aff55SBiju Das name = "diff2";
10876e9aff55SBiju Das break;
10886e9aff55SBiju Das case VC3_DIFF1:
10896e9aff55SBiju Das name = "diff1";
10906e9aff55SBiju Das break;
10916e9aff55SBiju Das case VC3_SE3:
10926e9aff55SBiju Das name = "se3";
10936e9aff55SBiju Das break;
10946e9aff55SBiju Das case VC3_SE2:
10956e9aff55SBiju Das name = "se2";
10966e9aff55SBiju Das break;
10976e9aff55SBiju Das case VC3_SE1:
10986e9aff55SBiju Das name = "se1";
10996e9aff55SBiju Das break;
11006e9aff55SBiju Das case VC3_REF:
11016e9aff55SBiju Das name = "ref";
11026e9aff55SBiju Das break;
11036e9aff55SBiju Das default:
11046e9aff55SBiju Das return dev_err_probe(dev, -EINVAL, "invalid clk output %d\n", i);
11056e9aff55SBiju Das }
11066e9aff55SBiju Das
11076e9aff55SBiju Das if (i == VC3_REF)
11086e9aff55SBiju Das clk_out[i] = devm_clk_hw_register_fixed_factor_index(dev,
11096e9aff55SBiju Das name, 0, CLK_SET_RATE_PARENT, 1, 1);
11106e9aff55SBiju Das else
11116e9aff55SBiju Das clk_out[i] = devm_clk_hw_register_fixed_factor_parent_hw(dev,
11126dcf03bcSBiju Das name, &clk_mux[i - 1].hw, CLK_SET_RATE_PARENT, 1, 1);
11136e9aff55SBiju Das
11146e9aff55SBiju Das if (IS_ERR(clk_out[i]))
11156e9aff55SBiju Das return PTR_ERR(clk_out[i]);
11166e9aff55SBiju Das }
11176e9aff55SBiju Das
11186e9aff55SBiju Das ret = devm_of_clk_add_hw_provider(dev, vc3_of_clk_get, clk_out);
11196e9aff55SBiju Das if (ret)
11206e9aff55SBiju Das return dev_err_probe(dev, ret, "unable to add clk provider\n");
11216e9aff55SBiju Das
11226e9aff55SBiju Das return ret;
11236e9aff55SBiju Das }
11246e9aff55SBiju Das
11256e9aff55SBiju Das static const struct of_device_id dev_ids[] = {
11266e9aff55SBiju Das { .compatible = "renesas,5p35023" },
11276e9aff55SBiju Das { /* Sentinel */ }
11286e9aff55SBiju Das };
11296e9aff55SBiju Das MODULE_DEVICE_TABLE(of, dev_ids);
11306e9aff55SBiju Das
11316e9aff55SBiju Das static struct i2c_driver vc3_driver = {
11326e9aff55SBiju Das .driver = {
11336e9aff55SBiju Das .name = "vc3",
11346e9aff55SBiju Das .of_match_table = of_match_ptr(dev_ids),
11356e9aff55SBiju Das },
1136a53ef055SUwe Kleine-König .probe = vc3_probe,
11376e9aff55SBiju Das };
11386e9aff55SBiju Das module_i2c_driver(vc3_driver);
11396e9aff55SBiju Das
11406e9aff55SBiju Das MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>");
11416e9aff55SBiju Das MODULE_DESCRIPTION("Renesas VersaClock 3 driver");
11426e9aff55SBiju Das MODULE_LICENSE("GPL");
1143