diff options
Diffstat (limited to 'drivers/clk/clk-cdce925.c')
| -rw-r--r-- | drivers/clk/clk-cdce925.c | 160 |
1 files changed, 103 insertions, 57 deletions
diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index c933be01c7db..0b2ad21e6e4d 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/i2c.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/gcd.h> @@ -24,25 +25,11 @@ * Model this as 2 PLL clocks which are parents to the outputs. */ -enum { - CDCE913, - CDCE925, - CDCE937, - CDCE949, -}; - struct clk_cdce925_chip_info { int num_plls; int num_outputs; }; -static const struct clk_cdce925_chip_info clk_cdce925_chip_info_tbl[] = { - [CDCE913] = { .num_plls = 1, .num_outputs = 3 }, - [CDCE925] = { .num_plls = 2, .num_outputs = 5 }, - [CDCE937] = { .num_plls = 3, .num_outputs = 7 }, - [CDCE949] = { .num_plls = 4, .num_outputs = 9 }, -}; - #define MAX_NUMBER_OF_PLLS 4 #define MAX_NUMBER_OF_OUTPUTS 9 @@ -114,7 +101,6 @@ static void cdce925_pll_find_rate(unsigned long rate, if (rate <= parent_rate) { /* Can always deliver parent_rate in bypass mode */ - rate = parent_rate; *n = 0; *m = 0; } else { @@ -142,13 +128,15 @@ static void cdce925_pll_find_rate(unsigned long rate, } } -static long cdce925_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int cdce925_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { u16 n, m; - cdce925_pll_find_rate(rate, *parent_rate, &n, &m); - return (long)cdce925_pll_calculate_rate(*parent_rate, n, m); + cdce925_pll_find_rate(req->rate, req->best_parent_rate, &n, &m); + req->rate = (long)cdce925_pll_calculate_rate(req->best_parent_rate, n, m); + + return 0; } static int cdce925_pll_set_rate(struct clk_hw *hw, unsigned long rate, @@ -280,7 +268,7 @@ static const struct clk_ops cdce925_pll_ops = { .prepare = cdce925_pll_prepare, .unprepare = cdce925_pll_unprepare, .recalc_rate = cdce925_pll_recalc_rate, - .round_rate = cdce925_pll_round_rate, + .determine_rate = cdce925_pll_determine_rate, .set_rate = cdce925_pll_set_rate, }; @@ -434,20 +422,23 @@ static unsigned long cdce925_clk_best_parent_rate( return rate * pdiv_best; } -static long cdce925_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int cdce925_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned long l_parent_rate = *parent_rate; - u16 divider = cdce925_calc_divider(rate, l_parent_rate); + unsigned long l_parent_rate = req->best_parent_rate; + u16 divider = cdce925_calc_divider(req->rate, l_parent_rate); - if (l_parent_rate / divider != rate) { - l_parent_rate = cdce925_clk_best_parent_rate(hw, rate); - divider = cdce925_calc_divider(rate, l_parent_rate); - *parent_rate = l_parent_rate; + if (l_parent_rate / divider != req->rate) { + l_parent_rate = cdce925_clk_best_parent_rate(hw, req->rate); + divider = cdce925_calc_divider(req->rate, l_parent_rate); + req->best_parent_rate = l_parent_rate; } if (divider) - return (long)(l_parent_rate / divider); + req->rate = (long)(l_parent_rate / divider); + else + req->rate = 0; + return 0; } @@ -465,7 +456,7 @@ static const struct clk_ops cdce925_clk_ops = { .prepare = cdce925_clk_prepare, .unprepare = cdce925_clk_unprepare, .recalc_rate = cdce925_clk_recalc_rate, - .round_rate = cdce925_clk_round_rate, + .determine_rate = cdce925_clk_determine_rate, .set_rate = cdce925_clk_set_rate, }; @@ -487,14 +478,17 @@ static u16 cdce925_y1_calc_divider(unsigned long rate, return (u16)divider; } -static long cdce925_clk_y1_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int cdce925_clk_y1_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned long l_parent_rate = *parent_rate; - u16 divider = cdce925_y1_calc_divider(rate, l_parent_rate); + unsigned long l_parent_rate = req->best_parent_rate; + u16 divider = cdce925_y1_calc_divider(req->rate, l_parent_rate); if (divider) - return (long)(l_parent_rate / divider); + req->rate = (long)(l_parent_rate / divider); + else + req->rate = 0; + return 0; } @@ -512,7 +506,7 @@ static const struct clk_ops cdce925_clk_y1_ops = { .prepare = cdce925_clk_prepare, .unprepare = cdce925_clk_unprepare, .recalc_rate = cdce925_clk_recalc_rate, - .round_rate = cdce925_clk_y1_round_rate, + .determine_rate = cdce925_clk_y1_determine_rate, .set_rate = cdce925_clk_y1_set_rate, }; @@ -602,15 +596,25 @@ of_clk_cdce925_get(struct of_phandle_args *clkspec, void *_data) return &data->clk[idx].hw; } +static int cdce925_regulator_enable(struct device *dev, const char *name) +{ + int err; + + err = devm_regulator_get_enable(dev, name); + if (err) + dev_err_probe(dev, err, "Failed to enable %s:\n", name); + + return err; +} + /* The CDCE925 uses a funky way to read/write registers. Bulk mode is * just weird, so just use the single byte mode exclusively. */ -static struct regmap_bus regmap_cdce925_bus = { +static const struct regmap_bus regmap_cdce925_bus = { .write = cdce925_regmap_i2c_write, .read = cdce925_regmap_i2c_read, }; -static int cdce925_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int cdce925_probe(struct i2c_client *client) { struct clk_cdce925_chip *data; struct device_node *node = client->dev.of_node; @@ -626,16 +630,25 @@ static int cdce925_probe(struct i2c_client *client, .name = "configuration0", .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; dev_dbg(&client->dev, "%s\n", __func__); + + err = cdce925_regulator_enable(&client->dev, "vdd"); + if (err) + return err; + + err = cdce925_regulator_enable(&client->dev, "vddout"); + if (err) + return err; + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->i2c_client = client; - data->chip_info = &clk_cdce925_chip_info_tbl[id->driver_data]; + data->chip_info = i2c_get_match_data(client); config.max_register = CDCE925_OFFSET_PLL + data->chip_info->num_plls * 0x10 - 1; data->regmap = devm_regmap_init(&client->dev, ®map_cdce925_bus, @@ -665,12 +678,16 @@ static int cdce925_probe(struct i2c_client *client, init.ops = &cdce925_pll_ops; init.flags = 0; init.parent_names = &parent_name; - init.num_parents = parent_name ? 1 : 0; + init.num_parents = 1; /* Register PLL clocks */ for (i = 0; i < data->chip_info->num_plls; ++i) { - pll_clk_name[i] = kasprintf(GFP_KERNEL, "%s.pll%d", - client->dev.of_node->name, i); + pll_clk_name[i] = kasprintf(GFP_KERNEL, "%pOFn.pll%d", + client->dev.of_node, i); + if (!pll_clk_name[i]) { + err = -ENOMEM; + goto error; + } init.name = pll_clk_name[i]; data->pll[i].chip = data; data->pll[i].hw.init = &init; @@ -703,6 +720,7 @@ static int cdce925_probe(struct i2c_client *client, 0x12 + (i*CDCE925_OFFSET_PLL), 0x07, value & 0x07); } + of_node_put(np_output); } /* Register output clock Y1 */ @@ -710,7 +728,11 @@ static int cdce925_probe(struct i2c_client *client, init.flags = 0; init.num_parents = 1; init.parent_names = &parent_name; /* Mux Y1 to input */ - init.name = kasprintf(GFP_KERNEL, "%s.Y1", client->dev.of_node->name); + init.name = kasprintf(GFP_KERNEL, "%pOFn.Y1", client->dev.of_node); + if (!init.name) { + err = -ENOMEM; + goto error; + } data->clk[0].chip = data; data->clk[0].hw.init = &init; data->clk[0].index = 0; @@ -727,8 +749,12 @@ static int cdce925_probe(struct i2c_client *client, init.flags = CLK_SET_RATE_PARENT; init.num_parents = 1; for (i = 1; i < data->chip_info->num_outputs; ++i) { - init.name = kasprintf(GFP_KERNEL, "%s.Y%d", - client->dev.of_node->name, i+1); + init.name = kasprintf(GFP_KERNEL, "%pOFn.Y%d", + client->dev.of_node, i+1); + if (!init.name) { + err = -ENOMEM; + goto error; + } data->clk[i].chip = data; data->clk[i].hw.init = &init; data->clk[i].index = i; @@ -779,28 +805,48 @@ error: return err; } +static const struct clk_cdce925_chip_info clk_cdce913_info = { + .num_plls = 1, + .num_outputs = 3, +}; + +static const struct clk_cdce925_chip_info clk_cdce925_info = { + .num_plls = 2, + .num_outputs = 5, +}; + +static const struct clk_cdce925_chip_info clk_cdce937_info = { + .num_plls = 3, + .num_outputs = 7, +}; + +static const struct clk_cdce925_chip_info clk_cdce949_info = { + .num_plls = 4, + .num_outputs = 9, +}; + static const struct i2c_device_id cdce925_id[] = { - { "cdce913", CDCE913 }, - { "cdce925", CDCE925 }, - { "cdce937", CDCE937 }, - { "cdce949", CDCE949 }, + { "cdce913", (kernel_ulong_t)&clk_cdce913_info }, + { "cdce925", (kernel_ulong_t)&clk_cdce925_info }, + { "cdce937", (kernel_ulong_t)&clk_cdce937_info }, + { "cdce949", (kernel_ulong_t)&clk_cdce949_info }, { } }; MODULE_DEVICE_TABLE(i2c, cdce925_id); static const struct of_device_id clk_cdce925_of_match[] = { - { .compatible = "ti,cdce913" }, - { .compatible = "ti,cdce925" }, - { .compatible = "ti,cdce937" }, - { .compatible = "ti,cdce949" }, - { }, + { .compatible = "ti,cdce913", .data = &clk_cdce913_info }, + { .compatible = "ti,cdce925", .data = &clk_cdce925_info }, + { .compatible = "ti,cdce937", .data = &clk_cdce937_info }, + { .compatible = "ti,cdce949", .data = &clk_cdce949_info }, + { } }; MODULE_DEVICE_TABLE(of, clk_cdce925_of_match); static struct i2c_driver cdce925_driver = { .driver = { .name = "cdce925", - .of_match_table = of_match_ptr(clk_cdce925_of_match), + .of_match_table = clk_cdce925_of_match, }, .probe = cdce925_probe, .id_table = cdce925_id, |
