mirror of https://gitee.com/openkylin/linux.git
Merge branch 'clk-vc5' into clk-next
* clk-vc5: clk: vc5: Enable addition output configurations of the Versaclock dt: Add additional option bindings for IDT VersaClock clk: vc5: Allow Versaclock driver to support multiple instances
This commit is contained in:
commit
7aae3c161e
|
@ -31,6 +31,29 @@ Required properties:
|
||||||
- 5p49v5933 and
|
- 5p49v5933 and
|
||||||
- 5p49v5935: (optional) property not present or "clkin".
|
- 5p49v5935: (optional) property not present or "clkin".
|
||||||
|
|
||||||
|
For all output ports, a corresponding, optional child node named OUT1,
|
||||||
|
OUT2, etc. can represent a each output, and the node can be used to
|
||||||
|
specify the following:
|
||||||
|
|
||||||
|
- itd,mode: can be one of the following:
|
||||||
|
- VC5_LVPECL
|
||||||
|
- VC5_CMOS
|
||||||
|
- VC5_HCSL33
|
||||||
|
- VC5_LVDS
|
||||||
|
- VC5_CMOS2
|
||||||
|
- VC5_CMOSD
|
||||||
|
- VC5_HCSL25
|
||||||
|
|
||||||
|
- idt,voltage-microvolts: can be one of the following
|
||||||
|
- 1800000
|
||||||
|
- 2500000
|
||||||
|
- 3300000
|
||||||
|
- idt,slew-percent: Percent of normal, can be one of
|
||||||
|
- 80
|
||||||
|
- 85
|
||||||
|
- 90
|
||||||
|
- 100
|
||||||
|
|
||||||
==Mapping between clock specifier and physical pins==
|
==Mapping between clock specifier and physical pins==
|
||||||
|
|
||||||
When referencing the provided clock in the DT using phandle and
|
When referencing the provided clock in the DT using phandle and
|
||||||
|
@ -81,6 +104,16 @@ i2c-master-node {
|
||||||
/* Connect XIN input to 25MHz reference */
|
/* Connect XIN input to 25MHz reference */
|
||||||
clocks = <&ref25m>;
|
clocks = <&ref25m>;
|
||||||
clock-names = "xin";
|
clock-names = "xin";
|
||||||
|
|
||||||
|
OUT1 {
|
||||||
|
itd,mode = <VC5_CMOS>;
|
||||||
|
idt,voltage-microvolts = <1800000>;
|
||||||
|
idt,slew-percent = <80>;
|
||||||
|
};
|
||||||
|
OUT2 {
|
||||||
|
...
|
||||||
|
};
|
||||||
|
...
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#include <dt-bindings/clk/versaclock.h>
|
||||||
|
|
||||||
/* VersaClock5 registers */
|
/* VersaClock5 registers */
|
||||||
#define VC5_OTP_CONTROL 0x00
|
#define VC5_OTP_CONTROL 0x00
|
||||||
|
|
||||||
|
@ -89,6 +91,28 @@
|
||||||
|
|
||||||
/* Clock control register for clock 1,2 */
|
/* Clock control register for clock 1,2 */
|
||||||
#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
|
#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_SHIFT 5
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_MASK GENMASK(7, VC5_CLK_OUTPUT_CFG0_CFG_SHIFT)
|
||||||
|
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_LVPECL (VC5_LVPECL)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_CMOS (VC5_CMOS)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_HCSL33 (VC5_HCSL33)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_LVDS (VC5_LVDS)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_CMOS2 (VC5_CMOS2)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_CMOSD (VC5_CMOSD)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_CFG_HCSL25 (VC5_HCSL25)
|
||||||
|
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_PWR_SHIFT 3
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_PWR_MASK GENMASK(4, VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_PWR_18 (0<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_PWR_25 (2<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_PWR_33 (3<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT 0
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_SLEW_MASK GENMASK(1, VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_SLEW_80 (0<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_SLEW_85 (1<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_SLEW_90 (2<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
|
||||||
|
#define VC5_CLK_OUTPUT_CFG0_SLEW_100 (3<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
|
||||||
#define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0)
|
#define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0)
|
||||||
|
|
||||||
#define VC5_CLK_OE_SHDN 0x68
|
#define VC5_CLK_OE_SHDN 0x68
|
||||||
|
@ -143,6 +167,8 @@ struct vc5_hw_data {
|
||||||
u32 div_int;
|
u32 div_int;
|
||||||
u32 div_frc;
|
u32 div_frc;
|
||||||
unsigned int num;
|
unsigned int num;
|
||||||
|
unsigned int clk_output_cfg0;
|
||||||
|
unsigned int clk_output_cfg0_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vc5_driver_data {
|
struct vc5_driver_data {
|
||||||
|
@ -161,30 +187,6 @@ struct vc5_driver_data {
|
||||||
struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
|
struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char * const vc5_mux_names[] = {
|
|
||||||
"mux"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * const vc5_dbl_names[] = {
|
|
||||||
"dbl"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * const vc5_pfd_names[] = {
|
|
||||||
"pfd"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * const vc5_pll_names[] = {
|
|
||||||
"pll"
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * const vc5_fod_names[] = {
|
|
||||||
"fod0", "fod1", "fod2", "fod3",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * const vc5_clk_out_names[] = {
|
|
||||||
"out0_sel_i2cb", "out1", "out2", "out3", "out4",
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VersaClock5 i2c regmap
|
* VersaClock5 i2c regmap
|
||||||
*/
|
*/
|
||||||
|
@ -591,6 +593,17 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
|
||||||
regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
|
regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
|
||||||
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
|
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
|
||||||
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
|
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
|
||||||
|
if (hwdata->clk_output_cfg0_mask) {
|
||||||
|
dev_dbg(&vc5->client->dev, "Update output %d mask 0x%0X val 0x%0X\n",
|
||||||
|
hwdata->num, hwdata->clk_output_cfg0_mask,
|
||||||
|
hwdata->clk_output_cfg0);
|
||||||
|
|
||||||
|
regmap_update_bits(vc5->regmap,
|
||||||
|
VC5_CLK_OUTPUT_CFG(hwdata->num, 0),
|
||||||
|
hwdata->clk_output_cfg0_mask,
|
||||||
|
hwdata->clk_output_cfg0);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,10 +703,123 @@ static int vc5_map_index_to_output(const enum vc5_model model,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vc5_update_mode(struct device_node *np_output,
|
||||||
|
struct vc5_hw_data *clk_out)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np_output, "idt,mode", &value)) {
|
||||||
|
clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_CFG_MASK;
|
||||||
|
switch (value) {
|
||||||
|
case VC5_CLK_OUTPUT_CFG0_CFG_LVPECL:
|
||||||
|
case VC5_CLK_OUTPUT_CFG0_CFG_CMOS:
|
||||||
|
case VC5_CLK_OUTPUT_CFG0_CFG_HCSL33:
|
||||||
|
case VC5_CLK_OUTPUT_CFG0_CFG_LVDS:
|
||||||
|
case VC5_CLK_OUTPUT_CFG0_CFG_CMOS2:
|
||||||
|
case VC5_CLK_OUTPUT_CFG0_CFG_CMOSD:
|
||||||
|
case VC5_CLK_OUTPUT_CFG0_CFG_HCSL25:
|
||||||
|
clk_out->clk_output_cfg0 |=
|
||||||
|
value << VC5_CLK_OUTPUT_CFG0_CFG_SHIFT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vc5_update_power(struct device_node *np_output,
|
||||||
|
struct vc5_hw_data *clk_out)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np_output,
|
||||||
|
"idt,voltage-microvolts", &value)) {
|
||||||
|
clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_PWR_MASK;
|
||||||
|
switch (value) {
|
||||||
|
case 1800000:
|
||||||
|
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_18;
|
||||||
|
break;
|
||||||
|
case 2500000:
|
||||||
|
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_25;
|
||||||
|
break;
|
||||||
|
case 3300000:
|
||||||
|
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_33;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vc5_update_slew(struct device_node *np_output,
|
||||||
|
struct vc5_hw_data *clk_out)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np_output, "idt,slew-percent", &value)) {
|
||||||
|
clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_SLEW_MASK;
|
||||||
|
switch (value) {
|
||||||
|
case 80:
|
||||||
|
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_80;
|
||||||
|
break;
|
||||||
|
case 85:
|
||||||
|
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_85;
|
||||||
|
break;
|
||||||
|
case 90:
|
||||||
|
clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_90;
|
||||||
|
break;
|
||||||
|
case 100:
|
||||||
|
clk_out->clk_output_cfg0 |=
|
||||||
|
VC5_CLK_OUTPUT_CFG0_SLEW_100;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vc5_get_output_config(struct i2c_client *client,
|
||||||
|
struct vc5_hw_data *clk_out)
|
||||||
|
{
|
||||||
|
struct device_node *np_output;
|
||||||
|
char *child_name;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
child_name = kasprintf(GFP_KERNEL, "OUT%d", clk_out->num + 1);
|
||||||
|
np_output = of_get_child_by_name(client->dev.of_node, child_name);
|
||||||
|
kfree(child_name);
|
||||||
|
if (!np_output)
|
||||||
|
goto output_done;
|
||||||
|
|
||||||
|
ret = vc5_update_mode(np_output, clk_out);
|
||||||
|
if (ret)
|
||||||
|
goto output_error;
|
||||||
|
|
||||||
|
ret = vc5_update_power(np_output, clk_out);
|
||||||
|
if (ret)
|
||||||
|
goto output_error;
|
||||||
|
|
||||||
|
ret = vc5_update_slew(np_output, clk_out);
|
||||||
|
|
||||||
|
output_error:
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"Invalid clock output configuration OUT%d\n",
|
||||||
|
clk_out->num + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
of_node_put(np_output);
|
||||||
|
|
||||||
|
output_done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct of_device_id clk_vc5_of_match[];
|
static const struct of_device_id clk_vc5_of_match[];
|
||||||
|
|
||||||
static int vc5_probe(struct i2c_client *client,
|
static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
const struct i2c_device_id *id)
|
|
||||||
{
|
{
|
||||||
struct vc5_driver_data *vc5;
|
struct vc5_driver_data *vc5;
|
||||||
struct clk_init_data init;
|
struct clk_init_data init;
|
||||||
|
@ -750,12 +876,13 @@ static int vc5_probe(struct i2c_client *client,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
init.name = vc5_mux_names[0];
|
init.name = kasprintf(GFP_KERNEL, "%pOFn.mux", client->dev.of_node);
|
||||||
init.ops = &vc5_mux_ops;
|
init.ops = &vc5_mux_ops;
|
||||||
init.flags = 0;
|
init.flags = 0;
|
||||||
init.parent_names = parent_names;
|
init.parent_names = parent_names;
|
||||||
vc5->clk_mux.init = &init;
|
vc5->clk_mux.init = &init;
|
||||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
|
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
|
||||||
|
kfree(init.name); /* clock framework made a copy of the name */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||||
goto err_clk;
|
goto err_clk;
|
||||||
|
@ -764,13 +891,16 @@ static int vc5_probe(struct i2c_client *client,
|
||||||
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
|
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
|
||||||
/* Register frequency doubler */
|
/* Register frequency doubler */
|
||||||
memset(&init, 0, sizeof(init));
|
memset(&init, 0, sizeof(init));
|
||||||
init.name = vc5_dbl_names[0];
|
init.name = kasprintf(GFP_KERNEL, "%pOFn.dbl",
|
||||||
|
client->dev.of_node);
|
||||||
init.ops = &vc5_dbl_ops;
|
init.ops = &vc5_dbl_ops;
|
||||||
init.flags = CLK_SET_RATE_PARENT;
|
init.flags = CLK_SET_RATE_PARENT;
|
||||||
init.parent_names = vc5_mux_names;
|
init.parent_names = parent_names;
|
||||||
|
parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
|
||||||
init.num_parents = 1;
|
init.num_parents = 1;
|
||||||
vc5->clk_mul.init = &init;
|
vc5->clk_mul.init = &init;
|
||||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
|
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
|
||||||
|
kfree(init.name); /* clock framework made a copy of the name */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "unable to register %s\n",
|
dev_err(&client->dev, "unable to register %s\n",
|
||||||
init.name);
|
init.name);
|
||||||
|
@ -780,16 +910,18 @@ static int vc5_probe(struct i2c_client *client,
|
||||||
|
|
||||||
/* Register PFD */
|
/* Register PFD */
|
||||||
memset(&init, 0, sizeof(init));
|
memset(&init, 0, sizeof(init));
|
||||||
init.name = vc5_pfd_names[0];
|
init.name = kasprintf(GFP_KERNEL, "%pOFn.pfd", client->dev.of_node);
|
||||||
init.ops = &vc5_pfd_ops;
|
init.ops = &vc5_pfd_ops;
|
||||||
init.flags = CLK_SET_RATE_PARENT;
|
init.flags = CLK_SET_RATE_PARENT;
|
||||||
|
init.parent_names = parent_names;
|
||||||
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
|
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
|
||||||
init.parent_names = vc5_dbl_names;
|
parent_names[0] = clk_hw_get_name(&vc5->clk_mul);
|
||||||
else
|
else
|
||||||
init.parent_names = vc5_mux_names;
|
parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
|
||||||
init.num_parents = 1;
|
init.num_parents = 1;
|
||||||
vc5->clk_pfd.init = &init;
|
vc5->clk_pfd.init = &init;
|
||||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
|
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
|
||||||
|
kfree(init.name); /* clock framework made a copy of the name */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||||
goto err_clk;
|
goto err_clk;
|
||||||
|
@ -797,15 +929,17 @@ static int vc5_probe(struct i2c_client *client,
|
||||||
|
|
||||||
/* Register PLL */
|
/* Register PLL */
|
||||||
memset(&init, 0, sizeof(init));
|
memset(&init, 0, sizeof(init));
|
||||||
init.name = vc5_pll_names[0];
|
init.name = kasprintf(GFP_KERNEL, "%pOFn.pll", client->dev.of_node);
|
||||||
init.ops = &vc5_pll_ops;
|
init.ops = &vc5_pll_ops;
|
||||||
init.flags = CLK_SET_RATE_PARENT;
|
init.flags = CLK_SET_RATE_PARENT;
|
||||||
init.parent_names = vc5_pfd_names;
|
init.parent_names = parent_names;
|
||||||
|
parent_names[0] = clk_hw_get_name(&vc5->clk_pfd);
|
||||||
init.num_parents = 1;
|
init.num_parents = 1;
|
||||||
vc5->clk_pll.num = 0;
|
vc5->clk_pll.num = 0;
|
||||||
vc5->clk_pll.vc5 = vc5;
|
vc5->clk_pll.vc5 = vc5;
|
||||||
vc5->clk_pll.hw.init = &init;
|
vc5->clk_pll.hw.init = &init;
|
||||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
|
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
|
||||||
|
kfree(init.name); /* clock framework made a copy of the name */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||||
goto err_clk;
|
goto err_clk;
|
||||||
|
@ -815,15 +949,18 @@ static int vc5_probe(struct i2c_client *client,
|
||||||
for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
|
for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
|
||||||
idx = vc5_map_index_to_output(vc5->chip_info->model, n);
|
idx = vc5_map_index_to_output(vc5->chip_info->model, n);
|
||||||
memset(&init, 0, sizeof(init));
|
memset(&init, 0, sizeof(init));
|
||||||
init.name = vc5_fod_names[idx];
|
init.name = kasprintf(GFP_KERNEL, "%pOFn.fod%d",
|
||||||
|
client->dev.of_node, idx);
|
||||||
init.ops = &vc5_fod_ops;
|
init.ops = &vc5_fod_ops;
|
||||||
init.flags = CLK_SET_RATE_PARENT;
|
init.flags = CLK_SET_RATE_PARENT;
|
||||||
init.parent_names = vc5_pll_names;
|
init.parent_names = parent_names;
|
||||||
|
parent_names[0] = clk_hw_get_name(&vc5->clk_pll.hw);
|
||||||
init.num_parents = 1;
|
init.num_parents = 1;
|
||||||
vc5->clk_fod[n].num = idx;
|
vc5->clk_fod[n].num = idx;
|
||||||
vc5->clk_fod[n].vc5 = vc5;
|
vc5->clk_fod[n].vc5 = vc5;
|
||||||
vc5->clk_fod[n].hw.init = &init;
|
vc5->clk_fod[n].hw.init = &init;
|
||||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
|
ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
|
||||||
|
kfree(init.name); /* clock framework made a copy of the name */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "unable to register %s\n",
|
dev_err(&client->dev, "unable to register %s\n",
|
||||||
init.name);
|
init.name);
|
||||||
|
@ -833,32 +970,36 @@ static int vc5_probe(struct i2c_client *client,
|
||||||
|
|
||||||
/* Register MUX-connected OUT0_I2C_SELB output */
|
/* Register MUX-connected OUT0_I2C_SELB output */
|
||||||
memset(&init, 0, sizeof(init));
|
memset(&init, 0, sizeof(init));
|
||||||
init.name = vc5_clk_out_names[0];
|
init.name = kasprintf(GFP_KERNEL, "%pOFn.out0_sel_i2cb",
|
||||||
|
client->dev.of_node);
|
||||||
init.ops = &vc5_clk_out_ops;
|
init.ops = &vc5_clk_out_ops;
|
||||||
init.flags = CLK_SET_RATE_PARENT;
|
init.flags = CLK_SET_RATE_PARENT;
|
||||||
init.parent_names = vc5_mux_names;
|
init.parent_names = parent_names;
|
||||||
|
parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
|
||||||
init.num_parents = 1;
|
init.num_parents = 1;
|
||||||
vc5->clk_out[0].num = idx;
|
vc5->clk_out[0].num = idx;
|
||||||
vc5->clk_out[0].vc5 = vc5;
|
vc5->clk_out[0].vc5 = vc5;
|
||||||
vc5->clk_out[0].hw.init = &init;
|
vc5->clk_out[0].hw.init = &init;
|
||||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
|
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
|
||||||
|
kfree(init.name); /* clock framework made a copy of the name */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "unable to register %s\n",
|
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||||
init.name);
|
|
||||||
goto err_clk;
|
goto err_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register FOD-connected OUTx outputs */
|
/* Register FOD-connected OUTx outputs */
|
||||||
for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
|
for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
|
||||||
idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1);
|
idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1);
|
||||||
parent_names[0] = vc5_fod_names[idx];
|
parent_names[0] = clk_hw_get_name(&vc5->clk_fod[idx].hw);
|
||||||
if (n == 1)
|
if (n == 1)
|
||||||
parent_names[1] = vc5_mux_names[0];
|
parent_names[1] = clk_hw_get_name(&vc5->clk_mux);
|
||||||
else
|
else
|
||||||
parent_names[1] = vc5_clk_out_names[n - 1];
|
parent_names[1] =
|
||||||
|
clk_hw_get_name(&vc5->clk_out[n - 1].hw);
|
||||||
|
|
||||||
memset(&init, 0, sizeof(init));
|
memset(&init, 0, sizeof(init));
|
||||||
init.name = vc5_clk_out_names[idx + 1];
|
init.name = kasprintf(GFP_KERNEL, "%pOFn.out%d",
|
||||||
|
client->dev.of_node, idx + 1);
|
||||||
init.ops = &vc5_clk_out_ops;
|
init.ops = &vc5_clk_out_ops;
|
||||||
init.flags = CLK_SET_RATE_PARENT;
|
init.flags = CLK_SET_RATE_PARENT;
|
||||||
init.parent_names = parent_names;
|
init.parent_names = parent_names;
|
||||||
|
@ -866,13 +1007,18 @@ static int vc5_probe(struct i2c_client *client,
|
||||||
vc5->clk_out[n].num = idx;
|
vc5->clk_out[n].num = idx;
|
||||||
vc5->clk_out[n].vc5 = vc5;
|
vc5->clk_out[n].vc5 = vc5;
|
||||||
vc5->clk_out[n].hw.init = &init;
|
vc5->clk_out[n].hw.init = &init;
|
||||||
ret = devm_clk_hw_register(&client->dev,
|
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw);
|
||||||
&vc5->clk_out[n].hw);
|
kfree(init.name); /* clock framework made a copy of the name */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "unable to register %s\n",
|
dev_err(&client->dev, "unable to register %s\n",
|
||||||
init.name);
|
init.name);
|
||||||
goto err_clk;
|
goto err_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fetch Clock Output configuration from DT (if specified) */
|
||||||
|
ret = vc5_get_output_config(client, &vc5->clk_out[n]);
|
||||||
|
if (ret)
|
||||||
|
goto err_clk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
|
ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
|
/* This file defines field values used by the versaclock 6 family
|
||||||
|
* for defining output type
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VC5_LVPECL 0
|
||||||
|
#define VC5_CMOS 1
|
||||||
|
#define VC5_HCSL33 2
|
||||||
|
#define VC5_LVDS 3
|
||||||
|
#define VC5_CMOS2 4
|
||||||
|
#define VC5_CMOSD 5
|
||||||
|
#define VC5_HCSL25 6
|
Loading…
Reference in New Issue