summaryrefslogtreecommitdiff
path: root/drivers/clk/clk-si5341.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/clk-si5341.c')
-rw-r--r--drivers/clk/clk-si5341.c89
1 files changed, 52 insertions, 37 deletions
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index 0e528d7ba656..2499b771cd83 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -21,7 +21,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SI5341_NUM_INPUTS 4
@@ -551,6 +551,7 @@ static int si5341_clk_set_parent(struct clk_hw *hw, u8 index)
}
static const struct clk_ops si5341_clk_ops = {
+ .determine_rate = clk_hw_determine_rate_no_reparent,
.set_parent = si5341_clk_set_parent,
.get_parent = si5341_clk_get_parent,
.recalc_rate = si5341_clk_recalc_rate,
@@ -662,8 +663,8 @@ static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
return f;
}
-static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int si5341_synth_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct clk_si5341_synth *synth = to_clk_si5341_synth(hw);
u64 f;
@@ -671,15 +672,21 @@ static long si5341_synth_clk_round_rate(struct clk_hw *hw, unsigned long rate,
/* The synthesizer accuracy is such that anything in range will work */
f = synth->data->freq_vco;
do_div(f, SI5341_SYNTH_N_MAX);
- if (rate < f)
- return f;
+ if (req->rate < f) {
+ req->rate = f;
+
+ return 0;
+ }
f = synth->data->freq_vco;
do_div(f, SI5341_SYNTH_N_MIN);
- if (rate > f)
- return f;
+ if (req->rate > f) {
+ req->rate = f;
+
+ return 0;
+ }
- return rate;
+ return 0;
}
static int si5341_synth_program(struct clk_si5341_synth *synth,
@@ -740,7 +747,7 @@ static const struct clk_ops si5341_synth_clk_ops = {
.prepare = si5341_synth_clk_prepare,
.unprepare = si5341_synth_clk_unprepare,
.recalc_rate = si5341_synth_clk_recalc_rate,
- .round_rate = si5341_synth_clk_round_rate,
+ .determine_rate = si5341_synth_clk_determine_rate,
.set_rate = si5341_synth_clk_set_rate,
};
@@ -827,19 +834,20 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
return parent_rate / r_divider;
}
-static long si5341_output_clk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int si5341_output_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
+ unsigned long rate = req->rate;
unsigned long r;
if (!rate)
return 0;
- r = *parent_rate >> 1;
+ r = req->best_parent_rate >> 1;
/* If rate is an even divisor, no changes to parent required */
if (r && !(r % rate))
- return (long)rate;
+ return 0;
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
if (rate > 200000000) {
@@ -849,14 +857,15 @@ static long si5341_output_clk_round_rate(struct clk_hw *hw, unsigned long rate,
/* Take a parent frequency near 400 MHz */
r = (400000000u / rate) & ~1;
}
- *parent_rate = r * rate;
+ req->best_parent_rate = r * rate;
} else {
/* We cannot change our parent's rate, report what we can do */
r /= rate;
- rate = *parent_rate / (r << 1);
+ rate = req->best_parent_rate / (r << 1);
}
- return rate;
+ req->rate = rate;
+ return 0;
}
static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -892,10 +901,8 @@ static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate,
r[0] = r_div ? (r_div & 0xff) : 1;
r[1] = (r_div >> 8) & 0xff;
r[2] = (r_div >> 16) & 0xff;
- err = regmap_bulk_write(output->data->regmap,
+ return regmap_bulk_write(output->data->regmap,
SI5341_OUT_R_REG(output), r, 3);
-
- return 0;
}
static int si5341_output_reparent(struct clk_si5341_output *output, u8 index)
@@ -929,7 +936,7 @@ static const struct clk_ops si5341_output_clk_ops = {
.prepare = si5341_output_clk_prepare,
.unprepare = si5341_output_clk_unprepare,
.recalc_rate = si5341_output_clk_recalc_rate,
- .round_rate = si5341_output_clk_round_rate,
+ .determine_rate = si5341_output_clk_determine_rate,
.set_rate = si5341_output_clk_set_rate,
.set_parent = si5341_output_set_parent,
.get_parent = si5341_output_get_parent,
@@ -1257,7 +1264,7 @@ static int si5341_wait_device_ready(struct i2c_client *client)
static const struct regmap_config si5341_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.ranges = si5341_regmap_ranges,
.num_ranges = ARRAY_SIZE(si5341_regmap_ranges),
.max_register = SI5341_REGISTER_MAX,
@@ -1553,7 +1560,7 @@ static int si5341_probe(struct i2c_client *client)
struct clk_init_data init;
struct clk *input;
const char *root_clock_name;
- const char *synth_clock_names[SI5341_NUM_SYNTH];
+ const char *synth_clock_names[SI5341_NUM_SYNTH] = { NULL };
int err;
unsigned int i;
struct clk_si5341_output_config config[SI5341_MAX_NUM_OUTPUTS];
@@ -1697,6 +1704,10 @@ static int si5341_probe(struct i2c_client *client)
for (i = 0; i < data->num_synth; ++i) {
synth_clock_names[i] = devm_kasprintf(&client->dev, GFP_KERNEL,
"%s.N%u", client->dev.of_node->name, i);
+ if (!synth_clock_names[i]) {
+ err = -ENOMEM;
+ goto free_clk_names;
+ }
init.name = synth_clock_names[i];
data->synth[i].index = i;
data->synth[i].data = data;
@@ -1705,6 +1716,7 @@ static int si5341_probe(struct i2c_client *client)
if (err) {
dev_err(&client->dev,
"synth N%u registration failed\n", i);
+ goto free_clk_names;
}
}
@@ -1714,6 +1726,10 @@ static int si5341_probe(struct i2c_client *client)
for (i = 0; i < data->num_outputs; ++i) {
init.name = kasprintf(GFP_KERNEL, "%s.%d",
client->dev.of_node->name, i);
+ if (!init.name) {
+ err = -ENOMEM;
+ goto free_clk_names;
+ }
init.flags = config[i].synth_master ? CLK_SET_RATE_PARENT : 0;
data->clk[i].index = i;
data->clk[i].data = data;
@@ -1735,7 +1751,7 @@ static int si5341_probe(struct i2c_client *client)
if (err) {
dev_err(&client->dev,
"output %u registration failed\n", i);
- goto cleanup;
+ goto free_clk_names;
}
if (config[i].always_on)
clk_prepare(data->clk[i].hw.clk);
@@ -1745,7 +1761,7 @@ static int si5341_probe(struct i2c_client *client)
data);
if (err) {
dev_err(&client->dev, "unable to add clk provider\n");
- goto cleanup;
+ goto free_clk_names;
}
if (initialization_required) {
@@ -1753,11 +1769,11 @@ static int si5341_probe(struct i2c_client *client)
regcache_cache_only(data->regmap, false);
err = regcache_sync(data->regmap);
if (err < 0)
- goto cleanup;
+ goto free_clk_names;
err = si5341_finalize_defaults(data);
if (err < 0)
- goto cleanup;
+ goto free_clk_names;
}
/* wait for device to report input clock present and PLL lock */
@@ -1766,32 +1782,31 @@ static int si5341_probe(struct i2c_client *client)
10000, 250000);
if (err) {
dev_err(&client->dev, "Error waiting for input clock or PLL lock\n");
- goto cleanup;
+ goto free_clk_names;
}
/* clear sticky alarm bits from initialization */
err = regmap_write(data->regmap, SI5341_STATUS_STICKY, 0);
if (err) {
dev_err(&client->dev, "unable to clear sticky status\n");
- goto cleanup;
+ goto free_clk_names;
}
err = sysfs_create_files(&client->dev.kobj, si5341_attributes);
- if (err) {
+ if (err)
dev_err(&client->dev, "unable to create sysfs files\n");
- goto cleanup;
- }
+free_clk_names:
/* Free the names, clk framework makes copies */
for (i = 0; i < data->num_synth; ++i)
devm_kfree(&client->dev, (void *)synth_clock_names[i]);
- return 0;
-
cleanup:
- for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
- if (data->clk[i].vddo_reg)
- regulator_disable(data->clk[i].vddo_reg);
+ if (err) {
+ for (i = 0; i < SI5341_MAX_NUM_OUTPUTS; ++i) {
+ if (data->clk[i].vddo_reg)
+ regulator_disable(data->clk[i].vddo_reg);
+ }
}
return err;
}
@@ -1834,7 +1849,7 @@ static struct i2c_driver si5341_driver = {
.name = "si5341",
.of_match_table = clk_si5341_of_match,
},
- .probe_new = si5341_probe,
+ .probe = si5341_probe,
.remove = si5341_remove,
.id_table = si5341_id,
};