diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 3b2a66f..e0da91d 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -1120,6 +1120,7 @@ static int si5351_dt_parse(struct i2c_client *client, const __be32 *p; int num = 0; u32 val; + int ret; if (np == NULL) return 0; @@ -1129,11 +1130,21 @@ static int si5351_dt_parse(struct i2c_client *client, return -ENOMEM; pdata->clk_xtal = of_clk_get(np, 0); - if (!IS_ERR(pdata->clk_xtal)) - clk_put(pdata->clk_xtal); - pdata->clk_clkin = of_clk_get(np, 1); - if (!IS_ERR(pdata->clk_clkin)) - clk_put(pdata->clk_clkin); + if (IS_ERR(pdata->clk_xtal)) { + dev_err(&client->dev, + "xtal clock not speficied\n"); + return -ENODEV; + } + + if (variant == SI5351_VARIANT_C) { + pdata->clk_clkin = of_clk_get(np, 1); + if (IS_ERR(pdata->clk_clkin)) { + dev_err(&client->dev, + "clkin clock not speficied\n"); + ret = -ENODEV; + goto err_put_clk_of; + } + } /* * property silabs,pll-source : , [<..>] @@ -1143,14 +1154,16 @@ static int si5351_dt_parse(struct i2c_client *client, if (num >= 2) { dev_err(&client->dev, "invalid pll %d on pll-source prop\n", num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } p = of_prop_next_u32(prop, p, &val); if (!p) { dev_err(&client->dev, "missing pll-source for pll %d\n", num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } switch (val) { @@ -1162,14 +1175,16 @@ static int si5351_dt_parse(struct i2c_client *client, dev_err(&client->dev, "invalid parent %d for pll %d\n", val, num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } pdata->pll_src[num] = SI5351_PLL_SRC_CLKIN; break; default: dev_err(&client->dev, "invalid parent %d for pll %d\n", val, num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } } @@ -1178,13 +1193,15 @@ static int si5351_dt_parse(struct i2c_client *client, if (of_property_read_u32(child, "reg", &num)) { dev_err(&client->dev, "missing reg property of %s\n", child->name); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } if (num >= 8 || (variant == SI5351_VARIANT_A3 && num >= 3)) { dev_err(&client->dev, "invalid clkout %d\n", num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } if (!of_property_read_u32(child, "silabs,multisynth-source", @@ -1202,7 +1219,8 @@ static int si5351_dt_parse(struct i2c_client *client, dev_err(&client->dev, "invalid parent %d for multisynth %d\n", val, num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } } @@ -1225,7 +1243,8 @@ static int si5351_dt_parse(struct i2c_client *client, dev_err(&client->dev, "invalid parent %d for clkout %d\n", val, num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } pdata->clkout[num].clkout_src = SI5351_CLKOUT_SRC_CLKIN; @@ -1234,7 +1253,8 @@ static int si5351_dt_parse(struct i2c_client *client, dev_err(&client->dev, "invalid parent %d for clkout %d\n", val, num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } } @@ -1251,7 +1271,8 @@ static int si5351_dt_parse(struct i2c_client *client, dev_err(&client->dev, "invalid drive strength %d for clkout %d\n", val, num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } } @@ -1278,7 +1299,8 @@ static int si5351_dt_parse(struct i2c_client *client, dev_err(&client->dev, "invalid disable state %d for clkout %d\n", val, num); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk_of; } } @@ -1291,9 +1313,18 @@ static int si5351_dt_parse(struct i2c_client *client, client->dev.platform_data = pdata; return 0; + +err_put_clk_of: + if (!IS_ERR(pdata->clk_xtal)) + clk_put(pdata->clk_xtal); + if (IS_ERR(pdata->clk_clkin)) + clk_put(pdata->clk_clkin); + + return ret; } #else -static int si5351_dt_parse(struct i2c_client *client, enum si5351_variant variant) +static int si5351_dt_parse(struct i2c_client *client, + enum si5351_variant variant) { return 0; } @@ -1322,7 +1353,8 @@ static int si5351_i2c_probe(struct i2c_client *client, drvdata = devm_kzalloc(&client->dev, sizeof(*drvdata), GFP_KERNEL); if (drvdata == NULL) { dev_err(&client->dev, "unable to allocate driver data\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err_put_clk; } i2c_set_clientdata(client, drvdata); @@ -1334,7 +1366,8 @@ static int si5351_i2c_probe(struct i2c_client *client, drvdata->regmap = devm_regmap_init_i2c(client, &si5351_regmap_config); if (IS_ERR(drvdata->regmap)) { dev_err(&client->dev, "failed to allocate register map\n"); - return PTR_ERR(drvdata->regmap); + ret = PTR_ERR(drvdata->regmap); + goto err_put_clk; } /* Disable interrupts */ @@ -1351,7 +1384,7 @@ static int si5351_i2c_probe(struct i2c_client *client, dev_err(&client->dev, "failed to reparent pll %d to %d\n", n, pdata->pll_src[n]); - return ret; + goto err_put_clk; } } @@ -1362,7 +1395,7 @@ static int si5351_i2c_probe(struct i2c_client *client, dev_err(&client->dev, "failed to reparent multisynth %d to %d\n", n, pdata->clkout[n].multisynth_src); - return ret; + goto err_put_clk; } ret = _si5351_clkout_reparent(drvdata, n, @@ -1371,7 +1404,7 @@ static int si5351_i2c_probe(struct i2c_client *client, dev_err(&client->dev, "failed to reparent clkout %d to %d\n", n, pdata->clkout[n].clkout_src); - return ret; + goto err_put_clk; } ret = _si5351_clkout_set_drive_strength(drvdata, n, @@ -1380,7 +1413,7 @@ static int si5351_i2c_probe(struct i2c_client *client, dev_err(&client->dev, "failed set drive strength of clkout%d to %d\n", n, pdata->clkout[n].drive); - return ret; + goto err_put_clk; } ret = _si5351_clkout_set_disable_state(drvdata, n, @@ -1389,7 +1422,7 @@ static int si5351_i2c_probe(struct i2c_client *client, dev_err(&client->dev, "failed set disable state of clkout%d to %d\n", n, pdata->clkout[n].disable_state); - return ret; + goto err_put_clk; } } @@ -1398,16 +1431,16 @@ static int si5351_i2c_probe(struct i2c_client *client, init.name = si5351_input_names[0]; init.ops = &si5351_xtal_ops; init.flags = 0; - if (!IS_ERR(drvdata->pxtal)) { - drvdata->pxtal_name = __clk_get_name(drvdata->pxtal); - init.parent_names = &drvdata->pxtal_name; - init.num_parents = 1; - } + drvdata->pxtal_name = __clk_get_name(drvdata->pxtal); + init.parent_names = &drvdata->pxtal_name; + init.num_parents = 1; + drvdata->xtal.init = &init; clk = devm_clk_register(&client->dev, &drvdata->xtal); if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return PTR_ERR(clk); + ret = PTR_ERR(clk); + goto err_put_clk; } /* register clkin input clock gate */ @@ -1415,17 +1448,17 @@ static int si5351_i2c_probe(struct i2c_client *client, memset(&init, 0, sizeof(init)); init.name = si5351_input_names[1]; init.ops = &si5351_clkin_ops; - if (!IS_ERR(drvdata->pclkin)) { - drvdata->pclkin_name = __clk_get_name(drvdata->pclkin); - init.parent_names = &drvdata->pclkin_name; - init.num_parents = 1; - } + drvdata->pclkin_name = __clk_get_name(drvdata->pclkin); + init.parent_names = &drvdata->pclkin_name; + init.num_parents = 1; + drvdata->clkin.init = &init; clk = devm_clk_register(&client->dev, &drvdata->clkin); if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return PTR_ERR(clk); + ret = PTR_ERR(clk); + goto err_put_clk; } } @@ -1447,7 +1480,8 @@ static int si5351_i2c_probe(struct i2c_client *client, clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw); if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk; } /* register PLLB or VXCO (Si5351B) */ @@ -1471,7 +1505,8 @@ static int si5351_i2c_probe(struct i2c_client *client, clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw); if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk; } /* register clk multisync and clk out divider */ @@ -1492,8 +1527,10 @@ static int si5351_i2c_probe(struct i2c_client *client, num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL); if (WARN_ON(!drvdata->msynth || !drvdata->clkout || - !drvdata->onecell.clks)) - return -ENOMEM; + !drvdata->onecell.clks)) { + ret = -ENOMEM; + goto err_put_clk; + } for (n = 0; n < num_clocks; n++) { drvdata->msynth[n].num = n; @@ -1511,7 +1548,8 @@ static int si5351_i2c_probe(struct i2c_client *client, if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk; } } @@ -1538,7 +1576,8 @@ static int si5351_i2c_probe(struct i2c_client *client, if (IS_ERR(clk)) { dev_err(&client->dev, "unable to register %s\n", init.name); - return -EINVAL; + ret = -EINVAL; + goto err_put_clk; } drvdata->onecell.clks[n] = clk; @@ -1557,9 +1596,31 @@ static int si5351_i2c_probe(struct i2c_client *client, &drvdata->onecell); if (ret) { dev_err(&client->dev, "unable to add clk provider\n"); - return ret; + goto err_put_clk; + } + + return 0; + +err_put_clk: + if (pdata) { + if (!IS_ERR(pdata->clk_xtal)) + clk_put(pdata->clk_xtal); + if (!IS_ERR(pdata->clk_clkin)) + clk_put(pdata->clk_clkin); } + return ret; +} + +int si5351_i2c_remove(struct i2c_client *client) +{ + struct si5351_driver_data *drvdata = i2c_get_clientdata(client); + + of_clk_del_provider(client->dev.of_node); + clk_put(drvdata->pxtal); + if (drvdata->variant == SI5351_VARIANT_C) + clk_put(drvdata->pclkin); + return 0; } @@ -1578,6 +1639,7 @@ static struct i2c_driver si5351_driver = { .of_match_table = of_match_ptr(si5351_dt_ids), }, .probe = si5351_i2c_probe, + .remove = si5351_i2c_remove, .id_table = si5351_i2c_ids, }; module_i2c_driver(si5351_driver);