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.c120
1 files changed, 67 insertions, 53 deletions
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index f7b41366666e..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,
@@ -655,15 +656,15 @@ static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
f = synth->data->freq_vco;
f *= n_den >> 4;
- /* Now we need to to 64-bit division: f/n_num */
+ /* Now we need to do 64-bit division: f/n_num */
/* And compensate for the 4 bits we dropped */
f = div64_u64(f, (n_num >> 4));
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,
};
@@ -798,6 +805,15 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
u32 r_divider;
u8 r[3];
+ err = regmap_read(output->data->regmap,
+ SI5341_OUT_CONFIG(output), &val);
+ if (err < 0)
+ return err;
+
+ /* If SI5341_OUT_CFG_RDIV_FORCE2 is set, r_divider is 2 */
+ if (val & SI5341_OUT_CFG_RDIV_FORCE2)
+ return parent_rate / 2;
+
err = regmap_bulk_read(output->data->regmap,
SI5341_OUT_R_REG(output), r, 3);
if (err < 0)
@@ -814,30 +830,24 @@ static unsigned long si5341_output_clk_recalc_rate(struct clk_hw *hw,
r_divider += 1;
r_divider <<= 1;
- err = regmap_read(output->data->regmap,
- SI5341_OUT_CONFIG(output), &val);
- if (err < 0)
- return err;
-
- if (val & SI5341_OUT_CFG_RDIV_FORCE2)
- r_divider = 2;
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) {
@@ -847,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,
@@ -890,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)
@@ -927,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,
@@ -1255,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,
@@ -1468,7 +1477,7 @@ static ssize_t input_present_show(struct device *dev,
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOSREF);
- return snprintf(buf, PAGE_SIZE, "%d\n", res);
+ return sysfs_emit(buf, "%d\n", res);
}
static DEVICE_ATTR_RO(input_present);
@@ -1483,7 +1492,7 @@ static ssize_t input_present_sticky_show(struct device *dev,
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOSREF);
- return snprintf(buf, PAGE_SIZE, "%d\n", res);
+ return sysfs_emit(buf, "%d\n", res);
}
static DEVICE_ATTR_RO(input_present_sticky);
@@ -1498,7 +1507,7 @@ static ssize_t pll_locked_show(struct device *dev,
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOL);
- return snprintf(buf, PAGE_SIZE, "%d\n", res);
+ return sysfs_emit(buf, "%d\n", res);
}
static DEVICE_ATTR_RO(pll_locked);
@@ -1513,7 +1522,7 @@ static ssize_t pll_locked_sticky_show(struct device *dev,
if (res < 0)
return res;
res = !(status & SI5341_STATUS_LOL);
- return snprintf(buf, PAGE_SIZE, "%d\n", res);
+ return sysfs_emit(buf, "%d\n", res);
}
static DEVICE_ATTR_RO(pll_locked_sticky);
@@ -1545,14 +1554,13 @@ static const struct attribute *si5341_attributes[] = {
NULL
};
-static int si5341_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int si5341_probe(struct i2c_client *client)
{
struct clk_si5341 *data;
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];
@@ -1696,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;
@@ -1704,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;
}
}
@@ -1713,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;
@@ -1734,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);
@@ -1744,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) {
@@ -1752,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 */
@@ -1765,37 +1782,36 @@ 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;
}
-static int si5341_remove(struct i2c_client *client)
+static void si5341_remove(struct i2c_client *client)
{
struct clk_si5341 *data = i2c_get_clientdata(client);
int i;
@@ -1806,8 +1822,6 @@ static int si5341_remove(struct i2c_client *client)
if (data->clk[i].vddo_reg)
regulator_disable(data->clk[i].vddo_reg);
}
-
- return 0;
}
static const struct i2c_device_id si5341_id[] = {