699 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * TI CDCE706 programmable 3-PLL clock synthesizer driver4 *5 * Copyright (c) 2014 Cadence Design Systems Inc.6 *7 * Reference: https://www.ti.com/lit/ds/symlink/cdce706.pdf8 */9 10#include <linux/clk.h>11#include <linux/clk-provider.h>12#include <linux/delay.h>13#include <linux/i2c.h>14#include <linux/interrupt.h>15#include <linux/mod_devicetable.h>16#include <linux/module.h>17#include <linux/of.h>18#include <linux/rational.h>19#include <linux/regmap.h>20#include <linux/slab.h>21 22#define CDCE706_CLKIN_CLOCK 1023#define CDCE706_CLKIN_SOURCE 1124#define CDCE706_PLL_M_LOW(pll) (1 + 3 * (pll))25#define CDCE706_PLL_N_LOW(pll) (2 + 3 * (pll))26#define CDCE706_PLL_HI(pll) (3 + 3 * (pll))27#define CDCE706_PLL_MUX 328#define CDCE706_PLL_FVCO 629#define CDCE706_DIVIDER(div) (13 + (div))30#define CDCE706_CLKOUT(out) (19 + (out))31 32#define CDCE706_CLKIN_CLOCK_MASK 0x1033#define CDCE706_CLKIN_SOURCE_SHIFT 634#define CDCE706_CLKIN_SOURCE_MASK 0xc035#define CDCE706_CLKIN_SOURCE_LVCMOS 0x4036 37#define CDCE706_PLL_MUX_MASK(pll) (0x80 >> (pll))38#define CDCE706_PLL_LOW_M_MASK 0xff39#define CDCE706_PLL_LOW_N_MASK 0xff40#define CDCE706_PLL_HI_M_MASK 0x141#define CDCE706_PLL_HI_N_MASK 0x1e42#define CDCE706_PLL_HI_N_SHIFT 143#define CDCE706_PLL_M_MAX 0x1ff44#define CDCE706_PLL_N_MAX 0xfff45#define CDCE706_PLL_FVCO_MASK(pll) (0x80 >> (pll))46#define CDCE706_PLL_FREQ_MIN 8000000047#define CDCE706_PLL_FREQ_MAX 30000000048#define CDCE706_PLL_FREQ_HI 18000000049 50#define CDCE706_DIVIDER_PLL(div) (9 + (div) - ((div) > 2) - ((div) > 4))51#define CDCE706_DIVIDER_PLL_SHIFT(div) ((div) < 2 ? 5 : 3 * ((div) & 1))52#define CDCE706_DIVIDER_PLL_MASK(div) (0x7 << CDCE706_DIVIDER_PLL_SHIFT(div))53#define CDCE706_DIVIDER_DIVIDER_MASK 0x7f54#define CDCE706_DIVIDER_DIVIDER_MAX 0x7f55 56#define CDCE706_CLKOUT_DIVIDER_MASK 0x757#define CDCE706_CLKOUT_ENABLE_MASK 0x858 59static const struct regmap_config cdce706_regmap_config = {60 .reg_bits = 8,61 .val_bits = 8,62 .val_format_endian = REGMAP_ENDIAN_NATIVE,63};64 65#define to_hw_data(phw) (container_of((phw), struct cdce706_hw_data, hw))66 67struct cdce706_hw_data {68 struct cdce706_dev_data *dev_data;69 unsigned idx;70 unsigned parent;71 struct clk_hw hw;72 unsigned div;73 unsigned mul;74 unsigned mux;75};76 77struct cdce706_dev_data {78 struct i2c_client *client;79 struct regmap *regmap;80 struct clk *clkin_clk[2];81 const char *clkin_name[2];82 struct cdce706_hw_data clkin[1];83 struct cdce706_hw_data pll[3];84 struct cdce706_hw_data divider[6];85 struct cdce706_hw_data clkout[6];86};87 88static const char * const cdce706_source_name[] = {89 "clk_in0", "clk_in1",90};91 92static const char * const cdce706_clkin_name[] = {93 "clk_in",94};95 96static const char * const cdce706_pll_name[] = {97 "pll1", "pll2", "pll3",98};99 100static const char * const cdce706_divider_parent_name[] = {101 "clk_in", "pll1", "pll2", "pll2", "pll3",102};103 104static const char *cdce706_divider_name[] = {105 "p0", "p1", "p2", "p3", "p4", "p5",106};107 108static const char * const cdce706_clkout_name[] = {109 "clk_out0", "clk_out1", "clk_out2", "clk_out3", "clk_out4", "clk_out5",110};111 112static int cdce706_reg_read(struct cdce706_dev_data *dev_data, unsigned reg,113 unsigned *val)114{115 int rc = regmap_read(dev_data->regmap, reg | 0x80, val);116 117 if (rc < 0)118 dev_err(&dev_data->client->dev, "error reading reg %u", reg);119 return rc;120}121 122static int cdce706_reg_write(struct cdce706_dev_data *dev_data, unsigned reg,123 unsigned val)124{125 int rc = regmap_write(dev_data->regmap, reg | 0x80, val);126 127 if (rc < 0)128 dev_err(&dev_data->client->dev, "error writing reg %u", reg);129 return rc;130}131 132static int cdce706_reg_update(struct cdce706_dev_data *dev_data, unsigned reg,133 unsigned mask, unsigned val)134{135 int rc = regmap_update_bits(dev_data->regmap, reg | 0x80, mask, val);136 137 if (rc < 0)138 dev_err(&dev_data->client->dev, "error updating reg %u", reg);139 return rc;140}141 142static int cdce706_clkin_set_parent(struct clk_hw *hw, u8 index)143{144 struct cdce706_hw_data *hwd = to_hw_data(hw);145 146 hwd->parent = index;147 return 0;148}149 150static u8 cdce706_clkin_get_parent(struct clk_hw *hw)151{152 struct cdce706_hw_data *hwd = to_hw_data(hw);153 154 return hwd->parent;155}156 157static const struct clk_ops cdce706_clkin_ops = {158 .determine_rate = clk_hw_determine_rate_no_reparent,159 .set_parent = cdce706_clkin_set_parent,160 .get_parent = cdce706_clkin_get_parent,161};162 163static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw,164 unsigned long parent_rate)165{166 struct cdce706_hw_data *hwd = to_hw_data(hw);167 168 dev_dbg(&hwd->dev_data->client->dev,169 "%s, pll: %d, mux: %d, mul: %u, div: %u\n",170 __func__, hwd->idx, hwd->mux, hwd->mul, hwd->div);171 172 if (!hwd->mux) {173 if (hwd->div && hwd->mul) {174 u64 res = (u64)parent_rate * hwd->mul;175 176 do_div(res, hwd->div);177 return res;178 }179 } else {180 if (hwd->div)181 return parent_rate / hwd->div;182 }183 return 0;184}185 186static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,187 unsigned long *parent_rate)188{189 struct cdce706_hw_data *hwd = to_hw_data(hw);190 unsigned long mul, div;191 u64 res;192 193 dev_dbg(&hwd->dev_data->client->dev,194 "%s, rate: %lu, parent_rate: %lu\n",195 __func__, rate, *parent_rate);196 197 rational_best_approximation(rate, *parent_rate,198 CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX,199 &mul, &div);200 hwd->mul = mul;201 hwd->div = div;202 203 dev_dbg(&hwd->dev_data->client->dev,204 "%s, pll: %d, mul: %lu, div: %lu\n",205 __func__, hwd->idx, mul, div);206 207 res = (u64)*parent_rate * hwd->mul;208 do_div(res, hwd->div);209 return res;210}211 212static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate,213 unsigned long parent_rate)214{215 struct cdce706_hw_data *hwd = to_hw_data(hw);216 unsigned long mul = hwd->mul, div = hwd->div;217 int err;218 219 dev_dbg(&hwd->dev_data->client->dev,220 "%s, pll: %d, mul: %lu, div: %lu\n",221 __func__, hwd->idx, mul, div);222 223 err = cdce706_reg_update(hwd->dev_data,224 CDCE706_PLL_HI(hwd->idx),225 CDCE706_PLL_HI_M_MASK | CDCE706_PLL_HI_N_MASK,226 ((div >> 8) & CDCE706_PLL_HI_M_MASK) |227 ((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) &228 CDCE706_PLL_HI_N_MASK));229 if (err < 0)230 return err;231 232 err = cdce706_reg_write(hwd->dev_data,233 CDCE706_PLL_M_LOW(hwd->idx),234 div & CDCE706_PLL_LOW_M_MASK);235 if (err < 0)236 return err;237 238 err = cdce706_reg_write(hwd->dev_data,239 CDCE706_PLL_N_LOW(hwd->idx),240 mul & CDCE706_PLL_LOW_N_MASK);241 if (err < 0)242 return err;243 244 err = cdce706_reg_update(hwd->dev_data,245 CDCE706_PLL_FVCO,246 CDCE706_PLL_FVCO_MASK(hwd->idx),247 rate > CDCE706_PLL_FREQ_HI ?248 CDCE706_PLL_FVCO_MASK(hwd->idx) : 0);249 return err;250}251 252static const struct clk_ops cdce706_pll_ops = {253 .recalc_rate = cdce706_pll_recalc_rate,254 .round_rate = cdce706_pll_round_rate,255 .set_rate = cdce706_pll_set_rate,256};257 258static int cdce706_divider_set_parent(struct clk_hw *hw, u8 index)259{260 struct cdce706_hw_data *hwd = to_hw_data(hw);261 262 if (hwd->parent == index)263 return 0;264 hwd->parent = index;265 return cdce706_reg_update(hwd->dev_data,266 CDCE706_DIVIDER_PLL(hwd->idx),267 CDCE706_DIVIDER_PLL_MASK(hwd->idx),268 index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx));269}270 271static u8 cdce706_divider_get_parent(struct clk_hw *hw)272{273 struct cdce706_hw_data *hwd = to_hw_data(hw);274 275 return hwd->parent;276}277 278static unsigned long cdce706_divider_recalc_rate(struct clk_hw *hw,279 unsigned long parent_rate)280{281 struct cdce706_hw_data *hwd = to_hw_data(hw);282 283 dev_dbg(&hwd->dev_data->client->dev,284 "%s, divider: %d, div: %u\n",285 __func__, hwd->idx, hwd->div);286 if (hwd->div)287 return parent_rate / hwd->div;288 return 0;289}290 291static int cdce706_divider_determine_rate(struct clk_hw *hw,292 struct clk_rate_request *req)293{294 struct cdce706_hw_data *hwd = to_hw_data(hw);295 struct cdce706_dev_data *cdce = hwd->dev_data;296 unsigned long rate = req->rate;297 unsigned long mul, div;298 299 dev_dbg(&hwd->dev_data->client->dev,300 "%s, rate: %lu, parent_rate: %lu\n",301 __func__, rate, req->best_parent_rate);302 303 rational_best_approximation(rate, req->best_parent_rate,304 1, CDCE706_DIVIDER_DIVIDER_MAX,305 &mul, &div);306 if (!mul)307 div = CDCE706_DIVIDER_DIVIDER_MAX;308 309 if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {310 unsigned long best_diff = rate;311 unsigned long best_div = 0;312 struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];313 unsigned long gp_rate = gp_clk ? clk_get_rate(gp_clk) : 0;314 315 for (div = CDCE706_PLL_FREQ_MIN / rate; best_diff &&316 div <= CDCE706_PLL_FREQ_MAX / rate; ++div) {317 unsigned long n, m;318 unsigned long diff;319 unsigned long div_rate;320 u64 div_rate64;321 322 if (rate * div < CDCE706_PLL_FREQ_MIN)323 continue;324 325 rational_best_approximation(rate * div, gp_rate,326 CDCE706_PLL_N_MAX,327 CDCE706_PLL_M_MAX,328 &n, &m);329 div_rate64 = (u64)gp_rate * n;330 do_div(div_rate64, m);331 do_div(div_rate64, div);332 div_rate = div_rate64;333 diff = max(div_rate, rate) - min(div_rate, rate);334 335 if (diff < best_diff) {336 best_diff = diff;337 best_div = div;338 dev_dbg(&hwd->dev_data->client->dev,339 "%s, %lu * %lu / %lu / %lu = %lu\n",340 __func__, gp_rate, n, m, div, div_rate);341 }342 }343 344 div = best_div;345 346 dev_dbg(&hwd->dev_data->client->dev,347 "%s, altering parent rate: %lu -> %lu\n",348 __func__, req->best_parent_rate, rate * div);349 req->best_parent_rate = rate * div;350 }351 hwd->div = div;352 353 dev_dbg(&hwd->dev_data->client->dev,354 "%s, divider: %d, div: %lu\n",355 __func__, hwd->idx, div);356 357 req->rate = req->best_parent_rate / div;358 return 0;359}360 361static int cdce706_divider_set_rate(struct clk_hw *hw, unsigned long rate,362 unsigned long parent_rate)363{364 struct cdce706_hw_data *hwd = to_hw_data(hw);365 366 dev_dbg(&hwd->dev_data->client->dev,367 "%s, divider: %d, div: %u\n",368 __func__, hwd->idx, hwd->div);369 370 return cdce706_reg_update(hwd->dev_data,371 CDCE706_DIVIDER(hwd->idx),372 CDCE706_DIVIDER_DIVIDER_MASK,373 hwd->div);374}375 376static const struct clk_ops cdce706_divider_ops = {377 .set_parent = cdce706_divider_set_parent,378 .get_parent = cdce706_divider_get_parent,379 .recalc_rate = cdce706_divider_recalc_rate,380 .determine_rate = cdce706_divider_determine_rate,381 .set_rate = cdce706_divider_set_rate,382};383 384static int cdce706_clkout_prepare(struct clk_hw *hw)385{386 struct cdce706_hw_data *hwd = to_hw_data(hw);387 388 return cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),389 CDCE706_CLKOUT_ENABLE_MASK,390 CDCE706_CLKOUT_ENABLE_MASK);391}392 393static void cdce706_clkout_unprepare(struct clk_hw *hw)394{395 struct cdce706_hw_data *hwd = to_hw_data(hw);396 397 cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),398 CDCE706_CLKOUT_ENABLE_MASK, 0);399}400 401static int cdce706_clkout_set_parent(struct clk_hw *hw, u8 index)402{403 struct cdce706_hw_data *hwd = to_hw_data(hw);404 405 if (hwd->parent == index)406 return 0;407 hwd->parent = index;408 return cdce706_reg_update(hwd->dev_data,409 CDCE706_CLKOUT(hwd->idx),410 CDCE706_CLKOUT_ENABLE_MASK, index);411}412 413static u8 cdce706_clkout_get_parent(struct clk_hw *hw)414{415 struct cdce706_hw_data *hwd = to_hw_data(hw);416 417 return hwd->parent;418}419 420static unsigned long cdce706_clkout_recalc_rate(struct clk_hw *hw,421 unsigned long parent_rate)422{423 return parent_rate;424}425 426static int cdce706_clkout_determine_rate(struct clk_hw *hw,427 struct clk_rate_request *req)428{429 req->best_parent_rate = req->rate;430 431 return 0;432}433 434static int cdce706_clkout_set_rate(struct clk_hw *hw, unsigned long rate,435 unsigned long parent_rate)436{437 return 0;438}439 440static const struct clk_ops cdce706_clkout_ops = {441 .prepare = cdce706_clkout_prepare,442 .unprepare = cdce706_clkout_unprepare,443 .set_parent = cdce706_clkout_set_parent,444 .get_parent = cdce706_clkout_get_parent,445 .recalc_rate = cdce706_clkout_recalc_rate,446 .determine_rate = cdce706_clkout_determine_rate,447 .set_rate = cdce706_clkout_set_rate,448};449 450static int cdce706_register_hw(struct cdce706_dev_data *cdce,451 struct cdce706_hw_data *hw, unsigned num_hw,452 const char * const *clk_names,453 struct clk_init_data *init)454{455 unsigned i;456 int ret;457 458 for (i = 0; i < num_hw; ++i, ++hw) {459 init->name = clk_names[i];460 hw->dev_data = cdce;461 hw->idx = i;462 hw->hw.init = init;463 ret = devm_clk_hw_register(&cdce->client->dev,464 &hw->hw);465 if (ret) {466 dev_err(&cdce->client->dev, "Failed to register %s\n",467 clk_names[i]);468 return ret;469 }470 }471 return 0;472}473 474static int cdce706_register_clkin(struct cdce706_dev_data *cdce)475{476 struct clk_init_data init = {477 .ops = &cdce706_clkin_ops,478 .parent_names = cdce->clkin_name,479 .num_parents = ARRAY_SIZE(cdce->clkin_name),480 };481 unsigned i;482 int ret;483 unsigned clock, source;484 485 for (i = 0; i < ARRAY_SIZE(cdce->clkin_name); ++i) {486 struct clk *parent = devm_clk_get(&cdce->client->dev,487 cdce706_source_name[i]);488 489 if (IS_ERR(parent)) {490 cdce->clkin_name[i] = cdce706_source_name[i];491 } else {492 cdce->clkin_name[i] = __clk_get_name(parent);493 cdce->clkin_clk[i] = parent;494 }495 }496 497 ret = cdce706_reg_read(cdce, CDCE706_CLKIN_SOURCE, &source);498 if (ret < 0)499 return ret;500 if ((source & CDCE706_CLKIN_SOURCE_MASK) ==501 CDCE706_CLKIN_SOURCE_LVCMOS) {502 ret = cdce706_reg_read(cdce, CDCE706_CLKIN_CLOCK, &clock);503 if (ret < 0)504 return ret;505 cdce->clkin[0].parent = !!(clock & CDCE706_CLKIN_CLOCK_MASK);506 }507 508 ret = cdce706_register_hw(cdce, cdce->clkin,509 ARRAY_SIZE(cdce->clkin),510 cdce706_clkin_name, &init);511 return ret;512}513 514static int cdce706_register_plls(struct cdce706_dev_data *cdce)515{516 struct clk_init_data init = {517 .ops = &cdce706_pll_ops,518 .parent_names = cdce706_clkin_name,519 .num_parents = ARRAY_SIZE(cdce706_clkin_name),520 };521 unsigned i;522 int ret;523 unsigned mux;524 525 ret = cdce706_reg_read(cdce, CDCE706_PLL_MUX, &mux);526 if (ret < 0)527 return ret;528 529 for (i = 0; i < ARRAY_SIZE(cdce->pll); ++i) {530 unsigned m, n, v;531 532 ret = cdce706_reg_read(cdce, CDCE706_PLL_M_LOW(i), &m);533 if (ret < 0)534 return ret;535 ret = cdce706_reg_read(cdce, CDCE706_PLL_N_LOW(i), &n);536 if (ret < 0)537 return ret;538 ret = cdce706_reg_read(cdce, CDCE706_PLL_HI(i), &v);539 if (ret < 0)540 return ret;541 cdce->pll[i].div = m | ((v & CDCE706_PLL_HI_M_MASK) << 8);542 cdce->pll[i].mul = n | ((v & CDCE706_PLL_HI_N_MASK) <<543 (8 - CDCE706_PLL_HI_N_SHIFT));544 cdce->pll[i].mux = mux & CDCE706_PLL_MUX_MASK(i);545 dev_dbg(&cdce->client->dev,546 "%s: i: %u, div: %u, mul: %u, mux: %d\n", __func__, i,547 cdce->pll[i].div, cdce->pll[i].mul, cdce->pll[i].mux);548 }549 550 ret = cdce706_register_hw(cdce, cdce->pll,551 ARRAY_SIZE(cdce->pll),552 cdce706_pll_name, &init);553 return ret;554}555 556static int cdce706_register_dividers(struct cdce706_dev_data *cdce)557{558 struct clk_init_data init = {559 .ops = &cdce706_divider_ops,560 .parent_names = cdce706_divider_parent_name,561 .num_parents = ARRAY_SIZE(cdce706_divider_parent_name),562 .flags = CLK_SET_RATE_PARENT,563 };564 unsigned i;565 int ret;566 567 for (i = 0; i < ARRAY_SIZE(cdce->divider); ++i) {568 unsigned val;569 570 ret = cdce706_reg_read(cdce, CDCE706_DIVIDER_PLL(i), &val);571 if (ret < 0)572 return ret;573 cdce->divider[i].parent =574 (val & CDCE706_DIVIDER_PLL_MASK(i)) >>575 CDCE706_DIVIDER_PLL_SHIFT(i);576 577 ret = cdce706_reg_read(cdce, CDCE706_DIVIDER(i), &val);578 if (ret < 0)579 return ret;580 cdce->divider[i].div = val & CDCE706_DIVIDER_DIVIDER_MASK;581 dev_dbg(&cdce->client->dev,582 "%s: i: %u, parent: %u, div: %u\n", __func__, i,583 cdce->divider[i].parent, cdce->divider[i].div);584 }585 586 ret = cdce706_register_hw(cdce, cdce->divider,587 ARRAY_SIZE(cdce->divider),588 cdce706_divider_name, &init);589 return ret;590}591 592static int cdce706_register_clkouts(struct cdce706_dev_data *cdce)593{594 struct clk_init_data init = {595 .ops = &cdce706_clkout_ops,596 .parent_names = cdce706_divider_name,597 .num_parents = ARRAY_SIZE(cdce706_divider_name),598 .flags = CLK_SET_RATE_PARENT,599 };600 unsigned i;601 int ret;602 603 for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) {604 unsigned val;605 606 ret = cdce706_reg_read(cdce, CDCE706_CLKOUT(i), &val);607 if (ret < 0)608 return ret;609 cdce->clkout[i].parent = val & CDCE706_CLKOUT_DIVIDER_MASK;610 dev_dbg(&cdce->client->dev,611 "%s: i: %u, parent: %u\n", __func__, i,612 cdce->clkout[i].parent);613 }614 615 return cdce706_register_hw(cdce, cdce->clkout,616 ARRAY_SIZE(cdce->clkout),617 cdce706_clkout_name, &init);618}619 620static struct clk_hw *621of_clk_cdce_get(struct of_phandle_args *clkspec, void *data)622{623 struct cdce706_dev_data *cdce = data;624 unsigned int idx = clkspec->args[0];625 626 if (idx >= ARRAY_SIZE(cdce->clkout)) {627 pr_err("%s: invalid index %u\n", __func__, idx);628 return ERR_PTR(-EINVAL);629 }630 631 return &cdce->clkout[idx].hw;632}633 634static int cdce706_probe(struct i2c_client *client)635{636 struct i2c_adapter *adapter = client->adapter;637 struct cdce706_dev_data *cdce;638 int ret;639 640 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))641 return -EIO;642 643 cdce = devm_kzalloc(&client->dev, sizeof(*cdce), GFP_KERNEL);644 if (!cdce)645 return -ENOMEM;646 647 cdce->client = client;648 cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config);649 if (IS_ERR(cdce->regmap)) {650 dev_err(&client->dev, "Failed to initialize regmap\n");651 return -EINVAL;652 }653 654 i2c_set_clientdata(client, cdce);655 656 ret = cdce706_register_clkin(cdce);657 if (ret < 0)658 return ret;659 ret = cdce706_register_plls(cdce);660 if (ret < 0)661 return ret;662 ret = cdce706_register_dividers(cdce);663 if (ret < 0)664 return ret;665 ret = cdce706_register_clkouts(cdce);666 if (ret < 0)667 return ret;668 return devm_of_clk_add_hw_provider(&client->dev, of_clk_cdce_get,669 cdce);670}671 672#ifdef CONFIG_OF673static const struct of_device_id cdce706_dt_match[] = {674 { .compatible = "ti,cdce706" },675 { },676};677MODULE_DEVICE_TABLE(of, cdce706_dt_match);678#endif679 680static const struct i2c_device_id cdce706_id[] = {681 { "cdce706", 0 },682 { }683};684MODULE_DEVICE_TABLE(i2c, cdce706_id);685 686static struct i2c_driver cdce706_i2c_driver = {687 .driver = {688 .name = "cdce706",689 .of_match_table = of_match_ptr(cdce706_dt_match),690 },691 .probe = cdce706_probe,692 .id_table = cdce706_id,693};694module_i2c_driver(cdce706_i2c_driver);695 696MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");697MODULE_DESCRIPTION("TI CDCE 706 clock synthesizer driver");698MODULE_LICENSE("GPL");699