Skip to content

Commit cc32378

Browse files
larsclausenbebarino
authored andcommitted
clk: vc5: Check IO access results
The devices of the versaclk clock generator family use an I2C control bus. IO access on an I2C bus can fail for various reasons. The driver currently ignores the return value of most IO operations. This results in silent failure. To avoid this check the return value and in case of an error abort the operation and propagate the error code to the caller. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Link: https://lore.kernel.org/r/20220719094637.844946-1-lars@metafoo.de Reviewed-by: Luca Ceresoli <luca@lucaceresoli.net> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
1 parent 568035b commit cc32378

File tree

1 file changed

+91
-50
lines changed

1 file changed

+91
-50
lines changed

drivers/clk/clk-versaclock5.c

Lines changed: 91 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,12 @@ static unsigned char vc5_mux_get_parent(struct clk_hw *hw)
230230
container_of(hw, struct vc5_driver_data, clk_mux);
231231
const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
232232
unsigned int src;
233+
int ret;
234+
235+
ret = regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src);
236+
if (ret)
237+
return 0;
233238

234-
regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src);
235239
src &= mask;
236240

237241
if (src == VC5_PRIM_SRC_SHDN_EN_XTAL)
@@ -286,8 +290,12 @@ static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
286290
struct vc5_driver_data *vc5 =
287291
container_of(hw, struct vc5_driver_data, clk_mul);
288292
unsigned int premul;
293+
int ret;
294+
295+
ret = regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
296+
if (ret)
297+
return 0;
289298

290-
regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
291299
if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ)
292300
parent_rate *= 2;
293301

@@ -315,11 +323,9 @@ static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
315323
else
316324
mask = 0;
317325

318-
regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
319-
VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
320-
mask);
321-
322-
return 0;
326+
return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
327+
VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
328+
mask);
323329
}
324330

325331
static const struct clk_ops vc5_dbl_ops = {
@@ -334,14 +340,19 @@ static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
334340
struct vc5_driver_data *vc5 =
335341
container_of(hw, struct vc5_driver_data, clk_pfd);
336342
unsigned int prediv, div;
343+
int ret;
337344

338-
regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
345+
ret = regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
346+
if (ret)
347+
return 0;
339348

340349
/* The bypass_prediv is set, PLL fed from Ref_in directly. */
341350
if (prediv & VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV)
342351
return parent_rate;
343352

344-
regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div);
353+
ret = regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div);
354+
if (ret)
355+
return 0;
345356

346357
/* The Sel_prediv2 is set, PLL fed from prediv2 (Ref_in / 2) */
347358
if (div & VC5_REF_DIVIDER_SEL_PREDIV2)
@@ -376,15 +387,18 @@ static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
376387
struct vc5_driver_data *vc5 =
377388
container_of(hw, struct vc5_driver_data, clk_pfd);
378389
unsigned long idiv;
390+
int ret;
379391
u8 div;
380392

381393
/* CLKIN within range of PLL input, feed directly to PLL. */
382394
if (parent_rate <= 50000000) {
383-
regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
384-
VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV,
385-
VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
386-
regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00);
387-
return 0;
395+
ret = regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
396+
VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV,
397+
VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
398+
if (ret)
399+
return ret;
400+
401+
return regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00);
388402
}
389403

390404
idiv = DIV_ROUND_UP(parent_rate, rate);
@@ -395,11 +409,12 @@ static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
395409
else
396410
div = VC5_REF_DIVIDER_REF_DIV(idiv);
397411

398-
regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div);
399-
regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
400-
VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, 0);
412+
ret = regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div);
413+
if (ret)
414+
return ret;
401415

402-
return 0;
416+
return regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
417+
VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, 0);
403418
}
404419

405420
static const struct clk_ops vc5_pfd_ops = {
@@ -551,22 +566,27 @@ static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate,
551566
hwdata->div_int >> 4, hwdata->div_int << 4,
552567
0
553568
};
569+
int ret;
554570

555-
regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
556-
data, 14);
571+
ret = regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
572+
data, 14);
573+
if (ret)
574+
return ret;
557575

558576
/*
559577
* Toggle magic bit in undocumented register for unknown reason.
560578
* This is what the IDT timing commander tool does and the chip
561579
* datasheet somewhat implies this is needed, but the register
562580
* and the bit is not documented.
563581
*/
564-
regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
565-
VC5_GLOBAL_REGISTER_GLOBAL_RESET, 0);
566-
regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
567-
VC5_GLOBAL_REGISTER_GLOBAL_RESET,
568-
VC5_GLOBAL_REGISTER_GLOBAL_RESET);
569-
return 0;
582+
ret = regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
583+
VC5_GLOBAL_REGISTER_GLOBAL_RESET, 0);
584+
if (ret)
585+
return ret;
586+
587+
return regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
588+
VC5_GLOBAL_REGISTER_GLOBAL_RESET,
589+
VC5_GLOBAL_REGISTER_GLOBAL_RESET);
570590
}
571591

572592
static const struct clk_ops vc5_fod_ops = {
@@ -606,7 +626,10 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
606626
* If the input mux is disabled, enable it first and
607627
* select source from matching FOD.
608628
*/
609-
regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
629+
ret = regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
630+
if (ret)
631+
return ret;
632+
610633
if ((src & mask) == 0) {
611634
src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD;
612635
ret = regmap_update_bits(vc5->regmap,
@@ -617,18 +640,24 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
617640
}
618641

619642
/* Enable the clock buffer */
620-
regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
621-
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
622-
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
643+
ret = regmap_update_bits(vc5->regmap,
644+
VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
645+
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
646+
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
647+
if (ret)
648+
return ret;
649+
623650
if (hwdata->clk_output_cfg0_mask) {
624651
dev_dbg(&vc5->client->dev, "Update output %d mask 0x%0X val 0x%0X\n",
625652
hwdata->num, hwdata->clk_output_cfg0_mask,
626653
hwdata->clk_output_cfg0);
627654

628-
regmap_update_bits(vc5->regmap,
629-
VC5_CLK_OUTPUT_CFG(hwdata->num, 0),
630-
hwdata->clk_output_cfg0_mask,
631-
hwdata->clk_output_cfg0);
655+
ret = regmap_update_bits(vc5->regmap,
656+
VC5_CLK_OUTPUT_CFG(hwdata->num, 0),
657+
hwdata->clk_output_cfg0_mask,
658+
hwdata->clk_output_cfg0);
659+
if (ret)
660+
return ret;
632661
}
633662

634663
return 0;
@@ -656,8 +685,12 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
656685
const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
657686
VC5_OUT_DIV_CONTROL_SEL_EXT;
658687
unsigned int src;
688+
int ret;
689+
690+
ret = regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
691+
if (ret)
692+
return 0;
659693

660-
regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
661694
src &= mask;
662695

663696
if (src == 0) /* Input mux set to DISABLED */
@@ -819,22 +852,27 @@ static int vc5_update_cap_load(struct device_node *node, struct vc5_driver_data
819852
{
820853
u32 value;
821854
int mapped_value;
855+
int ret;
822856

823-
if (!of_property_read_u32(node, "idt,xtal-load-femtofarads", &value)) {
824-
mapped_value = vc5_map_cap_value(value);
825-
if (mapped_value < 0)
826-
return mapped_value;
827-
828-
/*
829-
* The mapped_value is really the high 6 bits of
830-
* VC5_XTAL_X1_LOAD_CAP and VC5_XTAL_X2_LOAD_CAP, so
831-
* shift the value 2 places.
832-
*/
833-
regmap_update_bits(vc5->regmap, VC5_XTAL_X1_LOAD_CAP, ~0x03, mapped_value << 2);
834-
regmap_update_bits(vc5->regmap, VC5_XTAL_X2_LOAD_CAP, ~0x03, mapped_value << 2);
835-
}
857+
if (of_property_read_u32(node, "idt,xtal-load-femtofarads", &value))
858+
return 0;
836859

837-
return 0;
860+
mapped_value = vc5_map_cap_value(value);
861+
if (mapped_value < 0)
862+
return mapped_value;
863+
864+
/*
865+
* The mapped_value is really the high 6 bits of
866+
* VC5_XTAL_X1_LOAD_CAP and VC5_XTAL_X2_LOAD_CAP, so
867+
* shift the value 2 places.
868+
*/
869+
ret = regmap_update_bits(vc5->regmap, VC5_XTAL_X1_LOAD_CAP, ~0x03,
870+
mapped_value << 2);
871+
if (ret)
872+
return ret;
873+
874+
return regmap_update_bits(vc5->regmap, VC5_XTAL_X2_LOAD_CAP, ~0x03,
875+
mapped_value << 2);
838876
}
839877

840878
static int vc5_update_slew(struct device_node *np_output,
@@ -956,7 +994,10 @@ static int vc5_probe(struct i2c_client *client)
956994
"could not read idt,output-enable-active\n");
957995
}
958996

959-
regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, src_mask, src_val);
997+
ret = regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, src_mask,
998+
src_val);
999+
if (ret)
1000+
return ret;
9601001

9611002
/* Register clock input mux */
9621003
memset(&init, 0, sizeof(init));

0 commit comments

Comments
 (0)