diff options
Diffstat (limited to 'drivers/clk/clk-si570.c')
| -rw-r--r-- | drivers/clk/clk-si570.c | 102 |
1 files changed, 54 insertions, 48 deletions
diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index eea50121718a..b0b1830dd430 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -50,11 +50,21 @@ #define SI570_FREEZE_DCO (1 << 4) /** + * struct clk_si570_info: + * @max_freq: Maximum frequency for this device + * @has_temperature_stability: Device support temperature stability + */ +struct clk_si570_info { + u64 max_freq; + bool has_temperature_stability; +}; + +/** * struct clk_si570: * @hw: Clock hw struct * @regmap: Device's regmap - * @div_offset: Rgister offset for dividers - * @max_freq: Maximum frequency for this device + * @div_offset: Register offset for dividers + * @info: Device info * @fxtal: Factory xtal frequency * @n1: Clock divider N1 * @hs_div: Clock divider HSDIV @@ -66,7 +76,7 @@ struct clk_si570 { struct clk_hw hw; struct regmap *regmap; unsigned int div_offset; - u64 max_freq; + const struct clk_si570_info *info; u64 fxtal; unsigned int n1; unsigned int hs_div; @@ -76,11 +86,6 @@ struct clk_si570 { }; #define to_clk_si570(_hw) container_of(_hw, struct clk_si570, hw) -enum clk_si570_variant { - si57x, - si59x -}; - /** * si570_get_divs() - Read clock dividers from HW * @data: Pointer to struct clk_si570 @@ -176,7 +181,7 @@ static int si570_update_rfreq(struct clk_si570 *data) } /** - * si570_calc_divs() - Caluclate clock dividers + * si570_calc_divs() - Calculate clock dividers * @frequency: Target frequency * @data: Driver data structure * @out_rfreq: RFREG fractional multiplier (output) @@ -241,34 +246,40 @@ static unsigned long si570_recalc_rate(struct clk_hw *hw, return rate; } -static long si570_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int si570_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int err; u64 rfreq; unsigned int n1, hs_div; struct clk_si570 *data = to_clk_si570(hw); - if (!rate) + if (!req->rate) { + req->rate = 0; + return 0; + } - if (div64_u64(abs(rate - data->frequency) * 10000LL, + if (div64_u64(abs(req->rate - data->frequency) * 10000LL, data->frequency) < 35) { - rfreq = div64_u64((data->rfreq * rate) + - div64_u64(data->frequency, 2), data->frequency); + rfreq = div64_u64((data->rfreq * req->rate) + + div64_u64(data->frequency, 2), + data->frequency); n1 = data->n1; hs_div = data->hs_div; } else { - err = si570_calc_divs(rate, data, &rfreq, &n1, &hs_div); + err = si570_calc_divs(req->rate, data, &rfreq, &n1, &hs_div); if (err) { dev_err(&data->i2c_client->dev, "unable to round rate\n"); + req->rate = 0; + return 0; } } - return rate; + return 0; } /** @@ -341,7 +352,7 @@ static int si570_set_rate(struct clk_hw *hw, unsigned long rate, struct i2c_client *client = data->i2c_client; int err; - if (rate < SI570_MIN_FREQ || rate > data->max_freq) { + if (rate < SI570_MIN_FREQ || rate > data->info->max_freq) { dev_err(&client->dev, "requested frequency %lu Hz is out of range\n", rate); return -EINVAL; @@ -363,7 +374,7 @@ static int si570_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops si570_clk_ops = { .recalc_rate = si570_recalc_rate, - .round_rate = si570_round_rate, + .determine_rate = si570_determine_rate, .set_rate = si570_set_rate, }; @@ -392,21 +403,19 @@ static bool si570_regmap_is_writeable(struct device *dev, unsigned int reg) static const struct regmap_config si570_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 137, .writeable_reg = si570_regmap_is_writeable, .volatile_reg = si570_regmap_is_volatile, }; -static int si570_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int si570_probe(struct i2c_client *client) { struct clk_si570 *data; struct clk_init_data init; u32 initial_fout, factory_fout, stability; bool skip_recall; int err; - enum clk_si570_variant variant = id->driver_data; data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -418,7 +427,8 @@ static int si570_probe(struct i2c_client *client, data->hw.init = &init; data->i2c_client = client; - if (variant == si57x) { + data->info = i2c_get_match_data(client); + if (data->info->has_temperature_stability) { err = of_property_read_u32(client->dev.of_node, "temperature-stability", &stability); if (err) { @@ -429,10 +439,6 @@ static int si570_probe(struct i2c_client *client, /* adjust register offsets for 7ppm devices */ if (stability == 7) data->div_offset = SI570_DIV_OFFSET_7PPM; - - data->max_freq = SI570_MAX_FREQ; - } else { - data->max_freq = SI598_MAX_FREQ; } if (of_property_read_string(client->dev.of_node, "clock-output-names", @@ -465,8 +471,8 @@ static int si570_probe(struct i2c_client *client, dev_err(&client->dev, "clock registration failed\n"); return err; } - err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get, - &data->hw); + err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get, + &data->hw); if (err) { dev_err(&client->dev, "unable to add clk provider\n"); return err; @@ -476,10 +482,8 @@ static int si570_probe(struct i2c_client *client, if (!of_property_read_u32(client->dev.of_node, "clock-frequency", &initial_fout)) { err = clk_set_rate(data->hw.clk, initial_fout); - if (err) { - of_clk_del_provider(client->dev.of_node); + if (err) return err; - } } /* Display a message indicating that we've successfully registered */ @@ -489,27 +493,30 @@ static int si570_probe(struct i2c_client *client, return 0; } -static int si570_remove(struct i2c_client *client) -{ - of_clk_del_provider(client->dev.of_node); - return 0; -} +static const struct clk_si570_info clk_si570_info = { + .max_freq = SI570_MAX_FREQ, + .has_temperature_stability = true, +}; + +static const struct clk_si570_info clk_si590_info = { + .max_freq = SI598_MAX_FREQ, +}; static const struct i2c_device_id si570_id[] = { - { "si570", si57x }, - { "si571", si57x }, - { "si598", si59x }, - { "si599", si59x }, + { "si570", (kernel_ulong_t)&clk_si570_info }, + { "si571", (kernel_ulong_t)&clk_si570_info }, + { "si598", (kernel_ulong_t)&clk_si590_info }, + { "si599", (kernel_ulong_t)&clk_si590_info }, { } }; MODULE_DEVICE_TABLE(i2c, si570_id); static const struct of_device_id clk_si570_of_match[] = { - { .compatible = "silabs,si570" }, - { .compatible = "silabs,si571" }, - { .compatible = "silabs,si598" }, - { .compatible = "silabs,si599" }, - { }, + { .compatible = "silabs,si570", .data = &clk_si570_info }, + { .compatible = "silabs,si571", .data = &clk_si570_info }, + { .compatible = "silabs,si598", .data = &clk_si590_info }, + { .compatible = "silabs,si599", .data = &clk_si590_info }, + { } }; MODULE_DEVICE_TABLE(of, clk_si570_of_match); @@ -519,7 +526,6 @@ static struct i2c_driver si570_driver = { .of_match_table = clk_si570_of_match, }, .probe = si570_probe, - .remove = si570_remove, .id_table = si570_id, }; module_i2c_driver(si570_driver); |
