Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: si5351: Do not pass struct clk in platform_data

When registering clk-si5351 by platform_data, we should not pass struct clk
for the reference clocks. Drop struct clk from platform_data and rework the
driver to use devm_clk_get of named clock references.

While at it, check for at least one valid input clock and properly prepare/
enable valid reference clocks.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Reported-by: Michael Welling <mwelling@ieee.org>
Reported-by: Jean-Francois Moine <moinejf@free.fr>
Reported-by: Russell King <rmk+linux@arm.linux.org.uk>
Tested-by: Michael Welling <mwelling@ieee.org>
Tested-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Michael Turquette <mturquette@linaro.org>

authored by

Sebastian Hesselbarth and committed by
Michael Turquette
0cd3be6e f94029d8

+45 -22
+45 -18
drivers/clk/clk-si5351.c
··· 1128 1128 if (!pdata) 1129 1129 return -ENOMEM; 1130 1130 1131 - pdata->clk_xtal = of_clk_get(np, 0); 1132 - if (!IS_ERR(pdata->clk_xtal)) 1133 - clk_put(pdata->clk_xtal); 1134 - pdata->clk_clkin = of_clk_get(np, 1); 1135 - if (!IS_ERR(pdata->clk_clkin)) 1136 - clk_put(pdata->clk_clkin); 1137 - 1138 1131 /* 1139 1132 * property silabs,pll-source : <num src>, [<..>] 1140 1133 * allow to selectively set pll source ··· 1321 1328 i2c_set_clientdata(client, drvdata); 1322 1329 drvdata->client = client; 1323 1330 drvdata->variant = variant; 1324 - drvdata->pxtal = pdata->clk_xtal; 1325 - drvdata->pclkin = pdata->clk_clkin; 1331 + drvdata->pxtal = devm_clk_get(&client->dev, "xtal"); 1332 + drvdata->pclkin = devm_clk_get(&client->dev, "clkin"); 1333 + 1334 + if (PTR_ERR(drvdata->pxtal) == -EPROBE_DEFER || 1335 + PTR_ERR(drvdata->pclkin) == -EPROBE_DEFER) 1336 + return -EPROBE_DEFER; 1337 + 1338 + /* 1339 + * Check for valid parent clock: VARIANT_A and VARIANT_B need XTAL, 1340 + * VARIANT_C can have CLKIN instead. 1341 + */ 1342 + if (IS_ERR(drvdata->pxtal) && 1343 + (drvdata->variant != SI5351_VARIANT_C || IS_ERR(drvdata->pclkin))) { 1344 + dev_err(&client->dev, "missing parent clock\n"); 1345 + return -EINVAL; 1346 + } 1326 1347 1327 1348 drvdata->regmap = devm_regmap_init_i2c(client, &si5351_regmap_config); 1328 1349 if (IS_ERR(drvdata->regmap)) { ··· 1400 1393 } 1401 1394 } 1402 1395 1396 + if (!IS_ERR(drvdata->pxtal)) 1397 + clk_prepare_enable(drvdata->pxtal); 1398 + if (!IS_ERR(drvdata->pclkin)) 1399 + clk_prepare_enable(drvdata->pclkin); 1400 + 1403 1401 /* register xtal input clock gate */ 1404 1402 memset(&init, 0, sizeof(init)); 1405 1403 init.name = si5351_input_names[0]; ··· 1419 1407 clk = devm_clk_register(&client->dev, &drvdata->xtal); 1420 1408 if (IS_ERR(clk)) { 1421 1409 dev_err(&client->dev, "unable to register %s\n", init.name); 1422 - return PTR_ERR(clk); 1410 + ret = PTR_ERR(clk); 1411 + goto err_clk; 1423 1412 } 1424 1413 1425 1414 /* register clkin input clock gate */ ··· 1438 1425 if (IS_ERR(clk)) { 1439 1426 dev_err(&client->dev, "unable to register %s\n", 1440 1427 init.name); 1441 - return PTR_ERR(clk); 1428 + ret = PTR_ERR(clk); 1429 + goto err_clk; 1442 1430 } 1443 1431 } 1444 1432 ··· 1461 1447 clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw); 1462 1448 if (IS_ERR(clk)) { 1463 1449 dev_err(&client->dev, "unable to register %s\n", init.name); 1464 - return -EINVAL; 1450 + ret = PTR_ERR(clk); 1451 + goto err_clk; 1465 1452 } 1466 1453 1467 1454 /* register PLLB or VXCO (Si5351B) */ ··· 1486 1471 clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw); 1487 1472 if (IS_ERR(clk)) { 1488 1473 dev_err(&client->dev, "unable to register %s\n", init.name); 1489 - return -EINVAL; 1474 + ret = PTR_ERR(clk); 1475 + goto err_clk; 1490 1476 } 1491 1477 1492 1478 /* register clk multisync and clk out divider */ ··· 1508 1492 num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL); 1509 1493 1510 1494 if (WARN_ON(!drvdata->msynth || !drvdata->clkout || 1511 - !drvdata->onecell.clks)) 1512 - return -ENOMEM; 1495 + !drvdata->onecell.clks)) { 1496 + ret = -ENOMEM; 1497 + goto err_clk; 1498 + } 1513 1499 1514 1500 for (n = 0; n < num_clocks; n++) { 1515 1501 drvdata->msynth[n].num = n; ··· 1529 1511 if (IS_ERR(clk)) { 1530 1512 dev_err(&client->dev, "unable to register %s\n", 1531 1513 init.name); 1532 - return -EINVAL; 1514 + ret = PTR_ERR(clk); 1515 + goto err_clk; 1533 1516 } 1534 1517 } 1535 1518 ··· 1557 1538 if (IS_ERR(clk)) { 1558 1539 dev_err(&client->dev, "unable to register %s\n", 1559 1540 init.name); 1560 - return -EINVAL; 1541 + ret = PTR_ERR(clk); 1542 + goto err_clk; 1561 1543 } 1562 1544 drvdata->onecell.clks[n] = clk; 1563 1545 ··· 1577 1557 &drvdata->onecell); 1578 1558 if (ret) { 1579 1559 dev_err(&client->dev, "unable to add clk provider\n"); 1580 - return ret; 1560 + goto err_clk; 1581 1561 } 1582 1562 1583 1563 return 0; 1564 + 1565 + err_clk: 1566 + if (!IS_ERR(drvdata->pxtal)) 1567 + clk_disable_unprepare(drvdata->pxtal); 1568 + if (!IS_ERR(drvdata->pclkin)) 1569 + clk_disable_unprepare(drvdata->pclkin); 1570 + return ret; 1584 1571 } 1585 1572 1586 1573 static const struct i2c_device_id si5351_i2c_ids[] = {
-4
include/linux/platform_data/si5351.h
··· 5 5 #ifndef __LINUX_PLATFORM_DATA_SI5351_H__ 6 6 #define __LINUX_PLATFORM_DATA_SI5351_H__ 7 7 8 - struct clk; 9 - 10 8 /** 11 9 * enum si5351_pll_src - Si5351 pll clock source 12 10 * @SI5351_PLL_SRC_DEFAULT: default, do not change eeprom config ··· 105 107 * @clkout: array of clkout configuration 106 108 */ 107 109 struct si5351_platform_data { 108 - struct clk *clk_xtal; 109 - struct clk *clk_clkin; 110 110 enum si5351_pll_src pll_src[2]; 111 111 struct si5351_clkout_config clkout[8]; 112 112 };