diff for duplicates of <20150603222504.6017.28097@quantum> diff --git a/a/1.txt b/N1/1.txt index edd1e92..9a378fe 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -8,9 +8,8 @@ Quoting Mike Looijmans (2015-06-02 22:25:19) > Y4 and Y5 derive from PLL2 > Given a target output frequency, the driver will set the PLL and > divider to best approximate the desired output. -> = - -> Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl> +> +> Signed-off-by: Mike Looijmans <mike.looijmans-Oq418RWZeHk@public.gmane.org> Thanks for fixing it up. Applied to clk-next towards 4.2. @@ -22,22 +21,17 @@ Mike > Add devicetree binding documentation > v3: Remove clk-private.h and processed M.Turquette's feedback > Use "ti" prefix. Use of_clk_src_onecell_get to register. -> v4: Fix dev_dbg format warning on 64-bit systems (as suggested by Paul Bo= -lle) -> = - +> v4: Fix dev_dbg format warning on 64-bit systems (as suggested by Paul Bolle) +> > .../devicetree/bindings/clock/ti,cdce925.txt | 42 ++ > drivers/clk/Kconfig | 17 + > drivers/clk/Makefile | 1 + -> drivers/clk/clk-cdce925.c | 749 +++++++++++++++= -++++++ +> drivers/clk/clk-cdce925.c | 749 +++++++++++++++++++++ > 4 files changed, 809 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/ti,cdce925.txt > create mode 100644 drivers/clk/clk-cdce925.c -> = - -> diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Doc= -umentation/devicetree/bindings/clock/ti,cdce925.txt +> +> diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Documentation/devicetree/bindings/clock/ti,cdce925.txt > new file mode 100644 > index 0000000..4c7669a > --- /dev/null @@ -56,37 +50,32 @@ umentation/devicetree/bindings/clock/ti,cdce925.txt > +Required properties: > + - compatible: Shall be "ti,cdce925" > + - reg: I2C device address. -> + - clocks: Points to a fixed parent clock that provides the input freque= -ncy. +> + - clocks: Points to a fixed parent clock that provides the input frequency. > + - #clock-cells: From common clock bindings: Shall be 1. > + > +Optional properties: -> + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance o= -n a +> + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a > + board, or to compensate for external influences. > + -> +For both PLL1 and PLL2 an optional child node can be used to specify spr= -ead +> +For both PLL1 and PLL2 an optional child node can be used to specify spread > +spectrum clocking parameters for a board. > + - spread-spectrum: SSC mode as defined in the data sheet. -> + - spread-spectrum-center: Use "centered" mode instead of "max" mode. W= -hen -> + present, the clock runs at the requested frequency on average. Other= -wise +> + - spread-spectrum-center: Use "centered" mode instead of "max" mode. When +> + present, the clock runs at the requested frequency on average. Otherwise > + the requested frequency is the maximum value of the SCC range. > + > + > +Example: > + > + clockgen: cdce925pw@64 { -> + compatible =3D "cdce925"; -> + reg =3D <0x64>; -> + clocks =3D <&xtal_27Mhz>; -> + #clock-cells =3D <1>; -> + xtal-load-pf =3D <5>; +> + compatible = "cdce925"; +> + reg = <0x64>; +> + clocks = <&xtal_27Mhz>; +> + #clock-cells = <1>; +> + xtal-load-pf = <5>; > + /* PLL options to get SSC 1% centered */ > + PLL2 { -> + spread-spectrum =3D <4>; +> + spread-spectrum = <4>; > + spread-spectrum-center; > + }; > + }; @@ -97,8 +86,7 @@ wise > @@ -78,6 +78,23 @@ config COMMON_CLK_SI570 > This driver supports Silicon Labs 570/571/598/599 programmable > clock generators. -> = - +> > +config COMMON_CLK_CDCE925 > + tristate "Clock driver for TI CDCE925 devices" > + depends on I2C @@ -106,12 +94,9 @@ wise > + select REGMAP_I2C > + help > + ---help--- -> + This driver supports the TI CDCE925 programmable clock synthesi= -zer. -> + The chip contains two PLLs with spread-spectrum clocking suppor= -t and -> + five output dividers. The driver only supports the following se= -tup, +> + This driver supports the TI CDCE925 programmable clock synthesizer. +> + The chip contains two PLLs with spread-spectrum clocking support and +> + five output dividers. The driver only supports the following setup, > + and uses a fixed setting for the output muxes. > + Y1 is derived from the input clock > + Y2 and Y3 derive from PLL1 @@ -126,15 +111,14 @@ tup, > index 3d00c25..49d38de 100644 > --- a/drivers/clk/Makefile > +++ b/drivers/clk/Makefile -> @@ -38,6 +38,7 @@ obj-$(CONFIG_COMMON_CLK_RK808) +=3D clk-= -rk808.o -> obj-$(CONFIG_COMMON_CLK_S2MPS11) +=3D clk-s2mps11.o -> obj-$(CONFIG_COMMON_CLK_SI5351) +=3D clk-si5351.o -> obj-$(CONFIG_COMMON_CLK_SI570) +=3D clk-si570.o -> +obj-$(CONFIG_COMMON_CLK_CDCE925) +=3D clk-cdce925.o -> obj-$(CONFIG_CLK_TWL6040) +=3D clk-twl6040.o -> obj-$(CONFIG_ARCH_U300) +=3D clk-u300.o -> obj-$(CONFIG_ARCH_VT8500) +=3D clk-vt8500.o +> @@ -38,6 +38,7 @@ obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o +> obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o +> obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o +> obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o +> +obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o +> obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o +> obj-$(CONFIG_ARCH_U300) += clk-u300.o +> obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o > diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c > new file mode 100644 > index 0000000..56b870d @@ -197,8 +181,7 @@ rk808.o > + u16 m; /* 1..511 */ > + u16 n; /* 1..4095 */ > +}; -> +#define to_clk_cdce925_pll(_hw) container_of(_hw, struct clk_cdce= -925_pll, hw) +> +#define to_clk_cdce925_pll(_hw) container_of(_hw, struct clk_cdce925_pll, hw) > + > +struct clk_cdce925_chip { > + struct regmap *regmap; @@ -211,21 +194,19 @@ rk808.o > + > +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ > + -> +static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rat= -e, +> +static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rate, > + u16 n, u16 m) > +{ -> + if ((!m || !n) || (m =3D=3D n)) -> + return parent_rate; /* In bypass mode runs at same freque= -ncy */ +> + if ((!m || !n) || (m == n)) +> + return parent_rate; /* In bypass mode runs at same frequency */ > + return mult_frac(parent_rate, (unsigned long)n, (unsigned long)m); > +} > + > +static unsigned long cdce925_pll_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ -> + /* Output frequency of PLL is Fout =3D (Fin/Pdiv)*(N/M) */ -> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw); +> + /* Output frequency of PLL is Fout = (Fin/Pdiv)*(N/M) */ +> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw); > + > + return cdce925_pll_calculate_rate(parent_rate, data->n, data->m); > +} @@ -237,34 +218,33 @@ ncy */ > + unsigned long um; > + unsigned long g; > + -> + if (rate <=3D parent_rate) { +> + if (rate <= parent_rate) { > + /* Can always deliver parent_rate in bypass mode */ -> + rate =3D parent_rate; -> + *n =3D 0; -> + *m =3D 0; +> + rate = parent_rate; +> + *n = 0; +> + *m = 0; > + } else { > + /* In PLL mode, need to apply min/max range */ > + if (rate < CDCE925_PLL_FREQUENCY_MIN) -> + rate =3D CDCE925_PLL_FREQUENCY_MIN; +> + rate = CDCE925_PLL_FREQUENCY_MIN; > + else if (rate > CDCE925_PLL_FREQUENCY_MAX) -> + rate =3D CDCE925_PLL_FREQUENCY_MAX; +> + rate = CDCE925_PLL_FREQUENCY_MAX; > + -> + g =3D gcd(rate, parent_rate); -> + um =3D parent_rate / g; -> + un =3D rate / g; -> + /* When outside hw range, reduce to fit (rounding errors)= - */ +> + g = gcd(rate, parent_rate); +> + um = parent_rate / g; +> + un = rate / g; +> + /* When outside hw range, reduce to fit (rounding errors) */ > + while ((un > 4095) || (um > 511)) { -> + un >>=3D 1; -> + um >>=3D 1; +> + un >>= 1; +> + um >>= 1; > + } -> + if (un =3D=3D 0) -> + un =3D 1; -> + if (um =3D=3D 0) -> + um =3D 1; +> + if (un == 0) +> + un = 1; +> + if (um == 0) +> + um = 1; > + -> + *n =3D un; -> + *m =3D um; +> + *n = un; +> + *m = um; > + } > +} > + @@ -280,24 +260,22 @@ ncy */ > +static int cdce925_pll_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ -> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw); +> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw); > + -> + if (!rate || (rate =3D=3D parent_rate)) { -> + data->m =3D 0; /* Bypass mode */ -> + data->n =3D 0; +> + if (!rate || (rate == parent_rate)) { +> + data->m = 0; /* Bypass mode */ +> + data->n = 0; > + return 0; > + } > + > + if ((rate < CDCE925_PLL_FREQUENCY_MIN) || > + (rate > CDCE925_PLL_FREQUENCY_MAX)) { -> + pr_debug("%s: rate %lu outside PLL range.\n", __func__, r= -ate); +> + pr_debug("%s: rate %lu outside PLL range.\n", __func__, rate); > + return -EINVAL; > + } > + > + if (rate < parent_rate) { -> + pr_debug("%s: rate %lu less than parent rate %lu.\n", __f= -unc__, +> + pr_debug("%s: rate %lu less than parent rate %lu.\n", __func__, > + rate, parent_rate); > + return -EINVAL; > + } @@ -307,17 +285,17 @@ unc__, > +} > + > + -> +/* calculate p =3D max(0, 4 - int(log2 (n/m))) */ +> +/* calculate p = max(0, 4 - int(log2 (n/m))) */ > +static u8 cdce925_pll_calc_p(u16 n, u16 m) > +{ > + u8 p; -> + u16 r =3D n / m; +> + u16 r = n / m; > + -> + if (r >=3D 16) +> + if (r >= 16) > + return 0; -> + p =3D 4; +> + p = 4; > + while (r > 1) { -> + r >>=3D 1; +> + r >>= 1; > + --p; > + } > + return p; @@ -326,15 +304,15 @@ unc__, > +/* Returns VCO range bits for VCO1_0_RANGE */ > +static u8 cdce925_pll_calc_range_bits(struct clk_hw *hw, u16 n, u16 m) > +{ -> + struct clk *parent =3D clk_get_parent(hw->clk); -> + unsigned long rate =3D clk_get_rate(parent); +> + struct clk *parent = clk_get_parent(hw->clk); +> + unsigned long rate = clk_get_rate(parent); > + -> + rate =3D mult_frac(rate, (unsigned long)n, (unsigned long)m); -> + if (rate >=3D 175000000) +> + rate = mult_frac(rate, (unsigned long)n, (unsigned long)m); +> + if (rate >= 175000000) > + return 0x3; -> + if (rate >=3D 150000000) +> + if (rate >= 150000000) > + return 0x02; -> + if (rate >=3D 125000000) +> + if (rate >= 125000000) > + return 0x01; > + return 0x00; > +} @@ -343,49 +321,48 @@ unc__, > + * may sleep */ > +static int cdce925_pll_prepare(struct clk_hw *hw) > +{ -> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw); -> + u16 n =3D data->n; -> + u16 m =3D data->m; +> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw); +> + u16 n = data->n; +> + u16 m = data->m; > + u16 r; > + u8 q; > + u8 p; > + u16 nn; > + u8 pll[4]; /* Bits are spread out over 4 byte registers */ -> + u8 reg_ofs =3D data->index * CDCE925_OFFSET_PLL; +> + u8 reg_ofs = data->index * CDCE925_OFFSET_PLL; > + unsigned i; > + -> + if ((!m || !n) || (m =3D=3D n)) { +> + if ((!m || !n) || (m == n)) { > + /* Set PLL mux to bypass mode, leave the rest as is */ > + regmap_update_bits(data->chip->regmap, > + reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80); > + } else { > + /* According to data sheet: */ -> + /* p =3D max(0, 4 - int(log2 (n/m))) */ -> + p =3D cdce925_pll_calc_p(n, m); -> + /* nn =3D n * 2^p */ -> + nn =3D n * BIT(p); -> + /* q =3D int(nn/m) */ -> + q =3D nn / m; +> + /* p = max(0, 4 - int(log2 (n/m))) */ +> + p = cdce925_pll_calc_p(n, m); +> + /* nn = n * 2^p */ +> + nn = n * BIT(p); +> + /* q = int(nn/m) */ +> + q = nn / m; > + if ((q < 16) || (1 > 64)) { -> + pr_debug("%s invalid q=3D%d\n", __func__, q); +> + pr_debug("%s invalid q=%d\n", __func__, q); > + return -EINVAL; > + } -> + r =3D nn - (m*q); +> + r = nn - (m*q); > + if (r > 511) { -> + pr_debug("%s invalid r=3D%d\n", __func__, r); +> + pr_debug("%s invalid r=%d\n", __func__, r); > + return -EINVAL; > + } -> + pr_debug("%s n=3D%d m=3D%d p=3D%d q=3D%d r=3D%d\n", __fun= -c__, +> + pr_debug("%s n=%d m=%d p=%d q=%d r=%d\n", __func__, > + n, m, p, q, r); > + /* encode into register bits */ -> + pll[0] =3D n >> 4; -> + pll[1] =3D ((n & 0x0F) << 4) | ((r >> 5) & 0x0F); -> + pll[2] =3D ((r & 0x1F) << 3) | ((q >> 3) & 0x07); -> + pll[3] =3D ((q & 0x07) << 5) | (p << 2) | +> + pll[0] = n >> 4; +> + pll[1] = ((n & 0x0F) << 4) | ((r >> 5) & 0x0F); +> + pll[2] = ((r & 0x1F) << 3) | ((q >> 3) & 0x07); +> + pll[3] = ((q & 0x07) << 5) | (p << 2) | > + cdce925_pll_calc_range_bits(hw, n, m); > + /* Write to registers */ -> + for (i =3D 0; i < ARRAY_SIZE(pll); ++i) +> + for (i = 0; i < ARRAY_SIZE(pll); ++i) > + regmap_write(data->chip->regmap, > + reg_ofs + CDCE925_PLL_MULDIV + i, pll[i]); > + /* Enable PLL */ @@ -398,24 +375,23 @@ c__, > + > +static void cdce925_pll_unprepare(struct clk_hw *hw) > +{ -> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw); -> + u8 reg_ofs =3D data->index * CDCE925_OFFSET_PLL; +> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw); +> + u8 reg_ofs = data->index * CDCE925_OFFSET_PLL; > + > + regmap_update_bits(data->chip->regmap, > + reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80); > +} > + -> +static const struct clk_ops cdce925_pll_ops =3D { -> + .prepare =3D cdce925_pll_prepare, -> + .unprepare =3D cdce925_pll_unprepare, -> + .recalc_rate =3D cdce925_pll_recalc_rate, -> + .round_rate =3D cdce925_pll_round_rate, -> + .set_rate =3D cdce925_pll_set_rate, +> +static const struct clk_ops cdce925_pll_ops = { +> + .prepare = cdce925_pll_prepare, +> + .unprepare = cdce925_pll_unprepare, +> + .recalc_rate = cdce925_pll_recalc_rate, +> + .round_rate = cdce925_pll_round_rate, +> + .set_rate = cdce925_pll_set_rate, > +}; > + > + -> +static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pd= -iv) +> +static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pdiv) > +{ > + switch (data->index) { > + case 0: @@ -459,7 +435,7 @@ iv) > + > +static int cdce925_clk_prepare(struct clk_hw *hw) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + > + cdce925_clk_set_pdiv(data, data->pdiv); > + cdce925_clk_activate(data); @@ -468,7 +444,7 @@ iv) > + > +static void cdce925_clk_unprepare(struct clk_hw *hw) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + > + /* Disable clock by setting divider to "0" */ > + cdce925_clk_set_pdiv(data, 0); @@ -477,7 +453,7 @@ iv) > +static unsigned long cdce925_clk_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + > + if (data->pdiv) > + return parent_rate / data->pdiv; @@ -491,12 +467,12 @@ iv) > + > + if (!rate) > + return 0; -> + if (rate >=3D parent_rate) +> + if (rate >= parent_rate) > + return 1; > + -> + divider =3D DIV_ROUND_CLOSEST(parent_rate, rate); +> + divider = DIV_ROUND_CLOSEST(parent_rate, rate); > + if (divider > 0x7F) -> + divider =3D 0x7F; +> + divider = 0x7F; > + > + return (u16)divider; > +} @@ -504,42 +480,40 @@ iv) > +static unsigned long cdce925_clk_best_parent_rate( > + struct clk_hw *hw, unsigned long rate) > +{ -> + struct clk *pll =3D clk_get_parent(hw->clk); -> + struct clk *root =3D clk_get_parent(pll); -> + unsigned long root_rate =3D clk_get_rate(root); -> + unsigned long best_rate_error =3D rate; +> + struct clk *pll = clk_get_parent(hw->clk); +> + struct clk *root = clk_get_parent(pll); +> + unsigned long root_rate = clk_get_rate(root); +> + unsigned long best_rate_error = rate; > + u16 pdiv_min; > + u16 pdiv_max; > + u16 pdiv_best; > + u16 pdiv_now; > + -> + if (root_rate % rate =3D=3D 0) +> + if (root_rate % rate == 0) > + return root_rate; /* Don't need the PLL, use bypass */ > + -> + pdiv_min =3D (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN= -, rate)); -> + pdiv_max =3D (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate); +> + pdiv_min = (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN, rate)); +> + pdiv_max = (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate); > + > + if (pdiv_min > pdiv_max) > + return 0; /* No can do? */ > + -> + pdiv_best =3D pdiv_min; -> + for (pdiv_now =3D pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) { -> + unsigned long target_rate =3D rate * pdiv_now; -> + long pll_rate =3D clk_round_rate(pll, target_rate); +> + pdiv_best = pdiv_min; +> + for (pdiv_now = pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) { +> + unsigned long target_rate = rate * pdiv_now; +> + long pll_rate = clk_round_rate(pll, target_rate); > + unsigned long actual_rate; > + unsigned long rate_error; > + -> + if (pll_rate <=3D 0) +> + if (pll_rate <= 0) > + continue; -> + actual_rate =3D pll_rate / pdiv_now; -> + rate_error =3D abs((long)actual_rate - (long)rate); +> + actual_rate = pll_rate / pdiv_now; +> + rate_error = abs((long)actual_rate - (long)rate); > + if (rate_error < best_rate_error) { -> + pdiv_best =3D pdiv_now; -> + best_rate_error =3D rate_error; +> + pdiv_best = pdiv_now; +> + best_rate_error = rate_error; > + } -> + /* TODO: Consider PLL frequency based on smaller n/m valu= -es +> + /* TODO: Consider PLL frequency based on smaller n/m values > + * and pick the better one if the error is equal */ > + } > + @@ -549,13 +523,13 @@ es > +static long cdce925_clk_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *parent_rate) > +{ -> + unsigned long l_parent_rate =3D *parent_rate; -> + u16 divider =3D cdce925_calc_divider(rate, l_parent_rate); +> + unsigned long l_parent_rate = *parent_rate; +> + u16 divider = cdce925_calc_divider(rate, l_parent_rate); > + -> + if (l_parent_rate / divider !=3D rate) { -> + l_parent_rate =3D cdce925_clk_best_parent_rate(hw, rate); -> + divider =3D cdce925_calc_divider(rate, l_parent_rate); -> + *parent_rate =3D l_parent_rate; +> + if (l_parent_rate / divider != rate) { +> + l_parent_rate = cdce925_clk_best_parent_rate(hw, rate); +> + divider = cdce925_calc_divider(rate, l_parent_rate); +> + *parent_rate = l_parent_rate; > + } > + > + if (divider) @@ -566,19 +540,19 @@ es > +static int cdce925_clk_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + -> + data->pdiv =3D cdce925_calc_divider(rate, parent_rate); +> + data->pdiv = cdce925_calc_divider(rate, parent_rate); > + > + return 0; > +} > + -> +static const struct clk_ops cdce925_clk_ops =3D { -> + .prepare =3D cdce925_clk_prepare, -> + .unprepare =3D cdce925_clk_unprepare, -> + .recalc_rate =3D cdce925_clk_recalc_rate, -> + .round_rate =3D cdce925_clk_round_rate, -> + .set_rate =3D cdce925_clk_set_rate, +> +static const struct clk_ops cdce925_clk_ops = { +> + .prepare = cdce925_clk_prepare, +> + .unprepare = cdce925_clk_unprepare, +> + .recalc_rate = cdce925_clk_recalc_rate, +> + .round_rate = cdce925_clk_round_rate, +> + .set_rate = cdce925_clk_set_rate, > +}; > + > + @@ -589,22 +563,21 @@ es > + > + if (!rate) > + return 0; -> + if (rate >=3D parent_rate) +> + if (rate >= parent_rate) > + return 1; > + -> + divider =3D DIV_ROUND_CLOSEST(parent_rate, rate); +> + divider = DIV_ROUND_CLOSEST(parent_rate, rate); > + if (divider > 0x3FF) /* Y1 has 10-bit divider */ -> + divider =3D 0x3FF; +> + divider = 0x3FF; > + > + return (u16)divider; > +} > + -> +static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long r= -ate, +> +static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *parent_rate) > +{ -> + unsigned long l_parent_rate =3D *parent_rate; -> + u16 divider =3D cdce925_y1_calc_divider(rate, l_parent_rate); +> + unsigned long l_parent_rate = *parent_rate; +> + u16 divider = cdce925_y1_calc_divider(rate, l_parent_rate); > + > + if (divider) > + return (long)(l_parent_rate / divider); @@ -614,28 +587,28 @@ ate, > +static int cdce925_clk_y1_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + -> + data->pdiv =3D cdce925_y1_calc_divider(rate, parent_rate); +> + data->pdiv = cdce925_y1_calc_divider(rate, parent_rate); > + > + return 0; > +} > + -> +static const struct clk_ops cdce925_clk_y1_ops =3D { -> + .prepare =3D cdce925_clk_prepare, -> + .unprepare =3D cdce925_clk_unprepare, -> + .recalc_rate =3D cdce925_clk_recalc_rate, -> + .round_rate =3D cdce925_clk_y1_round_rate, -> + .set_rate =3D cdce925_clk_y1_set_rate, +> +static const struct clk_ops cdce925_clk_y1_ops = { +> + .prepare = cdce925_clk_prepare, +> + .unprepare = cdce925_clk_unprepare, +> + .recalc_rate = cdce925_clk_recalc_rate, +> + .round_rate = cdce925_clk_y1_round_rate, +> + .set_rate = cdce925_clk_y1_set_rate, > +}; > + > + -> +static struct regmap_config cdce925_regmap_config =3D { -> + .name =3D "configuration0", -> + .reg_bits =3D 8, -> + .val_bits =3D 8, -> + .cache_type =3D REGCACHE_RBTREE, -> + .max_register =3D 0x2F, +> +static struct regmap_config cdce925_regmap_config = { +> + .name = "configuration0", +> + .reg_bits = 8, +> + .val_bits = 8, +> + .cache_type = REGCACHE_RBTREE, +> + .max_register = 0x2F, > +}; > + > +#define CDCE925_I2C_COMMAND_BLOCK_TRANSFER 0x00 @@ -644,24 +617,23 @@ ate, > +static int cdce925_regmap_i2c_write( > + void *context, const void *data, size_t count) > +{ -> + struct device *dev =3D context; -> + struct i2c_client *i2c =3D to_i2c_client(dev); +> + struct device *dev = context; +> + struct i2c_client *i2c = to_i2c_client(dev); > + int ret; > + u8 reg_data[2]; > + -> + if (count !=3D 2) +> + if (count != 2) > + return -ENOTSUPP; > + > + /* First byte is command code */ -> + reg_data[0] =3D CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[= -0]; -> + reg_data[1] =3D ((u8 *)data)[1]; +> + reg_data[0] = CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[0]; +> + reg_data[1] = ((u8 *)data)[1]; > + > + dev_dbg(&i2c->dev, "%s(%zu) %#x %#x\n", __func__, count, > + reg_data[0], reg_data[1]); > + -> + ret =3D i2c_master_send(i2c, reg_data, count); -> + if (likely(ret =3D=3D count)) +> + ret = i2c_master_send(i2c, reg_data, count); +> + if (likely(ret == count)) > + return 0; > + else if (ret < 0) > + return ret; @@ -672,41 +644,38 @@ ate, > +static int cdce925_regmap_i2c_read(void *context, > + const void *reg, size_t reg_size, void *val, size_t val_size) > +{ -> + struct device *dev =3D context; -> + struct i2c_client *i2c =3D to_i2c_client(dev); +> + struct device *dev = context; +> + struct i2c_client *i2c = to_i2c_client(dev); > + struct i2c_msg xfer[2]; > + int ret; > + u8 reg_data[2]; > + -> + if (reg_size !=3D 1) +> + if (reg_size != 1) > + return -ENOTSUPP; > + -> + xfer[0].addr =3D i2c->addr; -> + xfer[0].flags =3D 0; -> + xfer[0].buf =3D reg_data; -> + if (val_size =3D=3D 1) { -> + reg_data[0] =3D -> + CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0= -]; -> + xfer[0].len =3D 1; +> + xfer[0].addr = i2c->addr; +> + xfer[0].flags = 0; +> + xfer[0].buf = reg_data; +> + if (val_size == 1) { +> + reg_data[0] = +> + CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0]; +> + xfer[0].len = 1; > + } else { -> + reg_data[0] =3D -> + CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[= -0]; -> + reg_data[1] =3D val_size; -> + xfer[0].len =3D 2; +> + reg_data[0] = +> + CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[0]; +> + reg_data[1] = val_size; +> + xfer[0].len = 2; > + } > + -> + xfer[1].addr =3D i2c->addr; -> + xfer[1].flags =3D I2C_M_RD; -> + xfer[1].len =3D val_size; -> + xfer[1].buf =3D val; +> + xfer[1].addr = i2c->addr; +> + xfer[1].flags = I2C_M_RD; +> + xfer[1].len = val_size; +> + xfer[1].buf = val; > + -> + ret =3D i2c_transfer(i2c->adapter, xfer, 2); -> + if (likely(ret =3D=3D 2)) { +> + ret = i2c_transfer(i2c->adapter, xfer, 2); +> + if (likely(ret == 2)) { > + dev_dbg(&i2c->dev, "%s(%zu, %u) %#x %#x\n", __func__, -> + reg_size, val_size, reg_data[0], *((u8 *)= -val)); +> + reg_size, val_size, reg_data[0], *((u8 *)val)); > + return 0; > + } else if (ret < 0) > + return ret; @@ -716,18 +685,18 @@ val)); > + > +/* The CDCE925 uses a funky way to read/write registers. Bulk mode is > + * just weird, so just use the single byte mode exclusively. */ -> +static struct regmap_bus regmap_cdce925_bus =3D { -> + .write =3D cdce925_regmap_i2c_write, -> + .read =3D cdce925_regmap_i2c_read, +> +static struct regmap_bus regmap_cdce925_bus = { +> + .write = cdce925_regmap_i2c_write, +> + .read = cdce925_regmap_i2c_read, > +}; > + > +static int cdce925_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct clk_cdce925_chip *data; -> + struct device_node *node =3D client->dev.of_node; +> + struct device_node *node = client->dev.of_node; > + const char *parent_name; -> + const char *pll_clk_name[NUMBER_OF_PLLS] =3D {NULL,}; +> + const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,}; > + struct clk_init_data init; > + struct clk *clk; > + u32 value; @@ -737,29 +706,27 @@ val)); > + char child_name[6]; > + > + dev_dbg(&client->dev, "%s\n", __func__); -> + data =3D devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); +> + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + -> + data->i2c_client =3D client; -> + data->regmap =3D devm_regmap_init(&client->dev, ®map_cdce925_b= -us, +> + data->i2c_client = client; +> + data->regmap = devm_regmap_init(&client->dev, ®map_cdce925_bus, > + &client->dev, &cdce925_regmap_config); > + if (IS_ERR(data->regmap)) { -> + dev_err(&client->dev, "failed to allocate register map\n"= -); +> + dev_err(&client->dev, "failed to allocate register map\n"); > + return PTR_ERR(data->regmap); > + } > + i2c_set_clientdata(client, data); > + -> + parent_name =3D of_clk_get_parent_name(node, 0); +> + parent_name = of_clk_get_parent_name(node, 0); > + if (!parent_name) { > + dev_err(&client->dev, "missing parent clock\n"); > + return -ENODEV; > + } > + dev_dbg(&client->dev, "parent is: %s\n", parent_name); > + -> + if (of_property_read_u32(node, "xtal-load-pf", &value) =3D=3D 0) +> + if (of_property_read_u32(node, "xtal-load-pf", &value) == 0) > + regmap_write(data->regmap, > + CDCE925_REG_XCSEL, (value << 3) & 0xF8); > + /* PWDN bit */ @@ -768,42 +735,40 @@ us, > + /* Set input source for Y1 to be the XTAL */ > + regmap_update_bits(data->regmap, 0x02, BIT(7), 0); > + -> + init.ops =3D &cdce925_pll_ops; -> + init.flags =3D 0; -> + init.parent_names =3D &parent_name; -> + init.num_parents =3D parent_name ? 1 : 0; +> + init.ops = &cdce925_pll_ops; +> + init.flags = 0; +> + init.parent_names = &parent_name; +> + init.num_parents = parent_name ? 1 : 0; > + > + /* Register PLL clocks */ -> + for (i =3D 0; i < NUMBER_OF_PLLS; ++i) { -> + pll_clk_name[i] =3D kasprintf(GFP_KERNEL, "%s.pll%d", +> + for (i = 0; i < NUMBER_OF_PLLS; ++i) { +> + pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d", > + client->dev.of_node->name, i); -> + init.name =3D pll_clk_name[i]; -> + data->pll[i].chip =3D data; -> + data->pll[i].hw.init =3D &init; -> + data->pll[i].index =3D i; -> + clk =3D devm_clk_register(&client->dev, &data->pll[i].hw); +> + init.name = pll_clk_name[i]; +> + data->pll[i].chip = data; +> + data->pll[i].hw.init = &init; +> + data->pll[i].index = i; +> + clk = devm_clk_register(&client->dev, &data->pll[i].hw); > + if (IS_ERR(clk)) { -> + dev_err(&client->dev, "Failed register PLL %d\n",= - i); -> + err =3D PTR_ERR(clk); +> + dev_err(&client->dev, "Failed register PLL %d\n", i); +> + err = PTR_ERR(clk); > + goto error; > + } > + sprintf(child_name, "PLL%d", i+1); -> + np_output =3D of_get_child_by_name(node, child_name); +> + np_output = of_get_child_by_name(node, child_name); > + if (!np_output) > + continue; > + if (!of_property_read_u32(np_output, > + "clock-frequency", &value)) { -> + err =3D clk_set_rate(clk, value); +> + err = clk_set_rate(clk, value); > + if (err) > + dev_err(&client->dev, -> + "unable to set PLL frequency %ud\= -n", +> + "unable to set PLL frequency %ud\n", > + value); > + } > + if (!of_property_read_u32(np_output, > + "spread-spectrum", &value)) { -> + u8 flag =3D of_property_read_bool(np_output, +> + u8 flag = of_property_read_bool(np_output, > + "spread-spectrum-center") ? 0x80 : 0x00; > + regmap_update_bits(data->regmap, > + 0x16 + (i*CDCE925_OFFSET_PLL), @@ -815,106 +780,104 @@ n", > + } > + > + /* Register output clock Y1 */ -> + init.ops =3D &cdce925_clk_y1_ops; -> + init.flags =3D 0; -> + init.num_parents =3D 1; -> + init.parent_names =3D &parent_name; /* Mux Y1 to input */ -> + init.name =3D kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node-= ->name); -> + data->clk[0].chip =3D data; -> + data->clk[0].hw.init =3D &init; -> + data->clk[0].index =3D 0; -> + data->clk[0].pdiv =3D 1; -> + clk =3D devm_clk_register(&client->dev, &data->clk[0].hw); +> + init.ops = &cdce925_clk_y1_ops; +> + init.flags = 0; +> + init.num_parents = 1; +> + init.parent_names = &parent_name; /* Mux Y1 to input */ +> + init.name = kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node->name); +> + data->clk[0].chip = data; +> + data->clk[0].hw.init = &init; +> + data->clk[0].index = 0; +> + data->clk[0].pdiv = 1; +> + clk = devm_clk_register(&client->dev, &data->clk[0].hw); > + kfree(init.name); /* clock framework made a copy of the name */ > + if (IS_ERR(clk)) { > + dev_err(&client->dev, "clock registration Y1 failed\n"); -> + err =3D PTR_ERR(clk); +> + err = PTR_ERR(clk); > + goto error; > + } -> + data->dt_clk[0] =3D clk; +> + data->dt_clk[0] = clk; > + > + /* Register output clocks Y2 .. Y5*/ -> + init.ops =3D &cdce925_clk_ops; -> + init.flags =3D CLK_SET_RATE_PARENT; -> + init.num_parents =3D 1; -> + for (i =3D 1; i < NUMBER_OF_OUTPUTS; ++i) { -> + init.name =3D kasprintf(GFP_KERNEL, "%s.Y%d", +> + init.ops = &cdce925_clk_ops; +> + init.flags = CLK_SET_RATE_PARENT; +> + init.num_parents = 1; +> + for (i = 1; i < NUMBER_OF_OUTPUTS; ++i) { +> + init.name = kasprintf(GFP_KERNEL, "%s.Y%d", > + client->dev.of_node->name, i+1); -> + data->clk[i].chip =3D data; -> + data->clk[i].hw.init =3D &init; -> + data->clk[i].index =3D i; -> + data->clk[i].pdiv =3D 1; +> + data->clk[i].chip = data; +> + data->clk[i].hw.init = &init; +> + data->clk[i].index = i; +> + data->clk[i].pdiv = 1; > + switch (i) { > + case 1: > + case 2: > + /* Mux Y2/3 to PLL1 */ -> + init.parent_names =3D &pll_clk_name[0]; +> + init.parent_names = &pll_clk_name[0]; > + break; > + case 3: > + case 4: > + /* Mux Y4/5 to PLL2 */ -> + init.parent_names =3D &pll_clk_name[1]; +> + init.parent_names = &pll_clk_name[1]; > + break; > + } -> + clk =3D devm_clk_register(&client->dev, &data->clk[i].hw); -> + kfree(init.name); /* clock framework made a copy of the n= -ame */ +> + clk = devm_clk_register(&client->dev, &data->clk[i].hw); +> + kfree(init.name); /* clock framework made a copy of the name */ > + if (IS_ERR(clk)) { -> + dev_err(&client->dev, "clock registration failed\= -n"); -> + err =3D PTR_ERR(clk); +> + dev_err(&client->dev, "clock registration failed\n"); +> + err = PTR_ERR(clk); > + goto error; > + } -> + data->dt_clk[i] =3D clk; +> + data->dt_clk[i] = clk; > + } > + > + /* Register the output clocks */ -> + data->onecell.clk_num =3D NUMBER_OF_OUTPUTS; -> + data->onecell.clks =3D data->dt_clk; -> + err =3D of_clk_add_provider(client->dev.of_node, of_clk_src_onece= -ll_get, +> + data->onecell.clk_num = NUMBER_OF_OUTPUTS; +> + data->onecell.clks = data->dt_clk; +> + err = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, > + &data->onecell); > + if (err) -> + dev_err(&client->dev, "unable to add OF clock provider\n"= -); +> + dev_err(&client->dev, "unable to add OF clock provider\n"); > + -> + err =3D 0; +> + err = 0; > + > +error: -> + for (i =3D 0; i < NUMBER_OF_PLLS; ++i) +> + for (i = 0; i < NUMBER_OF_PLLS; ++i) > + /* clock framework made a copy of the name */ > + kfree(pll_clk_name[i]); > + > + return err; > +} > + -> +static const struct i2c_device_id cdce925_id[] =3D { +> +static const struct i2c_device_id cdce925_id[] = { > + { "cdce925", 0 }, > + { } > +}; > +MODULE_DEVICE_TABLE(i2c, cdce925_id); > + -> +static const struct of_device_id clk_cdce925_of_match[] =3D { -> + { .compatible =3D "ti,cdce925" }, +> +static const struct of_device_id clk_cdce925_of_match[] = { +> + { .compatible = "ti,cdce925" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, clk_cdce925_of_match); > + -> +static struct i2c_driver cdce925_driver =3D { -> + .driver =3D { -> + .name =3D "cdce925", -> + .of_match_table =3D of_match_ptr(clk_cdce925_of_match), +> +static struct i2c_driver cdce925_driver = { +> + .driver = { +> + .name = "cdce925", +> + .of_match_table = of_match_ptr(clk_cdce925_of_match), > + }, -> + .probe =3D cdce925_probe, -> + .id_table =3D cdce925_id, +> + .probe = cdce925_probe, +> + .id_table = cdce925_id, > +}; > +module_i2c_driver(cdce925_driver); > + -> +MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); +> +MODULE_AUTHOR("Mike Looijmans <mike.looijmans-Oq418RWZeHk@public.gmane.org>"); > +MODULE_DESCRIPTION("cdce925 driver"); > +MODULE_LICENSE("GPL"); -> -- = - +> -- > 1.9.1 ->=20 +> +-- +To unsubscribe from this list: send the line "unsubscribe devicetree" in +the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org +More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/a/content_digest b/N1/content_digest index 1a954f2..a3400ec 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -1,14 +1,14 @@ "ref\01433153623-29205-1-git-send-email-mike.looijmans@topic.nl\0" "ref\01433309119-5186-1-git-send-email-mike.looijmans@topic.nl\0" - "From\0Michael Turquette <mturquette@linaro.org>\0" + "ref\01433309119-5186-1-git-send-email-mike.looijmans-Oq418RWZeHk@public.gmane.org\0" + "From\0Michael Turquette <mturquette-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>\0" "Subject\0Re: [PATCH v4] Add TI CDCE925 I2C controlled clock synthesizer driver\0" "Date\0Wed, 03 Jun 2015 15:25:04 -0700\0" - "To\0Mike Looijmans <mike.looijmans@topic.nl>" - " linux-clk@vger.kernel.org\0" - "Cc\0sboyd@codeaurora.org" - linux-kernel@vger.kernel.org - devicetree@vger.kernel.org - " Mike Looijmans <mike.looijmans@topic.nl>\0" + "To\0linux-clk-u79uwXL29TY76Z2rM5mHXA@public.gmane.org\0" + "Cc\0sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org" + linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org + devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org + " Mike Looijmans <mike.looijmans-Oq418RWZeHk@public.gmane.org>\0" "\00:1\0" "b\0" "Quoting Mike Looijmans (2015-06-02 22:25:19)\n" @@ -21,9 +21,8 @@ "> Y4 and Y5 derive from PLL2\n" "> Given a target output frequency, the driver will set the PLL and\n" "> divider to best approximate the desired output.\n" - "> =\n" - "\n" - "> Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>\n" + "> \n" + "> Signed-off-by: Mike Looijmans <mike.looijmans-Oq418RWZeHk@public.gmane.org>\n" "\n" "Thanks for fixing it up. Applied to clk-next towards 4.2.\n" "\n" @@ -35,22 +34,17 @@ "> Add devicetree binding documentation\n" "> v3: Remove clk-private.h and processed M.Turquette's feedback\n" "> Use \"ti\" prefix. Use of_clk_src_onecell_get to register.\n" - "> v4: Fix dev_dbg format warning on 64-bit systems (as suggested by Paul Bo=\n" - "lle)\n" - "> =\n" - "\n" + "> v4: Fix dev_dbg format warning on 64-bit systems (as suggested by Paul Bolle)\n" + "> \n" "> .../devicetree/bindings/clock/ti,cdce925.txt | 42 ++\n" "> drivers/clk/Kconfig | 17 +\n" "> drivers/clk/Makefile | 1 +\n" - "> drivers/clk/clk-cdce925.c | 749 +++++++++++++++=\n" - "++++++\n" + "> drivers/clk/clk-cdce925.c | 749 +++++++++++++++++++++\n" "> 4 files changed, 809 insertions(+)\n" "> create mode 100644 Documentation/devicetree/bindings/clock/ti,cdce925.txt\n" "> create mode 100644 drivers/clk/clk-cdce925.c\n" - "> =\n" - "\n" - "> diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Doc=\n" - "umentation/devicetree/bindings/clock/ti,cdce925.txt\n" + "> \n" + "> diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Documentation/devicetree/bindings/clock/ti,cdce925.txt\n" "> new file mode 100644\n" "> index 0000000..4c7669a\n" "> --- /dev/null\n" @@ -69,37 +63,32 @@ "> +Required properties:\n" "> + - compatible: Shall be \"ti,cdce925\"\n" "> + - reg: I2C device address.\n" - "> + - clocks: Points to a fixed parent clock that provides the input freque=\n" - "ncy.\n" + "> + - clocks: Points to a fixed parent clock that provides the input frequency.\n" "> + - #clock-cells: From common clock bindings: Shall be 1.\n" "> +\n" "> +Optional properties:\n" - "> + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance o=\n" - "n a\n" + "> + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a\n" "> + board, or to compensate for external influences.\n" "> +\n" - "> +For both PLL1 and PLL2 an optional child node can be used to specify spr=\n" - "ead\n" + "> +For both PLL1 and PLL2 an optional child node can be used to specify spread\n" "> +spectrum clocking parameters for a board.\n" "> + - spread-spectrum: SSC mode as defined in the data sheet.\n" - "> + - spread-spectrum-center: Use \"centered\" mode instead of \"max\" mode. W=\n" - "hen\n" - "> + present, the clock runs at the requested frequency on average. Other=\n" - "wise\n" + "> + - spread-spectrum-center: Use \"centered\" mode instead of \"max\" mode. When\n" + "> + present, the clock runs at the requested frequency on average. Otherwise\n" "> + the requested frequency is the maximum value of the SCC range.\n" "> +\n" "> +\n" "> +Example:\n" "> +\n" "> + clockgen: cdce925pw@64 {\n" - "> + compatible =3D \"cdce925\";\n" - "> + reg =3D <0x64>;\n" - "> + clocks =3D <&xtal_27Mhz>;\n" - "> + #clock-cells =3D <1>;\n" - "> + xtal-load-pf =3D <5>;\n" + "> + compatible = \"cdce925\";\n" + "> + reg = <0x64>;\n" + "> + clocks = <&xtal_27Mhz>;\n" + "> + #clock-cells = <1>;\n" + "> + xtal-load-pf = <5>;\n" "> + /* PLL options to get SSC 1% centered */\n" "> + PLL2 {\n" - "> + spread-spectrum =3D <4>;\n" + "> + spread-spectrum = <4>;\n" "> + spread-spectrum-center;\n" "> + };\n" "> + };\n" @@ -110,8 +99,7 @@ "> @@ -78,6 +78,23 @@ config COMMON_CLK_SI570\n" "> This driver supports Silicon Labs 570/571/598/599 programmable\n" "> clock generators.\n" - "> =\n" - "\n" + "> \n" "> +config COMMON_CLK_CDCE925\n" "> + tristate \"Clock driver for TI CDCE925 devices\"\n" "> + depends on I2C\n" @@ -119,12 +107,9 @@ "> + select REGMAP_I2C\n" "> + help\n" "> + ---help---\n" - "> + This driver supports the TI CDCE925 programmable clock synthesi=\n" - "zer.\n" - "> + The chip contains two PLLs with spread-spectrum clocking suppor=\n" - "t and\n" - "> + five output dividers. The driver only supports the following se=\n" - "tup,\n" + "> + This driver supports the TI CDCE925 programmable clock synthesizer.\n" + "> + The chip contains two PLLs with spread-spectrum clocking support and\n" + "> + five output dividers. The driver only supports the following setup,\n" "> + and uses a fixed setting for the output muxes.\n" "> + Y1 is derived from the input clock\n" "> + Y2 and Y3 derive from PLL1\n" @@ -139,15 +124,14 @@ "> index 3d00c25..49d38de 100644\n" "> --- a/drivers/clk/Makefile\n" "> +++ b/drivers/clk/Makefile\n" - "> @@ -38,6 +38,7 @@ obj-$(CONFIG_COMMON_CLK_RK808) +=3D clk-=\n" - "rk808.o\n" - "> obj-$(CONFIG_COMMON_CLK_S2MPS11) +=3D clk-s2mps11.o\n" - "> obj-$(CONFIG_COMMON_CLK_SI5351) +=3D clk-si5351.o\n" - "> obj-$(CONFIG_COMMON_CLK_SI570) +=3D clk-si570.o\n" - "> +obj-$(CONFIG_COMMON_CLK_CDCE925) +=3D clk-cdce925.o\n" - "> obj-$(CONFIG_CLK_TWL6040) +=3D clk-twl6040.o\n" - "> obj-$(CONFIG_ARCH_U300) +=3D clk-u300.o\n" - "> obj-$(CONFIG_ARCH_VT8500) +=3D clk-vt8500.o\n" + "> @@ -38,6 +38,7 @@ obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o\n" + "> obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o\n" + "> obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o\n" + "> obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o\n" + "> +obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o\n" + "> obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o\n" + "> obj-$(CONFIG_ARCH_U300) += clk-u300.o\n" + "> obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o\n" "> diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c\n" "> new file mode 100644\n" "> index 0000000..56b870d\n" @@ -210,8 +194,7 @@ "> + u16 m; /* 1..511 */\n" "> + u16 n; /* 1..4095 */\n" "> +};\n" - "> +#define to_clk_cdce925_pll(_hw) container_of(_hw, struct clk_cdce=\n" - "925_pll, hw)\n" + "> +#define to_clk_cdce925_pll(_hw) container_of(_hw, struct clk_cdce925_pll, hw)\n" "> +\n" "> +struct clk_cdce925_chip {\n" "> + struct regmap *regmap;\n" @@ -224,21 +207,19 @@ "> +\n" "> +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */\n" "> +\n" - "> +static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rat=\n" - "e,\n" + "> +static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rate,\n" "> + u16 n, u16 m)\n" "> +{\n" - "> + if ((!m || !n) || (m =3D=3D n))\n" - "> + return parent_rate; /* In bypass mode runs at same freque=\n" - "ncy */\n" + "> + if ((!m || !n) || (m == n))\n" + "> + return parent_rate; /* In bypass mode runs at same frequency */\n" "> + return mult_frac(parent_rate, (unsigned long)n, (unsigned long)m);\n" "> +}\n" "> +\n" "> +static unsigned long cdce925_pll_recalc_rate(struct clk_hw *hw,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + /* Output frequency of PLL is Fout =3D (Fin/Pdiv)*(N/M) */\n" - "> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw);\n" + "> + /* Output frequency of PLL is Fout = (Fin/Pdiv)*(N/M) */\n" + "> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);\n" "> +\n" "> + return cdce925_pll_calculate_rate(parent_rate, data->n, data->m);\n" "> +}\n" @@ -250,34 +231,33 @@ "> + unsigned long um;\n" "> + unsigned long g;\n" "> +\n" - "> + if (rate <=3D parent_rate) {\n" + "> + if (rate <= parent_rate) {\n" "> + /* Can always deliver parent_rate in bypass mode */\n" - "> + rate =3D parent_rate;\n" - "> + *n =3D 0;\n" - "> + *m =3D 0;\n" + "> + rate = parent_rate;\n" + "> + *n = 0;\n" + "> + *m = 0;\n" "> + } else {\n" "> + /* In PLL mode, need to apply min/max range */\n" "> + if (rate < CDCE925_PLL_FREQUENCY_MIN)\n" - "> + rate =3D CDCE925_PLL_FREQUENCY_MIN;\n" + "> + rate = CDCE925_PLL_FREQUENCY_MIN;\n" "> + else if (rate > CDCE925_PLL_FREQUENCY_MAX)\n" - "> + rate =3D CDCE925_PLL_FREQUENCY_MAX;\n" + "> + rate = CDCE925_PLL_FREQUENCY_MAX;\n" "> +\n" - "> + g =3D gcd(rate, parent_rate);\n" - "> + um =3D parent_rate / g;\n" - "> + un =3D rate / g;\n" - "> + /* When outside hw range, reduce to fit (rounding errors)=\n" - " */\n" + "> + g = gcd(rate, parent_rate);\n" + "> + um = parent_rate / g;\n" + "> + un = rate / g;\n" + "> + /* When outside hw range, reduce to fit (rounding errors) */\n" "> + while ((un > 4095) || (um > 511)) {\n" - "> + un >>=3D 1;\n" - "> + um >>=3D 1;\n" + "> + un >>= 1;\n" + "> + um >>= 1;\n" "> + }\n" - "> + if (un =3D=3D 0)\n" - "> + un =3D 1;\n" - "> + if (um =3D=3D 0)\n" - "> + um =3D 1;\n" + "> + if (un == 0)\n" + "> + un = 1;\n" + "> + if (um == 0)\n" + "> + um = 1;\n" "> +\n" - "> + *n =3D un;\n" - "> + *m =3D um;\n" + "> + *n = un;\n" + "> + *m = um;\n" "> + }\n" "> +}\n" "> +\n" @@ -293,24 +273,22 @@ "> +static int cdce925_pll_set_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw);\n" + "> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);\n" "> +\n" - "> + if (!rate || (rate =3D=3D parent_rate)) {\n" - "> + data->m =3D 0; /* Bypass mode */\n" - "> + data->n =3D 0;\n" + "> + if (!rate || (rate == parent_rate)) {\n" + "> + data->m = 0; /* Bypass mode */\n" + "> + data->n = 0;\n" "> + return 0;\n" "> + }\n" "> +\n" "> + if ((rate < CDCE925_PLL_FREQUENCY_MIN) ||\n" "> + (rate > CDCE925_PLL_FREQUENCY_MAX)) {\n" - "> + pr_debug(\"%s: rate %lu outside PLL range.\\n\", __func__, r=\n" - "ate);\n" + "> + pr_debug(\"%s: rate %lu outside PLL range.\\n\", __func__, rate);\n" "> + return -EINVAL;\n" "> + }\n" "> +\n" "> + if (rate < parent_rate) {\n" - "> + pr_debug(\"%s: rate %lu less than parent rate %lu.\\n\", __f=\n" - "unc__,\n" + "> + pr_debug(\"%s: rate %lu less than parent rate %lu.\\n\", __func__,\n" "> + rate, parent_rate);\n" "> + return -EINVAL;\n" "> + }\n" @@ -320,17 +298,17 @@ "> +}\n" "> +\n" "> +\n" - "> +/* calculate p =3D max(0, 4 - int(log2 (n/m))) */\n" + "> +/* calculate p = max(0, 4 - int(log2 (n/m))) */\n" "> +static u8 cdce925_pll_calc_p(u16 n, u16 m)\n" "> +{\n" "> + u8 p;\n" - "> + u16 r =3D n / m;\n" + "> + u16 r = n / m;\n" "> +\n" - "> + if (r >=3D 16)\n" + "> + if (r >= 16)\n" "> + return 0;\n" - "> + p =3D 4;\n" + "> + p = 4;\n" "> + while (r > 1) {\n" - "> + r >>=3D 1;\n" + "> + r >>= 1;\n" "> + --p;\n" "> + }\n" "> + return p;\n" @@ -339,15 +317,15 @@ "> +/* Returns VCO range bits for VCO1_0_RANGE */\n" "> +static u8 cdce925_pll_calc_range_bits(struct clk_hw *hw, u16 n, u16 m)\n" "> +{\n" - "> + struct clk *parent =3D clk_get_parent(hw->clk);\n" - "> + unsigned long rate =3D clk_get_rate(parent);\n" + "> + struct clk *parent = clk_get_parent(hw->clk);\n" + "> + unsigned long rate = clk_get_rate(parent);\n" "> +\n" - "> + rate =3D mult_frac(rate, (unsigned long)n, (unsigned long)m);\n" - "> + if (rate >=3D 175000000)\n" + "> + rate = mult_frac(rate, (unsigned long)n, (unsigned long)m);\n" + "> + if (rate >= 175000000)\n" "> + return 0x3;\n" - "> + if (rate >=3D 150000000)\n" + "> + if (rate >= 150000000)\n" "> + return 0x02;\n" - "> + if (rate >=3D 125000000)\n" + "> + if (rate >= 125000000)\n" "> + return 0x01;\n" "> + return 0x00;\n" "> +}\n" @@ -356,49 +334,48 @@ "> + * may sleep */\n" "> +static int cdce925_pll_prepare(struct clk_hw *hw)\n" "> +{\n" - "> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw);\n" - "> + u16 n =3D data->n;\n" - "> + u16 m =3D data->m;\n" + "> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);\n" + "> + u16 n = data->n;\n" + "> + u16 m = data->m;\n" "> + u16 r;\n" "> + u8 q;\n" "> + u8 p;\n" "> + u16 nn;\n" "> + u8 pll[4]; /* Bits are spread out over 4 byte registers */\n" - "> + u8 reg_ofs =3D data->index * CDCE925_OFFSET_PLL;\n" + "> + u8 reg_ofs = data->index * CDCE925_OFFSET_PLL;\n" "> + unsigned i;\n" "> +\n" - "> + if ((!m || !n) || (m =3D=3D n)) {\n" + "> + if ((!m || !n) || (m == n)) {\n" "> + /* Set PLL mux to bypass mode, leave the rest as is */\n" "> + regmap_update_bits(data->chip->regmap,\n" "> + reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80);\n" "> + } else {\n" "> + /* According to data sheet: */\n" - "> + /* p =3D max(0, 4 - int(log2 (n/m))) */\n" - "> + p =3D cdce925_pll_calc_p(n, m);\n" - "> + /* nn =3D n * 2^p */\n" - "> + nn =3D n * BIT(p);\n" - "> + /* q =3D int(nn/m) */\n" - "> + q =3D nn / m;\n" + "> + /* p = max(0, 4 - int(log2 (n/m))) */\n" + "> + p = cdce925_pll_calc_p(n, m);\n" + "> + /* nn = n * 2^p */\n" + "> + nn = n * BIT(p);\n" + "> + /* q = int(nn/m) */\n" + "> + q = nn / m;\n" "> + if ((q < 16) || (1 > 64)) {\n" - "> + pr_debug(\"%s invalid q=3D%d\\n\", __func__, q);\n" + "> + pr_debug(\"%s invalid q=%d\\n\", __func__, q);\n" "> + return -EINVAL;\n" "> + }\n" - "> + r =3D nn - (m*q);\n" + "> + r = nn - (m*q);\n" "> + if (r > 511) {\n" - "> + pr_debug(\"%s invalid r=3D%d\\n\", __func__, r);\n" + "> + pr_debug(\"%s invalid r=%d\\n\", __func__, r);\n" "> + return -EINVAL;\n" "> + }\n" - "> + pr_debug(\"%s n=3D%d m=3D%d p=3D%d q=3D%d r=3D%d\\n\", __fun=\n" - "c__,\n" + "> + pr_debug(\"%s n=%d m=%d p=%d q=%d r=%d\\n\", __func__,\n" "> + n, m, p, q, r);\n" "> + /* encode into register bits */\n" - "> + pll[0] =3D n >> 4;\n" - "> + pll[1] =3D ((n & 0x0F) << 4) | ((r >> 5) & 0x0F);\n" - "> + pll[2] =3D ((r & 0x1F) << 3) | ((q >> 3) & 0x07);\n" - "> + pll[3] =3D ((q & 0x07) << 5) | (p << 2) |\n" + "> + pll[0] = n >> 4;\n" + "> + pll[1] = ((n & 0x0F) << 4) | ((r >> 5) & 0x0F);\n" + "> + pll[2] = ((r & 0x1F) << 3) | ((q >> 3) & 0x07);\n" + "> + pll[3] = ((q & 0x07) << 5) | (p << 2) |\n" "> + cdce925_pll_calc_range_bits(hw, n, m);\n" "> + /* Write to registers */\n" - "> + for (i =3D 0; i < ARRAY_SIZE(pll); ++i)\n" + "> + for (i = 0; i < ARRAY_SIZE(pll); ++i)\n" "> + regmap_write(data->chip->regmap,\n" "> + reg_ofs + CDCE925_PLL_MULDIV + i, pll[i]);\n" "> + /* Enable PLL */\n" @@ -411,24 +388,23 @@ "> +\n" "> +static void cdce925_pll_unprepare(struct clk_hw *hw)\n" "> +{\n" - "> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw);\n" - "> + u8 reg_ofs =3D data->index * CDCE925_OFFSET_PLL;\n" + "> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);\n" + "> + u8 reg_ofs = data->index * CDCE925_OFFSET_PLL;\n" "> +\n" "> + regmap_update_bits(data->chip->regmap,\n" "> + reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80);\n" "> +}\n" "> +\n" - "> +static const struct clk_ops cdce925_pll_ops =3D {\n" - "> + .prepare =3D cdce925_pll_prepare,\n" - "> + .unprepare =3D cdce925_pll_unprepare,\n" - "> + .recalc_rate =3D cdce925_pll_recalc_rate,\n" - "> + .round_rate =3D cdce925_pll_round_rate,\n" - "> + .set_rate =3D cdce925_pll_set_rate,\n" + "> +static const struct clk_ops cdce925_pll_ops = {\n" + "> + .prepare = cdce925_pll_prepare,\n" + "> + .unprepare = cdce925_pll_unprepare,\n" + "> + .recalc_rate = cdce925_pll_recalc_rate,\n" + "> + .round_rate = cdce925_pll_round_rate,\n" + "> + .set_rate = cdce925_pll_set_rate,\n" "> +};\n" "> +\n" "> +\n" - "> +static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pd=\n" - "iv)\n" + "> +static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pdiv)\n" "> +{\n" "> + switch (data->index) {\n" "> + case 0:\n" @@ -472,7 +448,7 @@ "> +\n" "> +static int cdce925_clk_prepare(struct clk_hw *hw)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" "> + cdce925_clk_set_pdiv(data, data->pdiv);\n" "> + cdce925_clk_activate(data);\n" @@ -481,7 +457,7 @@ "> +\n" "> +static void cdce925_clk_unprepare(struct clk_hw *hw)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" "> + /* Disable clock by setting divider to \"0\" */\n" "> + cdce925_clk_set_pdiv(data, 0);\n" @@ -490,7 +466,7 @@ "> +static unsigned long cdce925_clk_recalc_rate(struct clk_hw *hw,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" "> + if (data->pdiv)\n" "> + return parent_rate / data->pdiv;\n" @@ -504,12 +480,12 @@ "> +\n" "> + if (!rate)\n" "> + return 0;\n" - "> + if (rate >=3D parent_rate)\n" + "> + if (rate >= parent_rate)\n" "> + return 1;\n" "> +\n" - "> + divider =3D DIV_ROUND_CLOSEST(parent_rate, rate);\n" + "> + divider = DIV_ROUND_CLOSEST(parent_rate, rate);\n" "> + if (divider > 0x7F)\n" - "> + divider =3D 0x7F;\n" + "> + divider = 0x7F;\n" "> +\n" "> + return (u16)divider;\n" "> +}\n" @@ -517,42 +493,40 @@ "> +static unsigned long cdce925_clk_best_parent_rate(\n" "> + struct clk_hw *hw, unsigned long rate)\n" "> +{\n" - "> + struct clk *pll =3D clk_get_parent(hw->clk);\n" - "> + struct clk *root =3D clk_get_parent(pll);\n" - "> + unsigned long root_rate =3D clk_get_rate(root);\n" - "> + unsigned long best_rate_error =3D rate;\n" + "> + struct clk *pll = clk_get_parent(hw->clk);\n" + "> + struct clk *root = clk_get_parent(pll);\n" + "> + unsigned long root_rate = clk_get_rate(root);\n" + "> + unsigned long best_rate_error = rate;\n" "> + u16 pdiv_min;\n" "> + u16 pdiv_max;\n" "> + u16 pdiv_best;\n" "> + u16 pdiv_now;\n" "> +\n" - "> + if (root_rate % rate =3D=3D 0)\n" + "> + if (root_rate % rate == 0)\n" "> + return root_rate; /* Don't need the PLL, use bypass */\n" "> +\n" - "> + pdiv_min =3D (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN=\n" - ", rate));\n" - "> + pdiv_max =3D (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate);\n" + "> + pdiv_min = (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN, rate));\n" + "> + pdiv_max = (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate);\n" "> +\n" "> + if (pdiv_min > pdiv_max)\n" "> + return 0; /* No can do? */\n" "> +\n" - "> + pdiv_best =3D pdiv_min;\n" - "> + for (pdiv_now =3D pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) {\n" - "> + unsigned long target_rate =3D rate * pdiv_now;\n" - "> + long pll_rate =3D clk_round_rate(pll, target_rate);\n" + "> + pdiv_best = pdiv_min;\n" + "> + for (pdiv_now = pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) {\n" + "> + unsigned long target_rate = rate * pdiv_now;\n" + "> + long pll_rate = clk_round_rate(pll, target_rate);\n" "> + unsigned long actual_rate;\n" "> + unsigned long rate_error;\n" "> +\n" - "> + if (pll_rate <=3D 0)\n" + "> + if (pll_rate <= 0)\n" "> + continue;\n" - "> + actual_rate =3D pll_rate / pdiv_now;\n" - "> + rate_error =3D abs((long)actual_rate - (long)rate);\n" + "> + actual_rate = pll_rate / pdiv_now;\n" + "> + rate_error = abs((long)actual_rate - (long)rate);\n" "> + if (rate_error < best_rate_error) {\n" - "> + pdiv_best =3D pdiv_now;\n" - "> + best_rate_error =3D rate_error;\n" + "> + pdiv_best = pdiv_now;\n" + "> + best_rate_error = rate_error;\n" "> + }\n" - "> + /* TODO: Consider PLL frequency based on smaller n/m valu=\n" - "es\n" + "> + /* TODO: Consider PLL frequency based on smaller n/m values\n" "> + * and pick the better one if the error is equal */\n" "> + }\n" "> +\n" @@ -562,13 +536,13 @@ "> +static long cdce925_clk_round_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long *parent_rate)\n" "> +{\n" - "> + unsigned long l_parent_rate =3D *parent_rate;\n" - "> + u16 divider =3D cdce925_calc_divider(rate, l_parent_rate);\n" + "> + unsigned long l_parent_rate = *parent_rate;\n" + "> + u16 divider = cdce925_calc_divider(rate, l_parent_rate);\n" "> +\n" - "> + if (l_parent_rate / divider !=3D rate) {\n" - "> + l_parent_rate =3D cdce925_clk_best_parent_rate(hw, rate);\n" - "> + divider =3D cdce925_calc_divider(rate, l_parent_rate);\n" - "> + *parent_rate =3D l_parent_rate;\n" + "> + if (l_parent_rate / divider != rate) {\n" + "> + l_parent_rate = cdce925_clk_best_parent_rate(hw, rate);\n" + "> + divider = cdce925_calc_divider(rate, l_parent_rate);\n" + "> + *parent_rate = l_parent_rate;\n" "> + }\n" "> +\n" "> + if (divider)\n" @@ -579,19 +553,19 @@ "> +static int cdce925_clk_set_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" - "> + data->pdiv =3D cdce925_calc_divider(rate, parent_rate);\n" + "> + data->pdiv = cdce925_calc_divider(rate, parent_rate);\n" "> +\n" "> + return 0;\n" "> +}\n" "> +\n" - "> +static const struct clk_ops cdce925_clk_ops =3D {\n" - "> + .prepare =3D cdce925_clk_prepare,\n" - "> + .unprepare =3D cdce925_clk_unprepare,\n" - "> + .recalc_rate =3D cdce925_clk_recalc_rate,\n" - "> + .round_rate =3D cdce925_clk_round_rate,\n" - "> + .set_rate =3D cdce925_clk_set_rate,\n" + "> +static const struct clk_ops cdce925_clk_ops = {\n" + "> + .prepare = cdce925_clk_prepare,\n" + "> + .unprepare = cdce925_clk_unprepare,\n" + "> + .recalc_rate = cdce925_clk_recalc_rate,\n" + "> + .round_rate = cdce925_clk_round_rate,\n" + "> + .set_rate = cdce925_clk_set_rate,\n" "> +};\n" "> +\n" "> +\n" @@ -602,22 +576,21 @@ "> +\n" "> + if (!rate)\n" "> + return 0;\n" - "> + if (rate >=3D parent_rate)\n" + "> + if (rate >= parent_rate)\n" "> + return 1;\n" "> +\n" - "> + divider =3D DIV_ROUND_CLOSEST(parent_rate, rate);\n" + "> + divider = DIV_ROUND_CLOSEST(parent_rate, rate);\n" "> + if (divider > 0x3FF) /* Y1 has 10-bit divider */\n" - "> + divider =3D 0x3FF;\n" + "> + divider = 0x3FF;\n" "> +\n" "> + return (u16)divider;\n" "> +}\n" "> +\n" - "> +static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long r=\n" - "ate,\n" + "> +static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long *parent_rate)\n" "> +{\n" - "> + unsigned long l_parent_rate =3D *parent_rate;\n" - "> + u16 divider =3D cdce925_y1_calc_divider(rate, l_parent_rate);\n" + "> + unsigned long l_parent_rate = *parent_rate;\n" + "> + u16 divider = cdce925_y1_calc_divider(rate, l_parent_rate);\n" "> +\n" "> + if (divider)\n" "> + return (long)(l_parent_rate / divider);\n" @@ -627,28 +600,28 @@ "> +static int cdce925_clk_y1_set_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" - "> + data->pdiv =3D cdce925_y1_calc_divider(rate, parent_rate);\n" + "> + data->pdiv = cdce925_y1_calc_divider(rate, parent_rate);\n" "> +\n" "> + return 0;\n" "> +}\n" "> +\n" - "> +static const struct clk_ops cdce925_clk_y1_ops =3D {\n" - "> + .prepare =3D cdce925_clk_prepare,\n" - "> + .unprepare =3D cdce925_clk_unprepare,\n" - "> + .recalc_rate =3D cdce925_clk_recalc_rate,\n" - "> + .round_rate =3D cdce925_clk_y1_round_rate,\n" - "> + .set_rate =3D cdce925_clk_y1_set_rate,\n" + "> +static const struct clk_ops cdce925_clk_y1_ops = {\n" + "> + .prepare = cdce925_clk_prepare,\n" + "> + .unprepare = cdce925_clk_unprepare,\n" + "> + .recalc_rate = cdce925_clk_recalc_rate,\n" + "> + .round_rate = cdce925_clk_y1_round_rate,\n" + "> + .set_rate = cdce925_clk_y1_set_rate,\n" "> +};\n" "> +\n" "> +\n" - "> +static struct regmap_config cdce925_regmap_config =3D {\n" - "> + .name =3D \"configuration0\",\n" - "> + .reg_bits =3D 8,\n" - "> + .val_bits =3D 8,\n" - "> + .cache_type =3D REGCACHE_RBTREE,\n" - "> + .max_register =3D 0x2F,\n" + "> +static struct regmap_config cdce925_regmap_config = {\n" + "> + .name = \"configuration0\",\n" + "> + .reg_bits = 8,\n" + "> + .val_bits = 8,\n" + "> + .cache_type = REGCACHE_RBTREE,\n" + "> + .max_register = 0x2F,\n" "> +};\n" "> +\n" "> +#define CDCE925_I2C_COMMAND_BLOCK_TRANSFER 0x00\n" @@ -657,24 +630,23 @@ "> +static int cdce925_regmap_i2c_write(\n" "> + void *context, const void *data, size_t count)\n" "> +{\n" - "> + struct device *dev =3D context;\n" - "> + struct i2c_client *i2c =3D to_i2c_client(dev);\n" + "> + struct device *dev = context;\n" + "> + struct i2c_client *i2c = to_i2c_client(dev);\n" "> + int ret;\n" "> + u8 reg_data[2];\n" "> +\n" - "> + if (count !=3D 2)\n" + "> + if (count != 2)\n" "> + return -ENOTSUPP;\n" "> +\n" "> + /* First byte is command code */\n" - "> + reg_data[0] =3D CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[=\n" - "0];\n" - "> + reg_data[1] =3D ((u8 *)data)[1];\n" + "> + reg_data[0] = CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[0];\n" + "> + reg_data[1] = ((u8 *)data)[1];\n" "> +\n" "> + dev_dbg(&i2c->dev, \"%s(%zu) %#x %#x\\n\", __func__, count,\n" "> + reg_data[0], reg_data[1]);\n" "> +\n" - "> + ret =3D i2c_master_send(i2c, reg_data, count);\n" - "> + if (likely(ret =3D=3D count))\n" + "> + ret = i2c_master_send(i2c, reg_data, count);\n" + "> + if (likely(ret == count))\n" "> + return 0;\n" "> + else if (ret < 0)\n" "> + return ret;\n" @@ -685,41 +657,38 @@ "> +static int cdce925_regmap_i2c_read(void *context,\n" "> + const void *reg, size_t reg_size, void *val, size_t val_size)\n" "> +{\n" - "> + struct device *dev =3D context;\n" - "> + struct i2c_client *i2c =3D to_i2c_client(dev);\n" + "> + struct device *dev = context;\n" + "> + struct i2c_client *i2c = to_i2c_client(dev);\n" "> + struct i2c_msg xfer[2];\n" "> + int ret;\n" "> + u8 reg_data[2];\n" "> +\n" - "> + if (reg_size !=3D 1)\n" + "> + if (reg_size != 1)\n" "> + return -ENOTSUPP;\n" "> +\n" - "> + xfer[0].addr =3D i2c->addr;\n" - "> + xfer[0].flags =3D 0;\n" - "> + xfer[0].buf =3D reg_data;\n" - "> + if (val_size =3D=3D 1) {\n" - "> + reg_data[0] =3D\n" - "> + CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0=\n" - "];\n" - "> + xfer[0].len =3D 1;\n" + "> + xfer[0].addr = i2c->addr;\n" + "> + xfer[0].flags = 0;\n" + "> + xfer[0].buf = reg_data;\n" + "> + if (val_size == 1) {\n" + "> + reg_data[0] =\n" + "> + CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0];\n" + "> + xfer[0].len = 1;\n" "> + } else {\n" - "> + reg_data[0] =3D\n" - "> + CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[=\n" - "0];\n" - "> + reg_data[1] =3D val_size;\n" - "> + xfer[0].len =3D 2;\n" + "> + reg_data[0] =\n" + "> + CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[0];\n" + "> + reg_data[1] = val_size;\n" + "> + xfer[0].len = 2;\n" "> + }\n" "> +\n" - "> + xfer[1].addr =3D i2c->addr;\n" - "> + xfer[1].flags =3D I2C_M_RD;\n" - "> + xfer[1].len =3D val_size;\n" - "> + xfer[1].buf =3D val;\n" + "> + xfer[1].addr = i2c->addr;\n" + "> + xfer[1].flags = I2C_M_RD;\n" + "> + xfer[1].len = val_size;\n" + "> + xfer[1].buf = val;\n" "> +\n" - "> + ret =3D i2c_transfer(i2c->adapter, xfer, 2);\n" - "> + if (likely(ret =3D=3D 2)) {\n" + "> + ret = i2c_transfer(i2c->adapter, xfer, 2);\n" + "> + if (likely(ret == 2)) {\n" "> + dev_dbg(&i2c->dev, \"%s(%zu, %u) %#x %#x\\n\", __func__,\n" - "> + reg_size, val_size, reg_data[0], *((u8 *)=\n" - "val));\n" + "> + reg_size, val_size, reg_data[0], *((u8 *)val));\n" "> + return 0;\n" "> + } else if (ret < 0)\n" "> + return ret;\n" @@ -729,18 +698,18 @@ "> +\n" "> +/* The CDCE925 uses a funky way to read/write registers. Bulk mode is\n" "> + * just weird, so just use the single byte mode exclusively. */\n" - "> +static struct regmap_bus regmap_cdce925_bus =3D {\n" - "> + .write =3D cdce925_regmap_i2c_write,\n" - "> + .read =3D cdce925_regmap_i2c_read,\n" + "> +static struct regmap_bus regmap_cdce925_bus = {\n" + "> + .write = cdce925_regmap_i2c_write,\n" + "> + .read = cdce925_regmap_i2c_read,\n" "> +};\n" "> +\n" "> +static int cdce925_probe(struct i2c_client *client,\n" "> + const struct i2c_device_id *id)\n" "> +{\n" "> + struct clk_cdce925_chip *data;\n" - "> + struct device_node *node =3D client->dev.of_node;\n" + "> + struct device_node *node = client->dev.of_node;\n" "> + const char *parent_name;\n" - "> + const char *pll_clk_name[NUMBER_OF_PLLS] =3D {NULL,};\n" + "> + const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,};\n" "> + struct clk_init_data init;\n" "> + struct clk *clk;\n" "> + u32 value;\n" @@ -750,29 +719,27 @@ "> + char child_name[6];\n" "> +\n" "> + dev_dbg(&client->dev, \"%s\\n\", __func__);\n" - "> + data =3D devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);\n" + "> + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);\n" "> + if (!data)\n" "> + return -ENOMEM;\n" "> +\n" - "> + data->i2c_client =3D client;\n" - "> + data->regmap =3D devm_regmap_init(&client->dev, ®map_cdce925_b=\n" - "us,\n" + "> + data->i2c_client = client;\n" + "> + data->regmap = devm_regmap_init(&client->dev, ®map_cdce925_bus,\n" "> + &client->dev, &cdce925_regmap_config);\n" "> + if (IS_ERR(data->regmap)) {\n" - "> + dev_err(&client->dev, \"failed to allocate register map\\n\"=\n" - ");\n" + "> + dev_err(&client->dev, \"failed to allocate register map\\n\");\n" "> + return PTR_ERR(data->regmap);\n" "> + }\n" "> + i2c_set_clientdata(client, data);\n" "> +\n" - "> + parent_name =3D of_clk_get_parent_name(node, 0);\n" + "> + parent_name = of_clk_get_parent_name(node, 0);\n" "> + if (!parent_name) {\n" "> + dev_err(&client->dev, \"missing parent clock\\n\");\n" "> + return -ENODEV;\n" "> + }\n" "> + dev_dbg(&client->dev, \"parent is: %s\\n\", parent_name);\n" "> +\n" - "> + if (of_property_read_u32(node, \"xtal-load-pf\", &value) =3D=3D 0)\n" + "> + if (of_property_read_u32(node, \"xtal-load-pf\", &value) == 0)\n" "> + regmap_write(data->regmap,\n" "> + CDCE925_REG_XCSEL, (value << 3) & 0xF8);\n" "> + /* PWDN bit */\n" @@ -781,42 +748,40 @@ "> + /* Set input source for Y1 to be the XTAL */\n" "> + regmap_update_bits(data->regmap, 0x02, BIT(7), 0);\n" "> +\n" - "> + init.ops =3D &cdce925_pll_ops;\n" - "> + init.flags =3D 0;\n" - "> + init.parent_names =3D &parent_name;\n" - "> + init.num_parents =3D parent_name ? 1 : 0;\n" + "> + init.ops = &cdce925_pll_ops;\n" + "> + init.flags = 0;\n" + "> + init.parent_names = &parent_name;\n" + "> + init.num_parents = parent_name ? 1 : 0;\n" "> +\n" "> + /* Register PLL clocks */\n" - "> + for (i =3D 0; i < NUMBER_OF_PLLS; ++i) {\n" - "> + pll_clk_name[i] =3D kasprintf(GFP_KERNEL, \"%s.pll%d\",\n" + "> + for (i = 0; i < NUMBER_OF_PLLS; ++i) {\n" + "> + pll_clk_name[i] = kasprintf(GFP_KERNEL, \"%s.pll%d\",\n" "> + client->dev.of_node->name, i);\n" - "> + init.name =3D pll_clk_name[i];\n" - "> + data->pll[i].chip =3D data;\n" - "> + data->pll[i].hw.init =3D &init;\n" - "> + data->pll[i].index =3D i;\n" - "> + clk =3D devm_clk_register(&client->dev, &data->pll[i].hw);\n" + "> + init.name = pll_clk_name[i];\n" + "> + data->pll[i].chip = data;\n" + "> + data->pll[i].hw.init = &init;\n" + "> + data->pll[i].index = i;\n" + "> + clk = devm_clk_register(&client->dev, &data->pll[i].hw);\n" "> + if (IS_ERR(clk)) {\n" - "> + dev_err(&client->dev, \"Failed register PLL %d\\n\",=\n" - " i);\n" - "> + err =3D PTR_ERR(clk);\n" + "> + dev_err(&client->dev, \"Failed register PLL %d\\n\", i);\n" + "> + err = PTR_ERR(clk);\n" "> + goto error;\n" "> + }\n" "> + sprintf(child_name, \"PLL%d\", i+1);\n" - "> + np_output =3D of_get_child_by_name(node, child_name);\n" + "> + np_output = of_get_child_by_name(node, child_name);\n" "> + if (!np_output)\n" "> + continue;\n" "> + if (!of_property_read_u32(np_output,\n" "> + \"clock-frequency\", &value)) {\n" - "> + err =3D clk_set_rate(clk, value);\n" + "> + err = clk_set_rate(clk, value);\n" "> + if (err)\n" "> + dev_err(&client->dev,\n" - "> + \"unable to set PLL frequency %ud\\=\n" - "n\",\n" + "> + \"unable to set PLL frequency %ud\\n\",\n" "> + value);\n" "> + }\n" "> + if (!of_property_read_u32(np_output,\n" "> + \"spread-spectrum\", &value)) {\n" - "> + u8 flag =3D of_property_read_bool(np_output,\n" + "> + u8 flag = of_property_read_bool(np_output,\n" "> + \"spread-spectrum-center\") ? 0x80 : 0x00;\n" "> + regmap_update_bits(data->regmap,\n" "> + 0x16 + (i*CDCE925_OFFSET_PLL),\n" @@ -828,108 +793,106 @@ "> + }\n" "> +\n" "> + /* Register output clock Y1 */\n" - "> + init.ops =3D &cdce925_clk_y1_ops;\n" - "> + init.flags =3D 0;\n" - "> + init.num_parents =3D 1;\n" - "> + init.parent_names =3D &parent_name; /* Mux Y1 to input */\n" - "> + init.name =3D kasprintf(GFP_KERNEL, \"%s.Y1\", client->dev.of_node-=\n" - ">name);\n" - "> + data->clk[0].chip =3D data;\n" - "> + data->clk[0].hw.init =3D &init;\n" - "> + data->clk[0].index =3D 0;\n" - "> + data->clk[0].pdiv =3D 1;\n" - "> + clk =3D devm_clk_register(&client->dev, &data->clk[0].hw);\n" + "> + init.ops = &cdce925_clk_y1_ops;\n" + "> + init.flags = 0;\n" + "> + init.num_parents = 1;\n" + "> + init.parent_names = &parent_name; /* Mux Y1 to input */\n" + "> + init.name = kasprintf(GFP_KERNEL, \"%s.Y1\", client->dev.of_node->name);\n" + "> + data->clk[0].chip = data;\n" + "> + data->clk[0].hw.init = &init;\n" + "> + data->clk[0].index = 0;\n" + "> + data->clk[0].pdiv = 1;\n" + "> + clk = devm_clk_register(&client->dev, &data->clk[0].hw);\n" "> + kfree(init.name); /* clock framework made a copy of the name */\n" "> + if (IS_ERR(clk)) {\n" "> + dev_err(&client->dev, \"clock registration Y1 failed\\n\");\n" - "> + err =3D PTR_ERR(clk);\n" + "> + err = PTR_ERR(clk);\n" "> + goto error;\n" "> + }\n" - "> + data->dt_clk[0] =3D clk;\n" + "> + data->dt_clk[0] = clk;\n" "> +\n" "> + /* Register output clocks Y2 .. Y5*/\n" - "> + init.ops =3D &cdce925_clk_ops;\n" - "> + init.flags =3D CLK_SET_RATE_PARENT;\n" - "> + init.num_parents =3D 1;\n" - "> + for (i =3D 1; i < NUMBER_OF_OUTPUTS; ++i) {\n" - "> + init.name =3D kasprintf(GFP_KERNEL, \"%s.Y%d\",\n" + "> + init.ops = &cdce925_clk_ops;\n" + "> + init.flags = CLK_SET_RATE_PARENT;\n" + "> + init.num_parents = 1;\n" + "> + for (i = 1; i < NUMBER_OF_OUTPUTS; ++i) {\n" + "> + init.name = kasprintf(GFP_KERNEL, \"%s.Y%d\",\n" "> + client->dev.of_node->name, i+1);\n" - "> + data->clk[i].chip =3D data;\n" - "> + data->clk[i].hw.init =3D &init;\n" - "> + data->clk[i].index =3D i;\n" - "> + data->clk[i].pdiv =3D 1;\n" + "> + data->clk[i].chip = data;\n" + "> + data->clk[i].hw.init = &init;\n" + "> + data->clk[i].index = i;\n" + "> + data->clk[i].pdiv = 1;\n" "> + switch (i) {\n" "> + case 1:\n" "> + case 2:\n" "> + /* Mux Y2/3 to PLL1 */\n" - "> + init.parent_names =3D &pll_clk_name[0];\n" + "> + init.parent_names = &pll_clk_name[0];\n" "> + break;\n" "> + case 3:\n" "> + case 4:\n" "> + /* Mux Y4/5 to PLL2 */\n" - "> + init.parent_names =3D &pll_clk_name[1];\n" + "> + init.parent_names = &pll_clk_name[1];\n" "> + break;\n" "> + }\n" - "> + clk =3D devm_clk_register(&client->dev, &data->clk[i].hw);\n" - "> + kfree(init.name); /* clock framework made a copy of the n=\n" - "ame */\n" + "> + clk = devm_clk_register(&client->dev, &data->clk[i].hw);\n" + "> + kfree(init.name); /* clock framework made a copy of the name */\n" "> + if (IS_ERR(clk)) {\n" - "> + dev_err(&client->dev, \"clock registration failed\\=\n" - "n\");\n" - "> + err =3D PTR_ERR(clk);\n" + "> + dev_err(&client->dev, \"clock registration failed\\n\");\n" + "> + err = PTR_ERR(clk);\n" "> + goto error;\n" "> + }\n" - "> + data->dt_clk[i] =3D clk;\n" + "> + data->dt_clk[i] = clk;\n" "> + }\n" "> +\n" "> + /* Register the output clocks */\n" - "> + data->onecell.clk_num =3D NUMBER_OF_OUTPUTS;\n" - "> + data->onecell.clks =3D data->dt_clk;\n" - "> + err =3D of_clk_add_provider(client->dev.of_node, of_clk_src_onece=\n" - "ll_get,\n" + "> + data->onecell.clk_num = NUMBER_OF_OUTPUTS;\n" + "> + data->onecell.clks = data->dt_clk;\n" + "> + err = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,\n" "> + &data->onecell);\n" "> + if (err)\n" - "> + dev_err(&client->dev, \"unable to add OF clock provider\\n\"=\n" - ");\n" + "> + dev_err(&client->dev, \"unable to add OF clock provider\\n\");\n" "> +\n" - "> + err =3D 0;\n" + "> + err = 0;\n" "> +\n" "> +error:\n" - "> + for (i =3D 0; i < NUMBER_OF_PLLS; ++i)\n" + "> + for (i = 0; i < NUMBER_OF_PLLS; ++i)\n" "> + /* clock framework made a copy of the name */\n" "> + kfree(pll_clk_name[i]);\n" "> +\n" "> + return err;\n" "> +}\n" "> +\n" - "> +static const struct i2c_device_id cdce925_id[] =3D {\n" + "> +static const struct i2c_device_id cdce925_id[] = {\n" "> + { \"cdce925\", 0 },\n" "> + { }\n" "> +};\n" "> +MODULE_DEVICE_TABLE(i2c, cdce925_id);\n" "> +\n" - "> +static const struct of_device_id clk_cdce925_of_match[] =3D {\n" - "> + { .compatible =3D \"ti,cdce925\" },\n" + "> +static const struct of_device_id clk_cdce925_of_match[] = {\n" + "> + { .compatible = \"ti,cdce925\" },\n" "> + { },\n" "> +};\n" "> +MODULE_DEVICE_TABLE(of, clk_cdce925_of_match);\n" "> +\n" - "> +static struct i2c_driver cdce925_driver =3D {\n" - "> + .driver =3D {\n" - "> + .name =3D \"cdce925\",\n" - "> + .of_match_table =3D of_match_ptr(clk_cdce925_of_match),\n" + "> +static struct i2c_driver cdce925_driver = {\n" + "> + .driver = {\n" + "> + .name = \"cdce925\",\n" + "> + .of_match_table = of_match_ptr(clk_cdce925_of_match),\n" "> + },\n" - "> + .probe =3D cdce925_probe,\n" - "> + .id_table =3D cdce925_id,\n" + "> + .probe = cdce925_probe,\n" + "> + .id_table = cdce925_id,\n" "> +};\n" "> +module_i2c_driver(cdce925_driver);\n" "> +\n" - "> +MODULE_AUTHOR(\"Mike Looijmans <mike.looijmans@topic.nl>\");\n" + "> +MODULE_AUTHOR(\"Mike Looijmans <mike.looijmans-Oq418RWZeHk@public.gmane.org>\");\n" "> +MODULE_DESCRIPTION(\"cdce925 driver\");\n" "> +MODULE_LICENSE(\"GPL\");\n" - "> -- =\n" - "\n" + "> -- \n" "> 1.9.1\n" - >=20 + "> \n" + "--\n" + "To unsubscribe from this list: send the line \"unsubscribe devicetree\" in\n" + "the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org\n" + More majordomo info at http://vger.kernel.org/majordomo-info.html -078c15b40d12285a98512f73e6b34bf7ce99afaa4b1536adcbc5e89873b7c89b +69c5e09bdc7605ff4301ff2b86c60ff8d0adbb28e83d389b0b18efe1eac712ba
diff --git a/a/1.txt b/N2/1.txt index edd1e92..dfa9d8f 100644 --- a/a/1.txt +++ b/N2/1.txt @@ -8,8 +8,7 @@ Quoting Mike Looijmans (2015-06-02 22:25:19) > Y4 and Y5 derive from PLL2 > Given a target output frequency, the driver will set the PLL and > divider to best approximate the desired output. -> = - +> > Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl> Thanks for fixing it up. Applied to clk-next towards 4.2. @@ -22,22 +21,17 @@ Mike > Add devicetree binding documentation > v3: Remove clk-private.h and processed M.Turquette's feedback > Use "ti" prefix. Use of_clk_src_onecell_get to register. -> v4: Fix dev_dbg format warning on 64-bit systems (as suggested by Paul Bo= -lle) -> = - +> v4: Fix dev_dbg format warning on 64-bit systems (as suggested by Paul Bolle) +> > .../devicetree/bindings/clock/ti,cdce925.txt | 42 ++ > drivers/clk/Kconfig | 17 + > drivers/clk/Makefile | 1 + -> drivers/clk/clk-cdce925.c | 749 +++++++++++++++= -++++++ +> drivers/clk/clk-cdce925.c | 749 +++++++++++++++++++++ > 4 files changed, 809 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/ti,cdce925.txt > create mode 100644 drivers/clk/clk-cdce925.c -> = - -> diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Doc= -umentation/devicetree/bindings/clock/ti,cdce925.txt +> +> diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Documentation/devicetree/bindings/clock/ti,cdce925.txt > new file mode 100644 > index 0000000..4c7669a > --- /dev/null @@ -56,37 +50,32 @@ umentation/devicetree/bindings/clock/ti,cdce925.txt > +Required properties: > + - compatible: Shall be "ti,cdce925" > + - reg: I2C device address. -> + - clocks: Points to a fixed parent clock that provides the input freque= -ncy. +> + - clocks: Points to a fixed parent clock that provides the input frequency. > + - #clock-cells: From common clock bindings: Shall be 1. > + > +Optional properties: -> + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance o= -n a +> + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a > + board, or to compensate for external influences. > + -> +For both PLL1 and PLL2 an optional child node can be used to specify spr= -ead +> +For both PLL1 and PLL2 an optional child node can be used to specify spread > +spectrum clocking parameters for a board. > + - spread-spectrum: SSC mode as defined in the data sheet. -> + - spread-spectrum-center: Use "centered" mode instead of "max" mode. W= -hen -> + present, the clock runs at the requested frequency on average. Other= -wise +> + - spread-spectrum-center: Use "centered" mode instead of "max" mode. When +> + present, the clock runs at the requested frequency on average. Otherwise > + the requested frequency is the maximum value of the SCC range. > + > + > +Example: > + > + clockgen: cdce925pw@64 { -> + compatible =3D "cdce925"; -> + reg =3D <0x64>; -> + clocks =3D <&xtal_27Mhz>; -> + #clock-cells =3D <1>; -> + xtal-load-pf =3D <5>; +> + compatible = "cdce925"; +> + reg = <0x64>; +> + clocks = <&xtal_27Mhz>; +> + #clock-cells = <1>; +> + xtal-load-pf = <5>; > + /* PLL options to get SSC 1% centered */ > + PLL2 { -> + spread-spectrum =3D <4>; +> + spread-spectrum = <4>; > + spread-spectrum-center; > + }; > + }; @@ -97,8 +86,7 @@ wise > @@ -78,6 +78,23 @@ config COMMON_CLK_SI570 > This driver supports Silicon Labs 570/571/598/599 programmable > clock generators. -> = - +> > +config COMMON_CLK_CDCE925 > + tristate "Clock driver for TI CDCE925 devices" > + depends on I2C @@ -106,12 +94,9 @@ wise > + select REGMAP_I2C > + help > + ---help--- -> + This driver supports the TI CDCE925 programmable clock synthesi= -zer. -> + The chip contains two PLLs with spread-spectrum clocking suppor= -t and -> + five output dividers. The driver only supports the following se= -tup, +> + This driver supports the TI CDCE925 programmable clock synthesizer. +> + The chip contains two PLLs with spread-spectrum clocking support and +> + five output dividers. The driver only supports the following setup, > + and uses a fixed setting for the output muxes. > + Y1 is derived from the input clock > + Y2 and Y3 derive from PLL1 @@ -126,15 +111,14 @@ tup, > index 3d00c25..49d38de 100644 > --- a/drivers/clk/Makefile > +++ b/drivers/clk/Makefile -> @@ -38,6 +38,7 @@ obj-$(CONFIG_COMMON_CLK_RK808) +=3D clk-= -rk808.o -> obj-$(CONFIG_COMMON_CLK_S2MPS11) +=3D clk-s2mps11.o -> obj-$(CONFIG_COMMON_CLK_SI5351) +=3D clk-si5351.o -> obj-$(CONFIG_COMMON_CLK_SI570) +=3D clk-si570.o -> +obj-$(CONFIG_COMMON_CLK_CDCE925) +=3D clk-cdce925.o -> obj-$(CONFIG_CLK_TWL6040) +=3D clk-twl6040.o -> obj-$(CONFIG_ARCH_U300) +=3D clk-u300.o -> obj-$(CONFIG_ARCH_VT8500) +=3D clk-vt8500.o +> @@ -38,6 +38,7 @@ obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o +> obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o +> obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o +> obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o +> +obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o +> obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o +> obj-$(CONFIG_ARCH_U300) += clk-u300.o +> obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o > diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c > new file mode 100644 > index 0000000..56b870d @@ -197,8 +181,7 @@ rk808.o > + u16 m; /* 1..511 */ > + u16 n; /* 1..4095 */ > +}; -> +#define to_clk_cdce925_pll(_hw) container_of(_hw, struct clk_cdce= -925_pll, hw) +> +#define to_clk_cdce925_pll(_hw) container_of(_hw, struct clk_cdce925_pll, hw) > + > +struct clk_cdce925_chip { > + struct regmap *regmap; @@ -211,21 +194,19 @@ rk808.o > + > +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */ > + -> +static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rat= -e, +> +static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rate, > + u16 n, u16 m) > +{ -> + if ((!m || !n) || (m =3D=3D n)) -> + return parent_rate; /* In bypass mode runs at same freque= -ncy */ +> + if ((!m || !n) || (m == n)) +> + return parent_rate; /* In bypass mode runs at same frequency */ > + return mult_frac(parent_rate, (unsigned long)n, (unsigned long)m); > +} > + > +static unsigned long cdce925_pll_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ -> + /* Output frequency of PLL is Fout =3D (Fin/Pdiv)*(N/M) */ -> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw); +> + /* Output frequency of PLL is Fout = (Fin/Pdiv)*(N/M) */ +> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw); > + > + return cdce925_pll_calculate_rate(parent_rate, data->n, data->m); > +} @@ -237,34 +218,33 @@ ncy */ > + unsigned long um; > + unsigned long g; > + -> + if (rate <=3D parent_rate) { +> + if (rate <= parent_rate) { > + /* Can always deliver parent_rate in bypass mode */ -> + rate =3D parent_rate; -> + *n =3D 0; -> + *m =3D 0; +> + rate = parent_rate; +> + *n = 0; +> + *m = 0; > + } else { > + /* In PLL mode, need to apply min/max range */ > + if (rate < CDCE925_PLL_FREQUENCY_MIN) -> + rate =3D CDCE925_PLL_FREQUENCY_MIN; +> + rate = CDCE925_PLL_FREQUENCY_MIN; > + else if (rate > CDCE925_PLL_FREQUENCY_MAX) -> + rate =3D CDCE925_PLL_FREQUENCY_MAX; +> + rate = CDCE925_PLL_FREQUENCY_MAX; > + -> + g =3D gcd(rate, parent_rate); -> + um =3D parent_rate / g; -> + un =3D rate / g; -> + /* When outside hw range, reduce to fit (rounding errors)= - */ +> + g = gcd(rate, parent_rate); +> + um = parent_rate / g; +> + un = rate / g; +> + /* When outside hw range, reduce to fit (rounding errors) */ > + while ((un > 4095) || (um > 511)) { -> + un >>=3D 1; -> + um >>=3D 1; +> + un >>= 1; +> + um >>= 1; > + } -> + if (un =3D=3D 0) -> + un =3D 1; -> + if (um =3D=3D 0) -> + um =3D 1; +> + if (un == 0) +> + un = 1; +> + if (um == 0) +> + um = 1; > + -> + *n =3D un; -> + *m =3D um; +> + *n = un; +> + *m = um; > + } > +} > + @@ -280,24 +260,22 @@ ncy */ > +static int cdce925_pll_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ -> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw); +> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw); > + -> + if (!rate || (rate =3D=3D parent_rate)) { -> + data->m =3D 0; /* Bypass mode */ -> + data->n =3D 0; +> + if (!rate || (rate == parent_rate)) { +> + data->m = 0; /* Bypass mode */ +> + data->n = 0; > + return 0; > + } > + > + if ((rate < CDCE925_PLL_FREQUENCY_MIN) || > + (rate > CDCE925_PLL_FREQUENCY_MAX)) { -> + pr_debug("%s: rate %lu outside PLL range.\n", __func__, r= -ate); +> + pr_debug("%s: rate %lu outside PLL range.\n", __func__, rate); > + return -EINVAL; > + } > + > + if (rate < parent_rate) { -> + pr_debug("%s: rate %lu less than parent rate %lu.\n", __f= -unc__, +> + pr_debug("%s: rate %lu less than parent rate %lu.\n", __func__, > + rate, parent_rate); > + return -EINVAL; > + } @@ -307,17 +285,17 @@ unc__, > +} > + > + -> +/* calculate p =3D max(0, 4 - int(log2 (n/m))) */ +> +/* calculate p = max(0, 4 - int(log2 (n/m))) */ > +static u8 cdce925_pll_calc_p(u16 n, u16 m) > +{ > + u8 p; -> + u16 r =3D n / m; +> + u16 r = n / m; > + -> + if (r >=3D 16) +> + if (r >= 16) > + return 0; -> + p =3D 4; +> + p = 4; > + while (r > 1) { -> + r >>=3D 1; +> + r >>= 1; > + --p; > + } > + return p; @@ -326,15 +304,15 @@ unc__, > +/* Returns VCO range bits for VCO1_0_RANGE */ > +static u8 cdce925_pll_calc_range_bits(struct clk_hw *hw, u16 n, u16 m) > +{ -> + struct clk *parent =3D clk_get_parent(hw->clk); -> + unsigned long rate =3D clk_get_rate(parent); +> + struct clk *parent = clk_get_parent(hw->clk); +> + unsigned long rate = clk_get_rate(parent); > + -> + rate =3D mult_frac(rate, (unsigned long)n, (unsigned long)m); -> + if (rate >=3D 175000000) +> + rate = mult_frac(rate, (unsigned long)n, (unsigned long)m); +> + if (rate >= 175000000) > + return 0x3; -> + if (rate >=3D 150000000) +> + if (rate >= 150000000) > + return 0x02; -> + if (rate >=3D 125000000) +> + if (rate >= 125000000) > + return 0x01; > + return 0x00; > +} @@ -343,49 +321,48 @@ unc__, > + * may sleep */ > +static int cdce925_pll_prepare(struct clk_hw *hw) > +{ -> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw); -> + u16 n =3D data->n; -> + u16 m =3D data->m; +> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw); +> + u16 n = data->n; +> + u16 m = data->m; > + u16 r; > + u8 q; > + u8 p; > + u16 nn; > + u8 pll[4]; /* Bits are spread out over 4 byte registers */ -> + u8 reg_ofs =3D data->index * CDCE925_OFFSET_PLL; +> + u8 reg_ofs = data->index * CDCE925_OFFSET_PLL; > + unsigned i; > + -> + if ((!m || !n) || (m =3D=3D n)) { +> + if ((!m || !n) || (m == n)) { > + /* Set PLL mux to bypass mode, leave the rest as is */ > + regmap_update_bits(data->chip->regmap, > + reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80); > + } else { > + /* According to data sheet: */ -> + /* p =3D max(0, 4 - int(log2 (n/m))) */ -> + p =3D cdce925_pll_calc_p(n, m); -> + /* nn =3D n * 2^p */ -> + nn =3D n * BIT(p); -> + /* q =3D int(nn/m) */ -> + q =3D nn / m; +> + /* p = max(0, 4 - int(log2 (n/m))) */ +> + p = cdce925_pll_calc_p(n, m); +> + /* nn = n * 2^p */ +> + nn = n * BIT(p); +> + /* q = int(nn/m) */ +> + q = nn / m; > + if ((q < 16) || (1 > 64)) { -> + pr_debug("%s invalid q=3D%d\n", __func__, q); +> + pr_debug("%s invalid q=%d\n", __func__, q); > + return -EINVAL; > + } -> + r =3D nn - (m*q); +> + r = nn - (m*q); > + if (r > 511) { -> + pr_debug("%s invalid r=3D%d\n", __func__, r); +> + pr_debug("%s invalid r=%d\n", __func__, r); > + return -EINVAL; > + } -> + pr_debug("%s n=3D%d m=3D%d p=3D%d q=3D%d r=3D%d\n", __fun= -c__, +> + pr_debug("%s n=%d m=%d p=%d q=%d r=%d\n", __func__, > + n, m, p, q, r); > + /* encode into register bits */ -> + pll[0] =3D n >> 4; -> + pll[1] =3D ((n & 0x0F) << 4) | ((r >> 5) & 0x0F); -> + pll[2] =3D ((r & 0x1F) << 3) | ((q >> 3) & 0x07); -> + pll[3] =3D ((q & 0x07) << 5) | (p << 2) | +> + pll[0] = n >> 4; +> + pll[1] = ((n & 0x0F) << 4) | ((r >> 5) & 0x0F); +> + pll[2] = ((r & 0x1F) << 3) | ((q >> 3) & 0x07); +> + pll[3] = ((q & 0x07) << 5) | (p << 2) | > + cdce925_pll_calc_range_bits(hw, n, m); > + /* Write to registers */ -> + for (i =3D 0; i < ARRAY_SIZE(pll); ++i) +> + for (i = 0; i < ARRAY_SIZE(pll); ++i) > + regmap_write(data->chip->regmap, > + reg_ofs + CDCE925_PLL_MULDIV + i, pll[i]); > + /* Enable PLL */ @@ -398,24 +375,23 @@ c__, > + > +static void cdce925_pll_unprepare(struct clk_hw *hw) > +{ -> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw); -> + u8 reg_ofs =3D data->index * CDCE925_OFFSET_PLL; +> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw); +> + u8 reg_ofs = data->index * CDCE925_OFFSET_PLL; > + > + regmap_update_bits(data->chip->regmap, > + reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80); > +} > + -> +static const struct clk_ops cdce925_pll_ops =3D { -> + .prepare =3D cdce925_pll_prepare, -> + .unprepare =3D cdce925_pll_unprepare, -> + .recalc_rate =3D cdce925_pll_recalc_rate, -> + .round_rate =3D cdce925_pll_round_rate, -> + .set_rate =3D cdce925_pll_set_rate, +> +static const struct clk_ops cdce925_pll_ops = { +> + .prepare = cdce925_pll_prepare, +> + .unprepare = cdce925_pll_unprepare, +> + .recalc_rate = cdce925_pll_recalc_rate, +> + .round_rate = cdce925_pll_round_rate, +> + .set_rate = cdce925_pll_set_rate, > +}; > + > + -> +static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pd= -iv) +> +static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pdiv) > +{ > + switch (data->index) { > + case 0: @@ -459,7 +435,7 @@ iv) > + > +static int cdce925_clk_prepare(struct clk_hw *hw) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + > + cdce925_clk_set_pdiv(data, data->pdiv); > + cdce925_clk_activate(data); @@ -468,7 +444,7 @@ iv) > + > +static void cdce925_clk_unprepare(struct clk_hw *hw) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + > + /* Disable clock by setting divider to "0" */ > + cdce925_clk_set_pdiv(data, 0); @@ -477,7 +453,7 @@ iv) > +static unsigned long cdce925_clk_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + > + if (data->pdiv) > + return parent_rate / data->pdiv; @@ -491,12 +467,12 @@ iv) > + > + if (!rate) > + return 0; -> + if (rate >=3D parent_rate) +> + if (rate >= parent_rate) > + return 1; > + -> + divider =3D DIV_ROUND_CLOSEST(parent_rate, rate); +> + divider = DIV_ROUND_CLOSEST(parent_rate, rate); > + if (divider > 0x7F) -> + divider =3D 0x7F; +> + divider = 0x7F; > + > + return (u16)divider; > +} @@ -504,42 +480,40 @@ iv) > +static unsigned long cdce925_clk_best_parent_rate( > + struct clk_hw *hw, unsigned long rate) > +{ -> + struct clk *pll =3D clk_get_parent(hw->clk); -> + struct clk *root =3D clk_get_parent(pll); -> + unsigned long root_rate =3D clk_get_rate(root); -> + unsigned long best_rate_error =3D rate; +> + struct clk *pll = clk_get_parent(hw->clk); +> + struct clk *root = clk_get_parent(pll); +> + unsigned long root_rate = clk_get_rate(root); +> + unsigned long best_rate_error = rate; > + u16 pdiv_min; > + u16 pdiv_max; > + u16 pdiv_best; > + u16 pdiv_now; > + -> + if (root_rate % rate =3D=3D 0) +> + if (root_rate % rate == 0) > + return root_rate; /* Don't need the PLL, use bypass */ > + -> + pdiv_min =3D (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN= -, rate)); -> + pdiv_max =3D (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate); +> + pdiv_min = (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN, rate)); +> + pdiv_max = (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate); > + > + if (pdiv_min > pdiv_max) > + return 0; /* No can do? */ > + -> + pdiv_best =3D pdiv_min; -> + for (pdiv_now =3D pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) { -> + unsigned long target_rate =3D rate * pdiv_now; -> + long pll_rate =3D clk_round_rate(pll, target_rate); +> + pdiv_best = pdiv_min; +> + for (pdiv_now = pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) { +> + unsigned long target_rate = rate * pdiv_now; +> + long pll_rate = clk_round_rate(pll, target_rate); > + unsigned long actual_rate; > + unsigned long rate_error; > + -> + if (pll_rate <=3D 0) +> + if (pll_rate <= 0) > + continue; -> + actual_rate =3D pll_rate / pdiv_now; -> + rate_error =3D abs((long)actual_rate - (long)rate); +> + actual_rate = pll_rate / pdiv_now; +> + rate_error = abs((long)actual_rate - (long)rate); > + if (rate_error < best_rate_error) { -> + pdiv_best =3D pdiv_now; -> + best_rate_error =3D rate_error; +> + pdiv_best = pdiv_now; +> + best_rate_error = rate_error; > + } -> + /* TODO: Consider PLL frequency based on smaller n/m valu= -es +> + /* TODO: Consider PLL frequency based on smaller n/m values > + * and pick the better one if the error is equal */ > + } > + @@ -549,13 +523,13 @@ es > +static long cdce925_clk_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *parent_rate) > +{ -> + unsigned long l_parent_rate =3D *parent_rate; -> + u16 divider =3D cdce925_calc_divider(rate, l_parent_rate); +> + unsigned long l_parent_rate = *parent_rate; +> + u16 divider = cdce925_calc_divider(rate, l_parent_rate); > + -> + if (l_parent_rate / divider !=3D rate) { -> + l_parent_rate =3D cdce925_clk_best_parent_rate(hw, rate); -> + divider =3D cdce925_calc_divider(rate, l_parent_rate); -> + *parent_rate =3D l_parent_rate; +> + if (l_parent_rate / divider != rate) { +> + l_parent_rate = cdce925_clk_best_parent_rate(hw, rate); +> + divider = cdce925_calc_divider(rate, l_parent_rate); +> + *parent_rate = l_parent_rate; > + } > + > + if (divider) @@ -566,19 +540,19 @@ es > +static int cdce925_clk_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + -> + data->pdiv =3D cdce925_calc_divider(rate, parent_rate); +> + data->pdiv = cdce925_calc_divider(rate, parent_rate); > + > + return 0; > +} > + -> +static const struct clk_ops cdce925_clk_ops =3D { -> + .prepare =3D cdce925_clk_prepare, -> + .unprepare =3D cdce925_clk_unprepare, -> + .recalc_rate =3D cdce925_clk_recalc_rate, -> + .round_rate =3D cdce925_clk_round_rate, -> + .set_rate =3D cdce925_clk_set_rate, +> +static const struct clk_ops cdce925_clk_ops = { +> + .prepare = cdce925_clk_prepare, +> + .unprepare = cdce925_clk_unprepare, +> + .recalc_rate = cdce925_clk_recalc_rate, +> + .round_rate = cdce925_clk_round_rate, +> + .set_rate = cdce925_clk_set_rate, > +}; > + > + @@ -589,22 +563,21 @@ es > + > + if (!rate) > + return 0; -> + if (rate >=3D parent_rate) +> + if (rate >= parent_rate) > + return 1; > + -> + divider =3D DIV_ROUND_CLOSEST(parent_rate, rate); +> + divider = DIV_ROUND_CLOSEST(parent_rate, rate); > + if (divider > 0x3FF) /* Y1 has 10-bit divider */ -> + divider =3D 0x3FF; +> + divider = 0x3FF; > + > + return (u16)divider; > +} > + -> +static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long r= -ate, +> +static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *parent_rate) > +{ -> + unsigned long l_parent_rate =3D *parent_rate; -> + u16 divider =3D cdce925_y1_calc_divider(rate, l_parent_rate); +> + unsigned long l_parent_rate = *parent_rate; +> + u16 divider = cdce925_y1_calc_divider(rate, l_parent_rate); > + > + if (divider) > + return (long)(l_parent_rate / divider); @@ -614,28 +587,28 @@ ate, > +static int cdce925_clk_y1_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ -> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw); +> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw); > + -> + data->pdiv =3D cdce925_y1_calc_divider(rate, parent_rate); +> + data->pdiv = cdce925_y1_calc_divider(rate, parent_rate); > + > + return 0; > +} > + -> +static const struct clk_ops cdce925_clk_y1_ops =3D { -> + .prepare =3D cdce925_clk_prepare, -> + .unprepare =3D cdce925_clk_unprepare, -> + .recalc_rate =3D cdce925_clk_recalc_rate, -> + .round_rate =3D cdce925_clk_y1_round_rate, -> + .set_rate =3D cdce925_clk_y1_set_rate, +> +static const struct clk_ops cdce925_clk_y1_ops = { +> + .prepare = cdce925_clk_prepare, +> + .unprepare = cdce925_clk_unprepare, +> + .recalc_rate = cdce925_clk_recalc_rate, +> + .round_rate = cdce925_clk_y1_round_rate, +> + .set_rate = cdce925_clk_y1_set_rate, > +}; > + > + -> +static struct regmap_config cdce925_regmap_config =3D { -> + .name =3D "configuration0", -> + .reg_bits =3D 8, -> + .val_bits =3D 8, -> + .cache_type =3D REGCACHE_RBTREE, -> + .max_register =3D 0x2F, +> +static struct regmap_config cdce925_regmap_config = { +> + .name = "configuration0", +> + .reg_bits = 8, +> + .val_bits = 8, +> + .cache_type = REGCACHE_RBTREE, +> + .max_register = 0x2F, > +}; > + > +#define CDCE925_I2C_COMMAND_BLOCK_TRANSFER 0x00 @@ -644,24 +617,23 @@ ate, > +static int cdce925_regmap_i2c_write( > + void *context, const void *data, size_t count) > +{ -> + struct device *dev =3D context; -> + struct i2c_client *i2c =3D to_i2c_client(dev); +> + struct device *dev = context; +> + struct i2c_client *i2c = to_i2c_client(dev); > + int ret; > + u8 reg_data[2]; > + -> + if (count !=3D 2) +> + if (count != 2) > + return -ENOTSUPP; > + > + /* First byte is command code */ -> + reg_data[0] =3D CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[= -0]; -> + reg_data[1] =3D ((u8 *)data)[1]; +> + reg_data[0] = CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[0]; +> + reg_data[1] = ((u8 *)data)[1]; > + > + dev_dbg(&i2c->dev, "%s(%zu) %#x %#x\n", __func__, count, > + reg_data[0], reg_data[1]); > + -> + ret =3D i2c_master_send(i2c, reg_data, count); -> + if (likely(ret =3D=3D count)) +> + ret = i2c_master_send(i2c, reg_data, count); +> + if (likely(ret == count)) > + return 0; > + else if (ret < 0) > + return ret; @@ -672,41 +644,38 @@ ate, > +static int cdce925_regmap_i2c_read(void *context, > + const void *reg, size_t reg_size, void *val, size_t val_size) > +{ -> + struct device *dev =3D context; -> + struct i2c_client *i2c =3D to_i2c_client(dev); +> + struct device *dev = context; +> + struct i2c_client *i2c = to_i2c_client(dev); > + struct i2c_msg xfer[2]; > + int ret; > + u8 reg_data[2]; > + -> + if (reg_size !=3D 1) +> + if (reg_size != 1) > + return -ENOTSUPP; > + -> + xfer[0].addr =3D i2c->addr; -> + xfer[0].flags =3D 0; -> + xfer[0].buf =3D reg_data; -> + if (val_size =3D=3D 1) { -> + reg_data[0] =3D -> + CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0= -]; -> + xfer[0].len =3D 1; +> + xfer[0].addr = i2c->addr; +> + xfer[0].flags = 0; +> + xfer[0].buf = reg_data; +> + if (val_size == 1) { +> + reg_data[0] = +> + CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0]; +> + xfer[0].len = 1; > + } else { -> + reg_data[0] =3D -> + CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[= -0]; -> + reg_data[1] =3D val_size; -> + xfer[0].len =3D 2; +> + reg_data[0] = +> + CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[0]; +> + reg_data[1] = val_size; +> + xfer[0].len = 2; > + } > + -> + xfer[1].addr =3D i2c->addr; -> + xfer[1].flags =3D I2C_M_RD; -> + xfer[1].len =3D val_size; -> + xfer[1].buf =3D val; +> + xfer[1].addr = i2c->addr; +> + xfer[1].flags = I2C_M_RD; +> + xfer[1].len = val_size; +> + xfer[1].buf = val; > + -> + ret =3D i2c_transfer(i2c->adapter, xfer, 2); -> + if (likely(ret =3D=3D 2)) { +> + ret = i2c_transfer(i2c->adapter, xfer, 2); +> + if (likely(ret == 2)) { > + dev_dbg(&i2c->dev, "%s(%zu, %u) %#x %#x\n", __func__, -> + reg_size, val_size, reg_data[0], *((u8 *)= -val)); +> + reg_size, val_size, reg_data[0], *((u8 *)val)); > + return 0; > + } else if (ret < 0) > + return ret; @@ -716,18 +685,18 @@ val)); > + > +/* The CDCE925 uses a funky way to read/write registers. Bulk mode is > + * just weird, so just use the single byte mode exclusively. */ -> +static struct regmap_bus regmap_cdce925_bus =3D { -> + .write =3D cdce925_regmap_i2c_write, -> + .read =3D cdce925_regmap_i2c_read, +> +static struct regmap_bus regmap_cdce925_bus = { +> + .write = cdce925_regmap_i2c_write, +> + .read = cdce925_regmap_i2c_read, > +}; > + > +static int cdce925_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct clk_cdce925_chip *data; -> + struct device_node *node =3D client->dev.of_node; +> + struct device_node *node = client->dev.of_node; > + const char *parent_name; -> + const char *pll_clk_name[NUMBER_OF_PLLS] =3D {NULL,}; +> + const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,}; > + struct clk_init_data init; > + struct clk *clk; > + u32 value; @@ -737,29 +706,27 @@ val)); > + char child_name[6]; > + > + dev_dbg(&client->dev, "%s\n", __func__); -> + data =3D devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); +> + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + -> + data->i2c_client =3D client; -> + data->regmap =3D devm_regmap_init(&client->dev, ®map_cdce925_b= -us, +> + data->i2c_client = client; +> + data->regmap = devm_regmap_init(&client->dev, ®map_cdce925_bus, > + &client->dev, &cdce925_regmap_config); > + if (IS_ERR(data->regmap)) { -> + dev_err(&client->dev, "failed to allocate register map\n"= -); +> + dev_err(&client->dev, "failed to allocate register map\n"); > + return PTR_ERR(data->regmap); > + } > + i2c_set_clientdata(client, data); > + -> + parent_name =3D of_clk_get_parent_name(node, 0); +> + parent_name = of_clk_get_parent_name(node, 0); > + if (!parent_name) { > + dev_err(&client->dev, "missing parent clock\n"); > + return -ENODEV; > + } > + dev_dbg(&client->dev, "parent is: %s\n", parent_name); > + -> + if (of_property_read_u32(node, "xtal-load-pf", &value) =3D=3D 0) +> + if (of_property_read_u32(node, "xtal-load-pf", &value) == 0) > + regmap_write(data->regmap, > + CDCE925_REG_XCSEL, (value << 3) & 0xF8); > + /* PWDN bit */ @@ -768,42 +735,40 @@ us, > + /* Set input source for Y1 to be the XTAL */ > + regmap_update_bits(data->regmap, 0x02, BIT(7), 0); > + -> + init.ops =3D &cdce925_pll_ops; -> + init.flags =3D 0; -> + init.parent_names =3D &parent_name; -> + init.num_parents =3D parent_name ? 1 : 0; +> + init.ops = &cdce925_pll_ops; +> + init.flags = 0; +> + init.parent_names = &parent_name; +> + init.num_parents = parent_name ? 1 : 0; > + > + /* Register PLL clocks */ -> + for (i =3D 0; i < NUMBER_OF_PLLS; ++i) { -> + pll_clk_name[i] =3D kasprintf(GFP_KERNEL, "%s.pll%d", +> + for (i = 0; i < NUMBER_OF_PLLS; ++i) { +> + pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d", > + client->dev.of_node->name, i); -> + init.name =3D pll_clk_name[i]; -> + data->pll[i].chip =3D data; -> + data->pll[i].hw.init =3D &init; -> + data->pll[i].index =3D i; -> + clk =3D devm_clk_register(&client->dev, &data->pll[i].hw); +> + init.name = pll_clk_name[i]; +> + data->pll[i].chip = data; +> + data->pll[i].hw.init = &init; +> + data->pll[i].index = i; +> + clk = devm_clk_register(&client->dev, &data->pll[i].hw); > + if (IS_ERR(clk)) { -> + dev_err(&client->dev, "Failed register PLL %d\n",= - i); -> + err =3D PTR_ERR(clk); +> + dev_err(&client->dev, "Failed register PLL %d\n", i); +> + err = PTR_ERR(clk); > + goto error; > + } > + sprintf(child_name, "PLL%d", i+1); -> + np_output =3D of_get_child_by_name(node, child_name); +> + np_output = of_get_child_by_name(node, child_name); > + if (!np_output) > + continue; > + if (!of_property_read_u32(np_output, > + "clock-frequency", &value)) { -> + err =3D clk_set_rate(clk, value); +> + err = clk_set_rate(clk, value); > + if (err) > + dev_err(&client->dev, -> + "unable to set PLL frequency %ud\= -n", +> + "unable to set PLL frequency %ud\n", > + value); > + } > + if (!of_property_read_u32(np_output, > + "spread-spectrum", &value)) { -> + u8 flag =3D of_property_read_bool(np_output, +> + u8 flag = of_property_read_bool(np_output, > + "spread-spectrum-center") ? 0x80 : 0x00; > + regmap_update_bits(data->regmap, > + 0x16 + (i*CDCE925_OFFSET_PLL), @@ -815,106 +780,100 @@ n", > + } > + > + /* Register output clock Y1 */ -> + init.ops =3D &cdce925_clk_y1_ops; -> + init.flags =3D 0; -> + init.num_parents =3D 1; -> + init.parent_names =3D &parent_name; /* Mux Y1 to input */ -> + init.name =3D kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node-= ->name); -> + data->clk[0].chip =3D data; -> + data->clk[0].hw.init =3D &init; -> + data->clk[0].index =3D 0; -> + data->clk[0].pdiv =3D 1; -> + clk =3D devm_clk_register(&client->dev, &data->clk[0].hw); +> + init.ops = &cdce925_clk_y1_ops; +> + init.flags = 0; +> + init.num_parents = 1; +> + init.parent_names = &parent_name; /* Mux Y1 to input */ +> + init.name = kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node->name); +> + data->clk[0].chip = data; +> + data->clk[0].hw.init = &init; +> + data->clk[0].index = 0; +> + data->clk[0].pdiv = 1; +> + clk = devm_clk_register(&client->dev, &data->clk[0].hw); > + kfree(init.name); /* clock framework made a copy of the name */ > + if (IS_ERR(clk)) { > + dev_err(&client->dev, "clock registration Y1 failed\n"); -> + err =3D PTR_ERR(clk); +> + err = PTR_ERR(clk); > + goto error; > + } -> + data->dt_clk[0] =3D clk; +> + data->dt_clk[0] = clk; > + > + /* Register output clocks Y2 .. Y5*/ -> + init.ops =3D &cdce925_clk_ops; -> + init.flags =3D CLK_SET_RATE_PARENT; -> + init.num_parents =3D 1; -> + for (i =3D 1; i < NUMBER_OF_OUTPUTS; ++i) { -> + init.name =3D kasprintf(GFP_KERNEL, "%s.Y%d", +> + init.ops = &cdce925_clk_ops; +> + init.flags = CLK_SET_RATE_PARENT; +> + init.num_parents = 1; +> + for (i = 1; i < NUMBER_OF_OUTPUTS; ++i) { +> + init.name = kasprintf(GFP_KERNEL, "%s.Y%d", > + client->dev.of_node->name, i+1); -> + data->clk[i].chip =3D data; -> + data->clk[i].hw.init =3D &init; -> + data->clk[i].index =3D i; -> + data->clk[i].pdiv =3D 1; +> + data->clk[i].chip = data; +> + data->clk[i].hw.init = &init; +> + data->clk[i].index = i; +> + data->clk[i].pdiv = 1; > + switch (i) { > + case 1: > + case 2: > + /* Mux Y2/3 to PLL1 */ -> + init.parent_names =3D &pll_clk_name[0]; +> + init.parent_names = &pll_clk_name[0]; > + break; > + case 3: > + case 4: > + /* Mux Y4/5 to PLL2 */ -> + init.parent_names =3D &pll_clk_name[1]; +> + init.parent_names = &pll_clk_name[1]; > + break; > + } -> + clk =3D devm_clk_register(&client->dev, &data->clk[i].hw); -> + kfree(init.name); /* clock framework made a copy of the n= -ame */ +> + clk = devm_clk_register(&client->dev, &data->clk[i].hw); +> + kfree(init.name); /* clock framework made a copy of the name */ > + if (IS_ERR(clk)) { -> + dev_err(&client->dev, "clock registration failed\= -n"); -> + err =3D PTR_ERR(clk); +> + dev_err(&client->dev, "clock registration failed\n"); +> + err = PTR_ERR(clk); > + goto error; > + } -> + data->dt_clk[i] =3D clk; +> + data->dt_clk[i] = clk; > + } > + > + /* Register the output clocks */ -> + data->onecell.clk_num =3D NUMBER_OF_OUTPUTS; -> + data->onecell.clks =3D data->dt_clk; -> + err =3D of_clk_add_provider(client->dev.of_node, of_clk_src_onece= -ll_get, +> + data->onecell.clk_num = NUMBER_OF_OUTPUTS; +> + data->onecell.clks = data->dt_clk; +> + err = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get, > + &data->onecell); > + if (err) -> + dev_err(&client->dev, "unable to add OF clock provider\n"= -); +> + dev_err(&client->dev, "unable to add OF clock provider\n"); > + -> + err =3D 0; +> + err = 0; > + > +error: -> + for (i =3D 0; i < NUMBER_OF_PLLS; ++i) +> + for (i = 0; i < NUMBER_OF_PLLS; ++i) > + /* clock framework made a copy of the name */ > + kfree(pll_clk_name[i]); > + > + return err; > +} > + -> +static const struct i2c_device_id cdce925_id[] =3D { +> +static const struct i2c_device_id cdce925_id[] = { > + { "cdce925", 0 }, > + { } > +}; > +MODULE_DEVICE_TABLE(i2c, cdce925_id); > + -> +static const struct of_device_id clk_cdce925_of_match[] =3D { -> + { .compatible =3D "ti,cdce925" }, +> +static const struct of_device_id clk_cdce925_of_match[] = { +> + { .compatible = "ti,cdce925" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, clk_cdce925_of_match); > + -> +static struct i2c_driver cdce925_driver =3D { -> + .driver =3D { -> + .name =3D "cdce925", -> + .of_match_table =3D of_match_ptr(clk_cdce925_of_match), +> +static struct i2c_driver cdce925_driver = { +> + .driver = { +> + .name = "cdce925", +> + .of_match_table = of_match_ptr(clk_cdce925_of_match), > + }, -> + .probe =3D cdce925_probe, -> + .id_table =3D cdce925_id, +> + .probe = cdce925_probe, +> + .id_table = cdce925_id, > +}; > +module_i2c_driver(cdce925_driver); > + > +MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>"); > +MODULE_DESCRIPTION("cdce925 driver"); > +MODULE_LICENSE("GPL"); -> -- = - +> -- > 1.9.1 ->=20 +> diff --git a/a/content_digest b/N2/content_digest index 1a954f2..aa2d7e1 100644 --- a/a/content_digest +++ b/N2/content_digest @@ -21,8 +21,7 @@ "> Y4 and Y5 derive from PLL2\n" "> Given a target output frequency, the driver will set the PLL and\n" "> divider to best approximate the desired output.\n" - "> =\n" - "\n" + "> \n" "> Signed-off-by: Mike Looijmans <mike.looijmans@topic.nl>\n" "\n" "Thanks for fixing it up. Applied to clk-next towards 4.2.\n" @@ -35,22 +34,17 @@ "> Add devicetree binding documentation\n" "> v3: Remove clk-private.h and processed M.Turquette's feedback\n" "> Use \"ti\" prefix. Use of_clk_src_onecell_get to register.\n" - "> v4: Fix dev_dbg format warning on 64-bit systems (as suggested by Paul Bo=\n" - "lle)\n" - "> =\n" - "\n" + "> v4: Fix dev_dbg format warning on 64-bit systems (as suggested by Paul Bolle)\n" + "> \n" "> .../devicetree/bindings/clock/ti,cdce925.txt | 42 ++\n" "> drivers/clk/Kconfig | 17 +\n" "> drivers/clk/Makefile | 1 +\n" - "> drivers/clk/clk-cdce925.c | 749 +++++++++++++++=\n" - "++++++\n" + "> drivers/clk/clk-cdce925.c | 749 +++++++++++++++++++++\n" "> 4 files changed, 809 insertions(+)\n" "> create mode 100644 Documentation/devicetree/bindings/clock/ti,cdce925.txt\n" "> create mode 100644 drivers/clk/clk-cdce925.c\n" - "> =\n" - "\n" - "> diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Doc=\n" - "umentation/devicetree/bindings/clock/ti,cdce925.txt\n" + "> \n" + "> diff --git a/Documentation/devicetree/bindings/clock/ti,cdce925.txt b/Documentation/devicetree/bindings/clock/ti,cdce925.txt\n" "> new file mode 100644\n" "> index 0000000..4c7669a\n" "> --- /dev/null\n" @@ -69,37 +63,32 @@ "> +Required properties:\n" "> + - compatible: Shall be \"ti,cdce925\"\n" "> + - reg: I2C device address.\n" - "> + - clocks: Points to a fixed parent clock that provides the input freque=\n" - "ncy.\n" + "> + - clocks: Points to a fixed parent clock that provides the input frequency.\n" "> + - #clock-cells: From common clock bindings: Shall be 1.\n" "> +\n" "> +Optional properties:\n" - "> + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance o=\n" - "n a\n" + "> + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a\n" "> + board, or to compensate for external influences.\n" "> +\n" - "> +For both PLL1 and PLL2 an optional child node can be used to specify spr=\n" - "ead\n" + "> +For both PLL1 and PLL2 an optional child node can be used to specify spread\n" "> +spectrum clocking parameters for a board.\n" "> + - spread-spectrum: SSC mode as defined in the data sheet.\n" - "> + - spread-spectrum-center: Use \"centered\" mode instead of \"max\" mode. W=\n" - "hen\n" - "> + present, the clock runs at the requested frequency on average. Other=\n" - "wise\n" + "> + - spread-spectrum-center: Use \"centered\" mode instead of \"max\" mode. When\n" + "> + present, the clock runs at the requested frequency on average. Otherwise\n" "> + the requested frequency is the maximum value of the SCC range.\n" "> +\n" "> +\n" "> +Example:\n" "> +\n" "> + clockgen: cdce925pw@64 {\n" - "> + compatible =3D \"cdce925\";\n" - "> + reg =3D <0x64>;\n" - "> + clocks =3D <&xtal_27Mhz>;\n" - "> + #clock-cells =3D <1>;\n" - "> + xtal-load-pf =3D <5>;\n" + "> + compatible = \"cdce925\";\n" + "> + reg = <0x64>;\n" + "> + clocks = <&xtal_27Mhz>;\n" + "> + #clock-cells = <1>;\n" + "> + xtal-load-pf = <5>;\n" "> + /* PLL options to get SSC 1% centered */\n" "> + PLL2 {\n" - "> + spread-spectrum =3D <4>;\n" + "> + spread-spectrum = <4>;\n" "> + spread-spectrum-center;\n" "> + };\n" "> + };\n" @@ -110,8 +99,7 @@ "> @@ -78,6 +78,23 @@ config COMMON_CLK_SI570\n" "> This driver supports Silicon Labs 570/571/598/599 programmable\n" "> clock generators.\n" - "> =\n" - "\n" + "> \n" "> +config COMMON_CLK_CDCE925\n" "> + tristate \"Clock driver for TI CDCE925 devices\"\n" "> + depends on I2C\n" @@ -119,12 +107,9 @@ "> + select REGMAP_I2C\n" "> + help\n" "> + ---help---\n" - "> + This driver supports the TI CDCE925 programmable clock synthesi=\n" - "zer.\n" - "> + The chip contains two PLLs with spread-spectrum clocking suppor=\n" - "t and\n" - "> + five output dividers. The driver only supports the following se=\n" - "tup,\n" + "> + This driver supports the TI CDCE925 programmable clock synthesizer.\n" + "> + The chip contains two PLLs with spread-spectrum clocking support and\n" + "> + five output dividers. The driver only supports the following setup,\n" "> + and uses a fixed setting for the output muxes.\n" "> + Y1 is derived from the input clock\n" "> + Y2 and Y3 derive from PLL1\n" @@ -139,15 +124,14 @@ "> index 3d00c25..49d38de 100644\n" "> --- a/drivers/clk/Makefile\n" "> +++ b/drivers/clk/Makefile\n" - "> @@ -38,6 +38,7 @@ obj-$(CONFIG_COMMON_CLK_RK808) +=3D clk-=\n" - "rk808.o\n" - "> obj-$(CONFIG_COMMON_CLK_S2MPS11) +=3D clk-s2mps11.o\n" - "> obj-$(CONFIG_COMMON_CLK_SI5351) +=3D clk-si5351.o\n" - "> obj-$(CONFIG_COMMON_CLK_SI570) +=3D clk-si570.o\n" - "> +obj-$(CONFIG_COMMON_CLK_CDCE925) +=3D clk-cdce925.o\n" - "> obj-$(CONFIG_CLK_TWL6040) +=3D clk-twl6040.o\n" - "> obj-$(CONFIG_ARCH_U300) +=3D clk-u300.o\n" - "> obj-$(CONFIG_ARCH_VT8500) +=3D clk-vt8500.o\n" + "> @@ -38,6 +38,7 @@ obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o\n" + "> obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o\n" + "> obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o\n" + "> obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o\n" + "> +obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o\n" + "> obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o\n" + "> obj-$(CONFIG_ARCH_U300) += clk-u300.o\n" + "> obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o\n" "> diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c\n" "> new file mode 100644\n" "> index 0000000..56b870d\n" @@ -210,8 +194,7 @@ "> + u16 m; /* 1..511 */\n" "> + u16 n; /* 1..4095 */\n" "> +};\n" - "> +#define to_clk_cdce925_pll(_hw) container_of(_hw, struct clk_cdce=\n" - "925_pll, hw)\n" + "> +#define to_clk_cdce925_pll(_hw) container_of(_hw, struct clk_cdce925_pll, hw)\n" "> +\n" "> +struct clk_cdce925_chip {\n" "> + struct regmap *regmap;\n" @@ -224,21 +207,19 @@ "> +\n" "> +/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */\n" "> +\n" - "> +static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rat=\n" - "e,\n" + "> +static unsigned long cdce925_pll_calculate_rate(unsigned long parent_rate,\n" "> + u16 n, u16 m)\n" "> +{\n" - "> + if ((!m || !n) || (m =3D=3D n))\n" - "> + return parent_rate; /* In bypass mode runs at same freque=\n" - "ncy */\n" + "> + if ((!m || !n) || (m == n))\n" + "> + return parent_rate; /* In bypass mode runs at same frequency */\n" "> + return mult_frac(parent_rate, (unsigned long)n, (unsigned long)m);\n" "> +}\n" "> +\n" "> +static unsigned long cdce925_pll_recalc_rate(struct clk_hw *hw,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + /* Output frequency of PLL is Fout =3D (Fin/Pdiv)*(N/M) */\n" - "> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw);\n" + "> + /* Output frequency of PLL is Fout = (Fin/Pdiv)*(N/M) */\n" + "> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);\n" "> +\n" "> + return cdce925_pll_calculate_rate(parent_rate, data->n, data->m);\n" "> +}\n" @@ -250,34 +231,33 @@ "> + unsigned long um;\n" "> + unsigned long g;\n" "> +\n" - "> + if (rate <=3D parent_rate) {\n" + "> + if (rate <= parent_rate) {\n" "> + /* Can always deliver parent_rate in bypass mode */\n" - "> + rate =3D parent_rate;\n" - "> + *n =3D 0;\n" - "> + *m =3D 0;\n" + "> + rate = parent_rate;\n" + "> + *n = 0;\n" + "> + *m = 0;\n" "> + } else {\n" "> + /* In PLL mode, need to apply min/max range */\n" "> + if (rate < CDCE925_PLL_FREQUENCY_MIN)\n" - "> + rate =3D CDCE925_PLL_FREQUENCY_MIN;\n" + "> + rate = CDCE925_PLL_FREQUENCY_MIN;\n" "> + else if (rate > CDCE925_PLL_FREQUENCY_MAX)\n" - "> + rate =3D CDCE925_PLL_FREQUENCY_MAX;\n" + "> + rate = CDCE925_PLL_FREQUENCY_MAX;\n" "> +\n" - "> + g =3D gcd(rate, parent_rate);\n" - "> + um =3D parent_rate / g;\n" - "> + un =3D rate / g;\n" - "> + /* When outside hw range, reduce to fit (rounding errors)=\n" - " */\n" + "> + g = gcd(rate, parent_rate);\n" + "> + um = parent_rate / g;\n" + "> + un = rate / g;\n" + "> + /* When outside hw range, reduce to fit (rounding errors) */\n" "> + while ((un > 4095) || (um > 511)) {\n" - "> + un >>=3D 1;\n" - "> + um >>=3D 1;\n" + "> + un >>= 1;\n" + "> + um >>= 1;\n" "> + }\n" - "> + if (un =3D=3D 0)\n" - "> + un =3D 1;\n" - "> + if (um =3D=3D 0)\n" - "> + um =3D 1;\n" + "> + if (un == 0)\n" + "> + un = 1;\n" + "> + if (um == 0)\n" + "> + um = 1;\n" "> +\n" - "> + *n =3D un;\n" - "> + *m =3D um;\n" + "> + *n = un;\n" + "> + *m = um;\n" "> + }\n" "> +}\n" "> +\n" @@ -293,24 +273,22 @@ "> +static int cdce925_pll_set_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw);\n" + "> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);\n" "> +\n" - "> + if (!rate || (rate =3D=3D parent_rate)) {\n" - "> + data->m =3D 0; /* Bypass mode */\n" - "> + data->n =3D 0;\n" + "> + if (!rate || (rate == parent_rate)) {\n" + "> + data->m = 0; /* Bypass mode */\n" + "> + data->n = 0;\n" "> + return 0;\n" "> + }\n" "> +\n" "> + if ((rate < CDCE925_PLL_FREQUENCY_MIN) ||\n" "> + (rate > CDCE925_PLL_FREQUENCY_MAX)) {\n" - "> + pr_debug(\"%s: rate %lu outside PLL range.\\n\", __func__, r=\n" - "ate);\n" + "> + pr_debug(\"%s: rate %lu outside PLL range.\\n\", __func__, rate);\n" "> + return -EINVAL;\n" "> + }\n" "> +\n" "> + if (rate < parent_rate) {\n" - "> + pr_debug(\"%s: rate %lu less than parent rate %lu.\\n\", __f=\n" - "unc__,\n" + "> + pr_debug(\"%s: rate %lu less than parent rate %lu.\\n\", __func__,\n" "> + rate, parent_rate);\n" "> + return -EINVAL;\n" "> + }\n" @@ -320,17 +298,17 @@ "> +}\n" "> +\n" "> +\n" - "> +/* calculate p =3D max(0, 4 - int(log2 (n/m))) */\n" + "> +/* calculate p = max(0, 4 - int(log2 (n/m))) */\n" "> +static u8 cdce925_pll_calc_p(u16 n, u16 m)\n" "> +{\n" "> + u8 p;\n" - "> + u16 r =3D n / m;\n" + "> + u16 r = n / m;\n" "> +\n" - "> + if (r >=3D 16)\n" + "> + if (r >= 16)\n" "> + return 0;\n" - "> + p =3D 4;\n" + "> + p = 4;\n" "> + while (r > 1) {\n" - "> + r >>=3D 1;\n" + "> + r >>= 1;\n" "> + --p;\n" "> + }\n" "> + return p;\n" @@ -339,15 +317,15 @@ "> +/* Returns VCO range bits for VCO1_0_RANGE */\n" "> +static u8 cdce925_pll_calc_range_bits(struct clk_hw *hw, u16 n, u16 m)\n" "> +{\n" - "> + struct clk *parent =3D clk_get_parent(hw->clk);\n" - "> + unsigned long rate =3D clk_get_rate(parent);\n" + "> + struct clk *parent = clk_get_parent(hw->clk);\n" + "> + unsigned long rate = clk_get_rate(parent);\n" "> +\n" - "> + rate =3D mult_frac(rate, (unsigned long)n, (unsigned long)m);\n" - "> + if (rate >=3D 175000000)\n" + "> + rate = mult_frac(rate, (unsigned long)n, (unsigned long)m);\n" + "> + if (rate >= 175000000)\n" "> + return 0x3;\n" - "> + if (rate >=3D 150000000)\n" + "> + if (rate >= 150000000)\n" "> + return 0x02;\n" - "> + if (rate >=3D 125000000)\n" + "> + if (rate >= 125000000)\n" "> + return 0x01;\n" "> + return 0x00;\n" "> +}\n" @@ -356,49 +334,48 @@ "> + * may sleep */\n" "> +static int cdce925_pll_prepare(struct clk_hw *hw)\n" "> +{\n" - "> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw);\n" - "> + u16 n =3D data->n;\n" - "> + u16 m =3D data->m;\n" + "> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);\n" + "> + u16 n = data->n;\n" + "> + u16 m = data->m;\n" "> + u16 r;\n" "> + u8 q;\n" "> + u8 p;\n" "> + u16 nn;\n" "> + u8 pll[4]; /* Bits are spread out over 4 byte registers */\n" - "> + u8 reg_ofs =3D data->index * CDCE925_OFFSET_PLL;\n" + "> + u8 reg_ofs = data->index * CDCE925_OFFSET_PLL;\n" "> + unsigned i;\n" "> +\n" - "> + if ((!m || !n) || (m =3D=3D n)) {\n" + "> + if ((!m || !n) || (m == n)) {\n" "> + /* Set PLL mux to bypass mode, leave the rest as is */\n" "> + regmap_update_bits(data->chip->regmap,\n" "> + reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80);\n" "> + } else {\n" "> + /* According to data sheet: */\n" - "> + /* p =3D max(0, 4 - int(log2 (n/m))) */\n" - "> + p =3D cdce925_pll_calc_p(n, m);\n" - "> + /* nn =3D n * 2^p */\n" - "> + nn =3D n * BIT(p);\n" - "> + /* q =3D int(nn/m) */\n" - "> + q =3D nn / m;\n" + "> + /* p = max(0, 4 - int(log2 (n/m))) */\n" + "> + p = cdce925_pll_calc_p(n, m);\n" + "> + /* nn = n * 2^p */\n" + "> + nn = n * BIT(p);\n" + "> + /* q = int(nn/m) */\n" + "> + q = nn / m;\n" "> + if ((q < 16) || (1 > 64)) {\n" - "> + pr_debug(\"%s invalid q=3D%d\\n\", __func__, q);\n" + "> + pr_debug(\"%s invalid q=%d\\n\", __func__, q);\n" "> + return -EINVAL;\n" "> + }\n" - "> + r =3D nn - (m*q);\n" + "> + r = nn - (m*q);\n" "> + if (r > 511) {\n" - "> + pr_debug(\"%s invalid r=3D%d\\n\", __func__, r);\n" + "> + pr_debug(\"%s invalid r=%d\\n\", __func__, r);\n" "> + return -EINVAL;\n" "> + }\n" - "> + pr_debug(\"%s n=3D%d m=3D%d p=3D%d q=3D%d r=3D%d\\n\", __fun=\n" - "c__,\n" + "> + pr_debug(\"%s n=%d m=%d p=%d q=%d r=%d\\n\", __func__,\n" "> + n, m, p, q, r);\n" "> + /* encode into register bits */\n" - "> + pll[0] =3D n >> 4;\n" - "> + pll[1] =3D ((n & 0x0F) << 4) | ((r >> 5) & 0x0F);\n" - "> + pll[2] =3D ((r & 0x1F) << 3) | ((q >> 3) & 0x07);\n" - "> + pll[3] =3D ((q & 0x07) << 5) | (p << 2) |\n" + "> + pll[0] = n >> 4;\n" + "> + pll[1] = ((n & 0x0F) << 4) | ((r >> 5) & 0x0F);\n" + "> + pll[2] = ((r & 0x1F) << 3) | ((q >> 3) & 0x07);\n" + "> + pll[3] = ((q & 0x07) << 5) | (p << 2) |\n" "> + cdce925_pll_calc_range_bits(hw, n, m);\n" "> + /* Write to registers */\n" - "> + for (i =3D 0; i < ARRAY_SIZE(pll); ++i)\n" + "> + for (i = 0; i < ARRAY_SIZE(pll); ++i)\n" "> + regmap_write(data->chip->regmap,\n" "> + reg_ofs + CDCE925_PLL_MULDIV + i, pll[i]);\n" "> + /* Enable PLL */\n" @@ -411,24 +388,23 @@ "> +\n" "> +static void cdce925_pll_unprepare(struct clk_hw *hw)\n" "> +{\n" - "> + struct clk_cdce925_pll *data =3D to_clk_cdce925_pll(hw);\n" - "> + u8 reg_ofs =3D data->index * CDCE925_OFFSET_PLL;\n" + "> + struct clk_cdce925_pll *data = to_clk_cdce925_pll(hw);\n" + "> + u8 reg_ofs = data->index * CDCE925_OFFSET_PLL;\n" "> +\n" "> + regmap_update_bits(data->chip->regmap,\n" "> + reg_ofs + CDCE925_PLL_MUX_OUTPUTS, 0x80, 0x80);\n" "> +}\n" "> +\n" - "> +static const struct clk_ops cdce925_pll_ops =3D {\n" - "> + .prepare =3D cdce925_pll_prepare,\n" - "> + .unprepare =3D cdce925_pll_unprepare,\n" - "> + .recalc_rate =3D cdce925_pll_recalc_rate,\n" - "> + .round_rate =3D cdce925_pll_round_rate,\n" - "> + .set_rate =3D cdce925_pll_set_rate,\n" + "> +static const struct clk_ops cdce925_pll_ops = {\n" + "> + .prepare = cdce925_pll_prepare,\n" + "> + .unprepare = cdce925_pll_unprepare,\n" + "> + .recalc_rate = cdce925_pll_recalc_rate,\n" + "> + .round_rate = cdce925_pll_round_rate,\n" + "> + .set_rate = cdce925_pll_set_rate,\n" "> +};\n" "> +\n" "> +\n" - "> +static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pd=\n" - "iv)\n" + "> +static void cdce925_clk_set_pdiv(struct clk_cdce925_output *data, u16 pdiv)\n" "> +{\n" "> + switch (data->index) {\n" "> + case 0:\n" @@ -472,7 +448,7 @@ "> +\n" "> +static int cdce925_clk_prepare(struct clk_hw *hw)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" "> + cdce925_clk_set_pdiv(data, data->pdiv);\n" "> + cdce925_clk_activate(data);\n" @@ -481,7 +457,7 @@ "> +\n" "> +static void cdce925_clk_unprepare(struct clk_hw *hw)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" "> + /* Disable clock by setting divider to \"0\" */\n" "> + cdce925_clk_set_pdiv(data, 0);\n" @@ -490,7 +466,7 @@ "> +static unsigned long cdce925_clk_recalc_rate(struct clk_hw *hw,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" "> + if (data->pdiv)\n" "> + return parent_rate / data->pdiv;\n" @@ -504,12 +480,12 @@ "> +\n" "> + if (!rate)\n" "> + return 0;\n" - "> + if (rate >=3D parent_rate)\n" + "> + if (rate >= parent_rate)\n" "> + return 1;\n" "> +\n" - "> + divider =3D DIV_ROUND_CLOSEST(parent_rate, rate);\n" + "> + divider = DIV_ROUND_CLOSEST(parent_rate, rate);\n" "> + if (divider > 0x7F)\n" - "> + divider =3D 0x7F;\n" + "> + divider = 0x7F;\n" "> +\n" "> + return (u16)divider;\n" "> +}\n" @@ -517,42 +493,40 @@ "> +static unsigned long cdce925_clk_best_parent_rate(\n" "> + struct clk_hw *hw, unsigned long rate)\n" "> +{\n" - "> + struct clk *pll =3D clk_get_parent(hw->clk);\n" - "> + struct clk *root =3D clk_get_parent(pll);\n" - "> + unsigned long root_rate =3D clk_get_rate(root);\n" - "> + unsigned long best_rate_error =3D rate;\n" + "> + struct clk *pll = clk_get_parent(hw->clk);\n" + "> + struct clk *root = clk_get_parent(pll);\n" + "> + unsigned long root_rate = clk_get_rate(root);\n" + "> + unsigned long best_rate_error = rate;\n" "> + u16 pdiv_min;\n" "> + u16 pdiv_max;\n" "> + u16 pdiv_best;\n" "> + u16 pdiv_now;\n" "> +\n" - "> + if (root_rate % rate =3D=3D 0)\n" + "> + if (root_rate % rate == 0)\n" "> + return root_rate; /* Don't need the PLL, use bypass */\n" "> +\n" - "> + pdiv_min =3D (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN=\n" - ", rate));\n" - "> + pdiv_max =3D (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate);\n" + "> + pdiv_min = (u16)max(1ul, DIV_ROUND_UP(CDCE925_PLL_FREQUENCY_MIN, rate));\n" + "> + pdiv_max = (u16)min(127ul, CDCE925_PLL_FREQUENCY_MAX / rate);\n" "> +\n" "> + if (pdiv_min > pdiv_max)\n" "> + return 0; /* No can do? */\n" "> +\n" - "> + pdiv_best =3D pdiv_min;\n" - "> + for (pdiv_now =3D pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) {\n" - "> + unsigned long target_rate =3D rate * pdiv_now;\n" - "> + long pll_rate =3D clk_round_rate(pll, target_rate);\n" + "> + pdiv_best = pdiv_min;\n" + "> + for (pdiv_now = pdiv_min; pdiv_now < pdiv_max; ++pdiv_now) {\n" + "> + unsigned long target_rate = rate * pdiv_now;\n" + "> + long pll_rate = clk_round_rate(pll, target_rate);\n" "> + unsigned long actual_rate;\n" "> + unsigned long rate_error;\n" "> +\n" - "> + if (pll_rate <=3D 0)\n" + "> + if (pll_rate <= 0)\n" "> + continue;\n" - "> + actual_rate =3D pll_rate / pdiv_now;\n" - "> + rate_error =3D abs((long)actual_rate - (long)rate);\n" + "> + actual_rate = pll_rate / pdiv_now;\n" + "> + rate_error = abs((long)actual_rate - (long)rate);\n" "> + if (rate_error < best_rate_error) {\n" - "> + pdiv_best =3D pdiv_now;\n" - "> + best_rate_error =3D rate_error;\n" + "> + pdiv_best = pdiv_now;\n" + "> + best_rate_error = rate_error;\n" "> + }\n" - "> + /* TODO: Consider PLL frequency based on smaller n/m valu=\n" - "es\n" + "> + /* TODO: Consider PLL frequency based on smaller n/m values\n" "> + * and pick the better one if the error is equal */\n" "> + }\n" "> +\n" @@ -562,13 +536,13 @@ "> +static long cdce925_clk_round_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long *parent_rate)\n" "> +{\n" - "> + unsigned long l_parent_rate =3D *parent_rate;\n" - "> + u16 divider =3D cdce925_calc_divider(rate, l_parent_rate);\n" + "> + unsigned long l_parent_rate = *parent_rate;\n" + "> + u16 divider = cdce925_calc_divider(rate, l_parent_rate);\n" "> +\n" - "> + if (l_parent_rate / divider !=3D rate) {\n" - "> + l_parent_rate =3D cdce925_clk_best_parent_rate(hw, rate);\n" - "> + divider =3D cdce925_calc_divider(rate, l_parent_rate);\n" - "> + *parent_rate =3D l_parent_rate;\n" + "> + if (l_parent_rate / divider != rate) {\n" + "> + l_parent_rate = cdce925_clk_best_parent_rate(hw, rate);\n" + "> + divider = cdce925_calc_divider(rate, l_parent_rate);\n" + "> + *parent_rate = l_parent_rate;\n" "> + }\n" "> +\n" "> + if (divider)\n" @@ -579,19 +553,19 @@ "> +static int cdce925_clk_set_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" - "> + data->pdiv =3D cdce925_calc_divider(rate, parent_rate);\n" + "> + data->pdiv = cdce925_calc_divider(rate, parent_rate);\n" "> +\n" "> + return 0;\n" "> +}\n" "> +\n" - "> +static const struct clk_ops cdce925_clk_ops =3D {\n" - "> + .prepare =3D cdce925_clk_prepare,\n" - "> + .unprepare =3D cdce925_clk_unprepare,\n" - "> + .recalc_rate =3D cdce925_clk_recalc_rate,\n" - "> + .round_rate =3D cdce925_clk_round_rate,\n" - "> + .set_rate =3D cdce925_clk_set_rate,\n" + "> +static const struct clk_ops cdce925_clk_ops = {\n" + "> + .prepare = cdce925_clk_prepare,\n" + "> + .unprepare = cdce925_clk_unprepare,\n" + "> + .recalc_rate = cdce925_clk_recalc_rate,\n" + "> + .round_rate = cdce925_clk_round_rate,\n" + "> + .set_rate = cdce925_clk_set_rate,\n" "> +};\n" "> +\n" "> +\n" @@ -602,22 +576,21 @@ "> +\n" "> + if (!rate)\n" "> + return 0;\n" - "> + if (rate >=3D parent_rate)\n" + "> + if (rate >= parent_rate)\n" "> + return 1;\n" "> +\n" - "> + divider =3D DIV_ROUND_CLOSEST(parent_rate, rate);\n" + "> + divider = DIV_ROUND_CLOSEST(parent_rate, rate);\n" "> + if (divider > 0x3FF) /* Y1 has 10-bit divider */\n" - "> + divider =3D 0x3FF;\n" + "> + divider = 0x3FF;\n" "> +\n" "> + return (u16)divider;\n" "> +}\n" "> +\n" - "> +static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long r=\n" - "ate,\n" + "> +static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long *parent_rate)\n" "> +{\n" - "> + unsigned long l_parent_rate =3D *parent_rate;\n" - "> + u16 divider =3D cdce925_y1_calc_divider(rate, l_parent_rate);\n" + "> + unsigned long l_parent_rate = *parent_rate;\n" + "> + u16 divider = cdce925_y1_calc_divider(rate, l_parent_rate);\n" "> +\n" "> + if (divider)\n" "> + return (long)(l_parent_rate / divider);\n" @@ -627,28 +600,28 @@ "> +static int cdce925_clk_y1_set_rate(struct clk_hw *hw, unsigned long rate,\n" "> + unsigned long parent_rate)\n" "> +{\n" - "> + struct clk_cdce925_output *data =3D to_clk_cdce925_output(hw);\n" + "> + struct clk_cdce925_output *data = to_clk_cdce925_output(hw);\n" "> +\n" - "> + data->pdiv =3D cdce925_y1_calc_divider(rate, parent_rate);\n" + "> + data->pdiv = cdce925_y1_calc_divider(rate, parent_rate);\n" "> +\n" "> + return 0;\n" "> +}\n" "> +\n" - "> +static const struct clk_ops cdce925_clk_y1_ops =3D {\n" - "> + .prepare =3D cdce925_clk_prepare,\n" - "> + .unprepare =3D cdce925_clk_unprepare,\n" - "> + .recalc_rate =3D cdce925_clk_recalc_rate,\n" - "> + .round_rate =3D cdce925_clk_y1_round_rate,\n" - "> + .set_rate =3D cdce925_clk_y1_set_rate,\n" + "> +static const struct clk_ops cdce925_clk_y1_ops = {\n" + "> + .prepare = cdce925_clk_prepare,\n" + "> + .unprepare = cdce925_clk_unprepare,\n" + "> + .recalc_rate = cdce925_clk_recalc_rate,\n" + "> + .round_rate = cdce925_clk_y1_round_rate,\n" + "> + .set_rate = cdce925_clk_y1_set_rate,\n" "> +};\n" "> +\n" "> +\n" - "> +static struct regmap_config cdce925_regmap_config =3D {\n" - "> + .name =3D \"configuration0\",\n" - "> + .reg_bits =3D 8,\n" - "> + .val_bits =3D 8,\n" - "> + .cache_type =3D REGCACHE_RBTREE,\n" - "> + .max_register =3D 0x2F,\n" + "> +static struct regmap_config cdce925_regmap_config = {\n" + "> + .name = \"configuration0\",\n" + "> + .reg_bits = 8,\n" + "> + .val_bits = 8,\n" + "> + .cache_type = REGCACHE_RBTREE,\n" + "> + .max_register = 0x2F,\n" "> +};\n" "> +\n" "> +#define CDCE925_I2C_COMMAND_BLOCK_TRANSFER 0x00\n" @@ -657,24 +630,23 @@ "> +static int cdce925_regmap_i2c_write(\n" "> + void *context, const void *data, size_t count)\n" "> +{\n" - "> + struct device *dev =3D context;\n" - "> + struct i2c_client *i2c =3D to_i2c_client(dev);\n" + "> + struct device *dev = context;\n" + "> + struct i2c_client *i2c = to_i2c_client(dev);\n" "> + int ret;\n" "> + u8 reg_data[2];\n" "> +\n" - "> + if (count !=3D 2)\n" + "> + if (count != 2)\n" "> + return -ENOTSUPP;\n" "> +\n" "> + /* First byte is command code */\n" - "> + reg_data[0] =3D CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[=\n" - "0];\n" - "> + reg_data[1] =3D ((u8 *)data)[1];\n" + "> + reg_data[0] = CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)data)[0];\n" + "> + reg_data[1] = ((u8 *)data)[1];\n" "> +\n" "> + dev_dbg(&i2c->dev, \"%s(%zu) %#x %#x\\n\", __func__, count,\n" "> + reg_data[0], reg_data[1]);\n" "> +\n" - "> + ret =3D i2c_master_send(i2c, reg_data, count);\n" - "> + if (likely(ret =3D=3D count))\n" + "> + ret = i2c_master_send(i2c, reg_data, count);\n" + "> + if (likely(ret == count))\n" "> + return 0;\n" "> + else if (ret < 0)\n" "> + return ret;\n" @@ -685,41 +657,38 @@ "> +static int cdce925_regmap_i2c_read(void *context,\n" "> + const void *reg, size_t reg_size, void *val, size_t val_size)\n" "> +{\n" - "> + struct device *dev =3D context;\n" - "> + struct i2c_client *i2c =3D to_i2c_client(dev);\n" + "> + struct device *dev = context;\n" + "> + struct i2c_client *i2c = to_i2c_client(dev);\n" "> + struct i2c_msg xfer[2];\n" "> + int ret;\n" "> + u8 reg_data[2];\n" "> +\n" - "> + if (reg_size !=3D 1)\n" + "> + if (reg_size != 1)\n" "> + return -ENOTSUPP;\n" "> +\n" - "> + xfer[0].addr =3D i2c->addr;\n" - "> + xfer[0].flags =3D 0;\n" - "> + xfer[0].buf =3D reg_data;\n" - "> + if (val_size =3D=3D 1) {\n" - "> + reg_data[0] =3D\n" - "> + CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0=\n" - "];\n" - "> + xfer[0].len =3D 1;\n" + "> + xfer[0].addr = i2c->addr;\n" + "> + xfer[0].flags = 0;\n" + "> + xfer[0].buf = reg_data;\n" + "> + if (val_size == 1) {\n" + "> + reg_data[0] =\n" + "> + CDCE925_I2C_COMMAND_BYTE_TRANSFER | ((u8 *)reg)[0];\n" + "> + xfer[0].len = 1;\n" "> + } else {\n" - "> + reg_data[0] =3D\n" - "> + CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[=\n" - "0];\n" - "> + reg_data[1] =3D val_size;\n" - "> + xfer[0].len =3D 2;\n" + "> + reg_data[0] =\n" + "> + CDCE925_I2C_COMMAND_BLOCK_TRANSFER | ((u8 *)reg)[0];\n" + "> + reg_data[1] = val_size;\n" + "> + xfer[0].len = 2;\n" "> + }\n" "> +\n" - "> + xfer[1].addr =3D i2c->addr;\n" - "> + xfer[1].flags =3D I2C_M_RD;\n" - "> + xfer[1].len =3D val_size;\n" - "> + xfer[1].buf =3D val;\n" + "> + xfer[1].addr = i2c->addr;\n" + "> + xfer[1].flags = I2C_M_RD;\n" + "> + xfer[1].len = val_size;\n" + "> + xfer[1].buf = val;\n" "> +\n" - "> + ret =3D i2c_transfer(i2c->adapter, xfer, 2);\n" - "> + if (likely(ret =3D=3D 2)) {\n" + "> + ret = i2c_transfer(i2c->adapter, xfer, 2);\n" + "> + if (likely(ret == 2)) {\n" "> + dev_dbg(&i2c->dev, \"%s(%zu, %u) %#x %#x\\n\", __func__,\n" - "> + reg_size, val_size, reg_data[0], *((u8 *)=\n" - "val));\n" + "> + reg_size, val_size, reg_data[0], *((u8 *)val));\n" "> + return 0;\n" "> + } else if (ret < 0)\n" "> + return ret;\n" @@ -729,18 +698,18 @@ "> +\n" "> +/* The CDCE925 uses a funky way to read/write registers. Bulk mode is\n" "> + * just weird, so just use the single byte mode exclusively. */\n" - "> +static struct regmap_bus regmap_cdce925_bus =3D {\n" - "> + .write =3D cdce925_regmap_i2c_write,\n" - "> + .read =3D cdce925_regmap_i2c_read,\n" + "> +static struct regmap_bus regmap_cdce925_bus = {\n" + "> + .write = cdce925_regmap_i2c_write,\n" + "> + .read = cdce925_regmap_i2c_read,\n" "> +};\n" "> +\n" "> +static int cdce925_probe(struct i2c_client *client,\n" "> + const struct i2c_device_id *id)\n" "> +{\n" "> + struct clk_cdce925_chip *data;\n" - "> + struct device_node *node =3D client->dev.of_node;\n" + "> + struct device_node *node = client->dev.of_node;\n" "> + const char *parent_name;\n" - "> + const char *pll_clk_name[NUMBER_OF_PLLS] =3D {NULL,};\n" + "> + const char *pll_clk_name[NUMBER_OF_PLLS] = {NULL,};\n" "> + struct clk_init_data init;\n" "> + struct clk *clk;\n" "> + u32 value;\n" @@ -750,29 +719,27 @@ "> + char child_name[6];\n" "> +\n" "> + dev_dbg(&client->dev, \"%s\\n\", __func__);\n" - "> + data =3D devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);\n" + "> + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);\n" "> + if (!data)\n" "> + return -ENOMEM;\n" "> +\n" - "> + data->i2c_client =3D client;\n" - "> + data->regmap =3D devm_regmap_init(&client->dev, ®map_cdce925_b=\n" - "us,\n" + "> + data->i2c_client = client;\n" + "> + data->regmap = devm_regmap_init(&client->dev, ®map_cdce925_bus,\n" "> + &client->dev, &cdce925_regmap_config);\n" "> + if (IS_ERR(data->regmap)) {\n" - "> + dev_err(&client->dev, \"failed to allocate register map\\n\"=\n" - ");\n" + "> + dev_err(&client->dev, \"failed to allocate register map\\n\");\n" "> + return PTR_ERR(data->regmap);\n" "> + }\n" "> + i2c_set_clientdata(client, data);\n" "> +\n" - "> + parent_name =3D of_clk_get_parent_name(node, 0);\n" + "> + parent_name = of_clk_get_parent_name(node, 0);\n" "> + if (!parent_name) {\n" "> + dev_err(&client->dev, \"missing parent clock\\n\");\n" "> + return -ENODEV;\n" "> + }\n" "> + dev_dbg(&client->dev, \"parent is: %s\\n\", parent_name);\n" "> +\n" - "> + if (of_property_read_u32(node, \"xtal-load-pf\", &value) =3D=3D 0)\n" + "> + if (of_property_read_u32(node, \"xtal-load-pf\", &value) == 0)\n" "> + regmap_write(data->regmap,\n" "> + CDCE925_REG_XCSEL, (value << 3) & 0xF8);\n" "> + /* PWDN bit */\n" @@ -781,42 +748,40 @@ "> + /* Set input source for Y1 to be the XTAL */\n" "> + regmap_update_bits(data->regmap, 0x02, BIT(7), 0);\n" "> +\n" - "> + init.ops =3D &cdce925_pll_ops;\n" - "> + init.flags =3D 0;\n" - "> + init.parent_names =3D &parent_name;\n" - "> + init.num_parents =3D parent_name ? 1 : 0;\n" + "> + init.ops = &cdce925_pll_ops;\n" + "> + init.flags = 0;\n" + "> + init.parent_names = &parent_name;\n" + "> + init.num_parents = parent_name ? 1 : 0;\n" "> +\n" "> + /* Register PLL clocks */\n" - "> + for (i =3D 0; i < NUMBER_OF_PLLS; ++i) {\n" - "> + pll_clk_name[i] =3D kasprintf(GFP_KERNEL, \"%s.pll%d\",\n" + "> + for (i = 0; i < NUMBER_OF_PLLS; ++i) {\n" + "> + pll_clk_name[i] = kasprintf(GFP_KERNEL, \"%s.pll%d\",\n" "> + client->dev.of_node->name, i);\n" - "> + init.name =3D pll_clk_name[i];\n" - "> + data->pll[i].chip =3D data;\n" - "> + data->pll[i].hw.init =3D &init;\n" - "> + data->pll[i].index =3D i;\n" - "> + clk =3D devm_clk_register(&client->dev, &data->pll[i].hw);\n" + "> + init.name = pll_clk_name[i];\n" + "> + data->pll[i].chip = data;\n" + "> + data->pll[i].hw.init = &init;\n" + "> + data->pll[i].index = i;\n" + "> + clk = devm_clk_register(&client->dev, &data->pll[i].hw);\n" "> + if (IS_ERR(clk)) {\n" - "> + dev_err(&client->dev, \"Failed register PLL %d\\n\",=\n" - " i);\n" - "> + err =3D PTR_ERR(clk);\n" + "> + dev_err(&client->dev, \"Failed register PLL %d\\n\", i);\n" + "> + err = PTR_ERR(clk);\n" "> + goto error;\n" "> + }\n" "> + sprintf(child_name, \"PLL%d\", i+1);\n" - "> + np_output =3D of_get_child_by_name(node, child_name);\n" + "> + np_output = of_get_child_by_name(node, child_name);\n" "> + if (!np_output)\n" "> + continue;\n" "> + if (!of_property_read_u32(np_output,\n" "> + \"clock-frequency\", &value)) {\n" - "> + err =3D clk_set_rate(clk, value);\n" + "> + err = clk_set_rate(clk, value);\n" "> + if (err)\n" "> + dev_err(&client->dev,\n" - "> + \"unable to set PLL frequency %ud\\=\n" - "n\",\n" + "> + \"unable to set PLL frequency %ud\\n\",\n" "> + value);\n" "> + }\n" "> + if (!of_property_read_u32(np_output,\n" "> + \"spread-spectrum\", &value)) {\n" - "> + u8 flag =3D of_property_read_bool(np_output,\n" + "> + u8 flag = of_property_read_bool(np_output,\n" "> + \"spread-spectrum-center\") ? 0x80 : 0x00;\n" "> + regmap_update_bits(data->regmap,\n" "> + 0x16 + (i*CDCE925_OFFSET_PLL),\n" @@ -828,108 +793,102 @@ "> + }\n" "> +\n" "> + /* Register output clock Y1 */\n" - "> + init.ops =3D &cdce925_clk_y1_ops;\n" - "> + init.flags =3D 0;\n" - "> + init.num_parents =3D 1;\n" - "> + init.parent_names =3D &parent_name; /* Mux Y1 to input */\n" - "> + init.name =3D kasprintf(GFP_KERNEL, \"%s.Y1\", client->dev.of_node-=\n" - ">name);\n" - "> + data->clk[0].chip =3D data;\n" - "> + data->clk[0].hw.init =3D &init;\n" - "> + data->clk[0].index =3D 0;\n" - "> + data->clk[0].pdiv =3D 1;\n" - "> + clk =3D devm_clk_register(&client->dev, &data->clk[0].hw);\n" + "> + init.ops = &cdce925_clk_y1_ops;\n" + "> + init.flags = 0;\n" + "> + init.num_parents = 1;\n" + "> + init.parent_names = &parent_name; /* Mux Y1 to input */\n" + "> + init.name = kasprintf(GFP_KERNEL, \"%s.Y1\", client->dev.of_node->name);\n" + "> + data->clk[0].chip = data;\n" + "> + data->clk[0].hw.init = &init;\n" + "> + data->clk[0].index = 0;\n" + "> + data->clk[0].pdiv = 1;\n" + "> + clk = devm_clk_register(&client->dev, &data->clk[0].hw);\n" "> + kfree(init.name); /* clock framework made a copy of the name */\n" "> + if (IS_ERR(clk)) {\n" "> + dev_err(&client->dev, \"clock registration Y1 failed\\n\");\n" - "> + err =3D PTR_ERR(clk);\n" + "> + err = PTR_ERR(clk);\n" "> + goto error;\n" "> + }\n" - "> + data->dt_clk[0] =3D clk;\n" + "> + data->dt_clk[0] = clk;\n" "> +\n" "> + /* Register output clocks Y2 .. Y5*/\n" - "> + init.ops =3D &cdce925_clk_ops;\n" - "> + init.flags =3D CLK_SET_RATE_PARENT;\n" - "> + init.num_parents =3D 1;\n" - "> + for (i =3D 1; i < NUMBER_OF_OUTPUTS; ++i) {\n" - "> + init.name =3D kasprintf(GFP_KERNEL, \"%s.Y%d\",\n" + "> + init.ops = &cdce925_clk_ops;\n" + "> + init.flags = CLK_SET_RATE_PARENT;\n" + "> + init.num_parents = 1;\n" + "> + for (i = 1; i < NUMBER_OF_OUTPUTS; ++i) {\n" + "> + init.name = kasprintf(GFP_KERNEL, \"%s.Y%d\",\n" "> + client->dev.of_node->name, i+1);\n" - "> + data->clk[i].chip =3D data;\n" - "> + data->clk[i].hw.init =3D &init;\n" - "> + data->clk[i].index =3D i;\n" - "> + data->clk[i].pdiv =3D 1;\n" + "> + data->clk[i].chip = data;\n" + "> + data->clk[i].hw.init = &init;\n" + "> + data->clk[i].index = i;\n" + "> + data->clk[i].pdiv = 1;\n" "> + switch (i) {\n" "> + case 1:\n" "> + case 2:\n" "> + /* Mux Y2/3 to PLL1 */\n" - "> + init.parent_names =3D &pll_clk_name[0];\n" + "> + init.parent_names = &pll_clk_name[0];\n" "> + break;\n" "> + case 3:\n" "> + case 4:\n" "> + /* Mux Y4/5 to PLL2 */\n" - "> + init.parent_names =3D &pll_clk_name[1];\n" + "> + init.parent_names = &pll_clk_name[1];\n" "> + break;\n" "> + }\n" - "> + clk =3D devm_clk_register(&client->dev, &data->clk[i].hw);\n" - "> + kfree(init.name); /* clock framework made a copy of the n=\n" - "ame */\n" + "> + clk = devm_clk_register(&client->dev, &data->clk[i].hw);\n" + "> + kfree(init.name); /* clock framework made a copy of the name */\n" "> + if (IS_ERR(clk)) {\n" - "> + dev_err(&client->dev, \"clock registration failed\\=\n" - "n\");\n" - "> + err =3D PTR_ERR(clk);\n" + "> + dev_err(&client->dev, \"clock registration failed\\n\");\n" + "> + err = PTR_ERR(clk);\n" "> + goto error;\n" "> + }\n" - "> + data->dt_clk[i] =3D clk;\n" + "> + data->dt_clk[i] = clk;\n" "> + }\n" "> +\n" "> + /* Register the output clocks */\n" - "> + data->onecell.clk_num =3D NUMBER_OF_OUTPUTS;\n" - "> + data->onecell.clks =3D data->dt_clk;\n" - "> + err =3D of_clk_add_provider(client->dev.of_node, of_clk_src_onece=\n" - "ll_get,\n" + "> + data->onecell.clk_num = NUMBER_OF_OUTPUTS;\n" + "> + data->onecell.clks = data->dt_clk;\n" + "> + err = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,\n" "> + &data->onecell);\n" "> + if (err)\n" - "> + dev_err(&client->dev, \"unable to add OF clock provider\\n\"=\n" - ");\n" + "> + dev_err(&client->dev, \"unable to add OF clock provider\\n\");\n" "> +\n" - "> + err =3D 0;\n" + "> + err = 0;\n" "> +\n" "> +error:\n" - "> + for (i =3D 0; i < NUMBER_OF_PLLS; ++i)\n" + "> + for (i = 0; i < NUMBER_OF_PLLS; ++i)\n" "> + /* clock framework made a copy of the name */\n" "> + kfree(pll_clk_name[i]);\n" "> +\n" "> + return err;\n" "> +}\n" "> +\n" - "> +static const struct i2c_device_id cdce925_id[] =3D {\n" + "> +static const struct i2c_device_id cdce925_id[] = {\n" "> + { \"cdce925\", 0 },\n" "> + { }\n" "> +};\n" "> +MODULE_DEVICE_TABLE(i2c, cdce925_id);\n" "> +\n" - "> +static const struct of_device_id clk_cdce925_of_match[] =3D {\n" - "> + { .compatible =3D \"ti,cdce925\" },\n" + "> +static const struct of_device_id clk_cdce925_of_match[] = {\n" + "> + { .compatible = \"ti,cdce925\" },\n" "> + { },\n" "> +};\n" "> +MODULE_DEVICE_TABLE(of, clk_cdce925_of_match);\n" "> +\n" - "> +static struct i2c_driver cdce925_driver =3D {\n" - "> + .driver =3D {\n" - "> + .name =3D \"cdce925\",\n" - "> + .of_match_table =3D of_match_ptr(clk_cdce925_of_match),\n" + "> +static struct i2c_driver cdce925_driver = {\n" + "> + .driver = {\n" + "> + .name = \"cdce925\",\n" + "> + .of_match_table = of_match_ptr(clk_cdce925_of_match),\n" "> + },\n" - "> + .probe =3D cdce925_probe,\n" - "> + .id_table =3D cdce925_id,\n" + "> + .probe = cdce925_probe,\n" + "> + .id_table = cdce925_id,\n" "> +};\n" "> +module_i2c_driver(cdce925_driver);\n" "> +\n" "> +MODULE_AUTHOR(\"Mike Looijmans <mike.looijmans@topic.nl>\");\n" "> +MODULE_DESCRIPTION(\"cdce925 driver\");\n" "> +MODULE_LICENSE(\"GPL\");\n" - "> -- =\n" - "\n" + "> -- \n" "> 1.9.1\n" - >=20 + > -078c15b40d12285a98512f73e6b34bf7ce99afaa4b1536adcbc5e89873b7c89b +a2171823e8744467ad30c60fa1bad9bfca4733f6ed1a45aa44ff3e4e6682c843
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.