diff options
Diffstat (limited to 'drivers/clk/clk-versaclock5.c')
-rw-r--r-- | drivers/clk/clk-versaclock5.c | 76 |
1 files changed, 58 insertions, 18 deletions
diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index 56741f3cf0a3..ea7d552a2f2b 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -113,10 +113,29 @@ #define VC5_MUX_IN_XIN BIT(0) #define VC5_MUX_IN_CLKIN BIT(1) +/* Maximum number of clk_out supported by this driver */ +#define VC5_MAX_CLK_OUT_NUM 5 + +/* Maximum number of FODs supported by this driver */ +#define VC5_MAX_FOD_NUM 4 + +/* flags to describe chip features */ +/* chip has built-in oscilator */ +#define VC5_HAS_INTERNAL_XTAL BIT(0) + /* Supported IDT VC5 models. */ enum vc5_model { IDT_VC5_5P49V5923, IDT_VC5_5P49V5933, + IDT_VC5_5P49V5935, +}; + +/* Structure to describe features of a particular VC5 model */ +struct vc5_chip_info { + const enum vc5_model model; + const unsigned int clk_fod_cnt; + const unsigned int clk_out_cnt; + const u32 flags; }; struct vc5_driver_data; @@ -132,15 +151,15 @@ struct vc5_hw_data { struct vc5_driver_data { struct i2c_client *client; struct regmap *regmap; - enum vc5_model model; + const struct vc5_chip_info *chip_info; struct clk *pin_xin; struct clk *pin_clkin; unsigned char clk_mux_ins; struct clk_hw clk_mux; struct vc5_hw_data clk_pll; - struct vc5_hw_data clk_fod[2]; - struct vc5_hw_data clk_out[3]; + struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM]; + struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM]; }; static const char * const vc5_mux_names[] = { @@ -563,7 +582,7 @@ static struct clk_hw *vc5_of_clk_get(struct of_phandle_args *clkspec, struct vc5_driver_data *vc5 = data; unsigned int idx = clkspec->args[0]; - if (idx > 2) + if (idx >= vc5->chip_info->clk_out_cnt) return ERR_PTR(-EINVAL); return &vc5->clk_out[idx].hw; @@ -576,6 +595,7 @@ static int vc5_map_index_to_output(const enum vc5_model model, case IDT_VC5_5P49V5933: return (n == 0) ? 0 : 3; case IDT_VC5_5P49V5923: + case IDT_VC5_5P49V5935: default: return n; } @@ -586,12 +606,10 @@ static const struct of_device_id clk_vc5_of_match[]; static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct of_device_id *of_id = - of_match_device(clk_vc5_of_match, &client->dev); struct vc5_driver_data *vc5; struct clk_init_data init; const char *parent_names[2]; - unsigned int n, idx; + unsigned int n, idx = 0; int ret; vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL); @@ -600,7 +618,7 @@ static int vc5_probe(struct i2c_client *client, i2c_set_clientdata(client, vc5); vc5->client = client; - vc5->model = (enum vc5_model)of_id->data; + vc5->chip_info = of_device_get_match_data(&client->dev); vc5->pin_xin = devm_clk_get(&client->dev, "xin"); if (PTR_ERR(vc5->pin_xin) == -EPROBE_DEFER) @@ -622,8 +640,7 @@ static int vc5_probe(struct i2c_client *client, if (!IS_ERR(vc5->pin_xin)) { vc5->clk_mux_ins |= VC5_MUX_IN_XIN; parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin); - } else if (vc5->model == IDT_VC5_5P49V5933) { - /* IDT VC5 5P49V5933 has built-in oscilator. */ + } else if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) { vc5->pin_xin = clk_register_fixed_rate(&client->dev, "internal-xtal", NULL, 0, 25000000); @@ -672,8 +689,8 @@ static int vc5_probe(struct i2c_client *client, } /* Register FODs */ - for (n = 0; n < 2; n++) { - idx = vc5_map_index_to_output(vc5->model, n); + for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) { + idx = vc5_map_index_to_output(vc5->chip_info->model, n); memset(&init, 0, sizeof(init)); init.name = vc5_fod_names[idx]; init.ops = &vc5_fod_ops; @@ -709,8 +726,8 @@ static int vc5_probe(struct i2c_client *client, } /* Register FOD-connected OUTx outputs */ - for (n = 1; n < 3; n++) { - idx = vc5_map_index_to_output(vc5->model, n - 1); + for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) { + idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1); parent_names[0] = vc5_fod_names[idx]; if (n == 1) parent_names[1] = vc5_mux_names[0]; @@ -744,7 +761,7 @@ static int vc5_probe(struct i2c_client *client, return 0; err_clk: - if (vc5->model == IDT_VC5_5P49V5933) + if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) clk_unregister_fixed_rate(vc5->pin_xin); return ret; } @@ -755,22 +772,45 @@ static int vc5_remove(struct i2c_client *client) of_clk_del_provider(client->dev.of_node); - if (vc5->model == IDT_VC5_5P49V5933) + if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) clk_unregister_fixed_rate(vc5->pin_xin); return 0; } +static const struct vc5_chip_info idt_5p49v5923_info = { + .model = IDT_VC5_5P49V5923, + .clk_fod_cnt = 2, + .clk_out_cnt = 3, + .flags = 0, +}; + +static const struct vc5_chip_info idt_5p49v5933_info = { + .model = IDT_VC5_5P49V5933, + .clk_fod_cnt = 2, + .clk_out_cnt = 3, + .flags = VC5_HAS_INTERNAL_XTAL, +}; + +static const struct vc5_chip_info idt_5p49v5935_info = { + .model = IDT_VC5_5P49V5935, + .clk_fod_cnt = 4, + .clk_out_cnt = 5, + .flags = VC5_HAS_INTERNAL_XTAL, +}; + static const struct i2c_device_id vc5_id[] = { { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 }, { "5p49v5933", .driver_data = IDT_VC5_5P49V5933 }, + { "5p49v5935", .driver_data = IDT_VC5_5P49V5935 }, { } }; MODULE_DEVICE_TABLE(i2c, vc5_id); static const struct of_device_id clk_vc5_of_match[] = { - { .compatible = "idt,5p49v5923", .data = (void *)IDT_VC5_5P49V5923 }, - { .compatible = "idt,5p49v5933", .data = (void *)IDT_VC5_5P49V5933 }, + { .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info }, + { .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info }, + { .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info }, { }, }; MODULE_DEVICE_TABLE(of, clk_vc5_of_match); |