Skip to content

Commit f3d661d

Browse files
aford173bebarino
authored andcommitted
clk: vc5: Add support for optional load capacitance
There are two registers which can set the load capacitance for XTAL1 and XTAL2. These are optional registers when using an external crystal. Parse the device tree and set the corresponding registers accordingly. Signed-off-by: Adam Ford <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Luca Ceresoli <[email protected]> Signed-off-by: Stephen Boyd <[email protected]>
1 parent 31e7aa7 commit f3d661d

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

drivers/clk/clk-versaclock5.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,63 @@ static int vc5_update_power(struct device_node *np_output,
759759
return 0;
760760
}
761761

762+
static int vc5_map_cap_value(u32 femtofarads)
763+
{
764+
int mapped_value;
765+
766+
/*
767+
* The datasheet explicitly states 9000 - 25000 with 0.5pF
768+
* steps, but the Programmer's guide shows the steps are 0.430pF.
769+
* After getting feedback from Renesas, the .5pF steps were the
770+
* goal, but 430nF was the actual values.
771+
* Because of this, the actual range goes to 22760 instead of 25000
772+
*/
773+
if (femtofarads < 9000 || femtofarads > 22760)
774+
return -EINVAL;
775+
776+
/*
777+
* The Programmer's guide shows XTAL[5:0] but in reality,
778+
* XTAL[0] and XTAL[1] are both LSB which makes the math
779+
* strange. With clarfication from Renesas, setting the
780+
* values should be simpler by ignoring XTAL[0]
781+
*/
782+
mapped_value = DIV_ROUND_CLOSEST(femtofarads - 9000, 430);
783+
784+
/*
785+
* Since the calculation ignores XTAL[0], there is one
786+
* special case where mapped_value = 32. In reality, this means
787+
* the real mapped value should be 111111b. In other cases,
788+
* the mapped_value needs to be shifted 1 to the left.
789+
*/
790+
if (mapped_value > 31)
791+
mapped_value = 0x3f;
792+
else
793+
mapped_value <<= 1;
794+
795+
return mapped_value;
796+
}
797+
static int vc5_update_cap_load(struct device_node *node, struct vc5_driver_data *vc5)
798+
{
799+
u32 value;
800+
int mapped_value;
801+
802+
if (!of_property_read_u32(node, "idt,xtal-load-femtofarads", &value)) {
803+
mapped_value = vc5_map_cap_value(value);
804+
if (mapped_value < 0)
805+
return mapped_value;
806+
807+
/*
808+
* The mapped_value is really the high 6 bits of
809+
* VC5_XTAL_X1_LOAD_CAP and VC5_XTAL_X2_LOAD_CAP, so
810+
* shift the value 2 places.
811+
*/
812+
regmap_update_bits(vc5->regmap, VC5_XTAL_X1_LOAD_CAP, ~0x03, mapped_value << 2);
813+
regmap_update_bits(vc5->regmap, VC5_XTAL_X2_LOAD_CAP, ~0x03, mapped_value << 2);
814+
}
815+
816+
return 0;
817+
}
818+
762819
static int vc5_update_slew(struct device_node *np_output,
763820
struct vc5_out_data *clk_out)
764821
{
@@ -884,6 +941,13 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
884941
return -EINVAL;
885942
}
886943

944+
/* Configure Optional Loading Capacitance for external XTAL */
945+
if (!(vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)) {
946+
ret = vc5_update_cap_load(client->dev.of_node, vc5);
947+
if (ret)
948+
goto err_clk_register;
949+
}
950+
887951
init.name = kasprintf(GFP_KERNEL, "%pOFn.mux", client->dev.of_node);
888952
init.ops = &vc5_mux_ops;
889953
init.flags = 0;

0 commit comments

Comments
 (0)