Merge branches 'clk-baikal', 'clk-broadcom', 'clk-vc5' and 'clk-versaclock' into...
[platform/kernel/linux-starfive.git] / drivers / clk / clk-versaclock5.c
index 03cfef4..2cf3e57 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 
-#include <dt-bindings/clk/versaclock.h>
+#include <dt-bindings/clock/versaclock.h>
 
 /* VersaClock5 registers */
 #define VC5_OTP_CONTROL                                0x00
@@ -153,6 +153,7 @@ enum vc5_model {
        IDT_VC5_5P49V5935,
        IDT_VC6_5P49V6901,
        IDT_VC6_5P49V6965,
+       IDT_VC6_5P49V6975,
 };
 
 /* Structure to describe features of a particular VC5 model */
@@ -230,8 +231,12 @@ static unsigned char vc5_mux_get_parent(struct clk_hw *hw)
                container_of(hw, struct vc5_driver_data, clk_mux);
        const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
        unsigned int src;
+       int ret;
+
+       ret = regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src);
+       if (ret)
+               return 0;
 
-       regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src);
        src &= mask;
 
        if (src == VC5_PRIM_SRC_SHDN_EN_XTAL)
@@ -286,8 +291,12 @@ static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
        struct vc5_driver_data *vc5 =
                container_of(hw, struct vc5_driver_data, clk_mul);
        unsigned int premul;
+       int ret;
+
+       ret = regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
+       if (ret)
+               return 0;
 
-       regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
        if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ)
                parent_rate *= 2;
 
@@ -315,11 +324,9 @@ static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
        else
                mask = 0;
 
-       regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
-                          VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
-                          mask);
-
-       return 0;
+       return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
+                                 VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
+                                 mask);
 }
 
 static const struct clk_ops vc5_dbl_ops = {
@@ -334,14 +341,19 @@ static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
        struct vc5_driver_data *vc5 =
                container_of(hw, struct vc5_driver_data, clk_pfd);
        unsigned int prediv, div;
+       int ret;
 
-       regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
+       ret = regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
+       if (ret)
+               return 0;
 
        /* The bypass_prediv is set, PLL fed from Ref_in directly. */
        if (prediv & VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV)
                return parent_rate;
 
-       regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div);
+       ret = regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div);
+       if (ret)
+               return 0;
 
        /* The Sel_prediv2 is set, PLL fed from prediv2 (Ref_in / 2) */
        if (div & VC5_REF_DIVIDER_SEL_PREDIV2)
@@ -376,15 +388,17 @@ static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
        struct vc5_driver_data *vc5 =
                container_of(hw, struct vc5_driver_data, clk_pfd);
        unsigned long idiv;
+       int ret;
        u8 div;
 
        /* CLKIN within range of PLL input, feed directly to PLL. */
        if (parent_rate <= 50000000) {
-               regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
-                                  VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV,
-                                  VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
-               regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00);
-               return 0;
+               ret = regmap_set_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
+                                     VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
+               if (ret)
+                       return ret;
+
+               return regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00);
        }
 
        idiv = DIV_ROUND_UP(parent_rate, rate);
@@ -395,11 +409,12 @@ static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
        else
                div = VC5_REF_DIVIDER_REF_DIV(idiv);
 
-       regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div);
-       regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
-                          VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, 0);
+       ret = regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div);
+       if (ret)
+               return ret;
 
-       return 0;
+       return regmap_clear_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
+                                VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
 }
 
 static const struct clk_ops vc5_pfd_ops = {
@@ -551,9 +566,12 @@ static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate,
                hwdata->div_int >> 4, hwdata->div_int << 4,
                0
        };
+       int ret;
 
-       regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
-                         data, 14);
+       ret = regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
+                               data, 14);
+       if (ret)
+               return ret;
 
        /*
         * Toggle magic bit in undocumented register for unknown reason.
@@ -561,12 +579,13 @@ static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate,
         * datasheet somewhat implies this is needed, but the register
         * and the bit is not documented.
         */
-       regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
-                          VC5_GLOBAL_REGISTER_GLOBAL_RESET, 0);
-       regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
-                          VC5_GLOBAL_REGISTER_GLOBAL_RESET,
-                          VC5_GLOBAL_REGISTER_GLOBAL_RESET);
-       return 0;
+       ret = regmap_clear_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
+                               VC5_GLOBAL_REGISTER_GLOBAL_RESET);
+       if (ret)
+               return ret;
+
+       return regmap_set_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
+                              VC5_GLOBAL_REGISTER_GLOBAL_RESET);
 }
 
 static const struct clk_ops vc5_fod_ops = {
@@ -594,10 +613,9 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
         * registers.
         */
        if (vc5->chip_info->flags & VC5_HAS_BYPASS_SYNC_BIT) {
-               ret = regmap_update_bits(vc5->regmap,
-                                        VC5_RESERVED_X0(hwdata->num),
-                                        VC5_RESERVED_X0_BYPASS_SYNC,
-                                        VC5_RESERVED_X0_BYPASS_SYNC);
+               ret = regmap_set_bits(vc5->regmap,
+                                     VC5_RESERVED_X0(hwdata->num),
+                                     VC5_RESERVED_X0_BYPASS_SYNC);
                if (ret)
                        return ret;
        }
@@ -606,7 +624,10 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
         * If the input mux is disabled, enable it first and
         * select source from matching FOD.
         */
-       regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
+       ret = regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
+       if (ret)
+               return ret;
+
        if ((src & mask) == 0) {
                src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD;
                ret = regmap_update_bits(vc5->regmap,
@@ -617,18 +638,22 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
        }
 
        /* Enable the clock buffer */
-       regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
-                          VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
-                          VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
+       ret = regmap_set_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
+                             VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
+       if (ret)
+               return ret;
+
        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);
+               ret = regmap_update_bits(vc5->regmap,
+                                        VC5_CLK_OUTPUT_CFG(hwdata->num, 0),
+                                        hwdata->clk_output_cfg0_mask,
+                                        hwdata->clk_output_cfg0);
+               if (ret)
+                       return ret;
        }
 
        return 0;
@@ -640,8 +665,8 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw)
        struct vc5_driver_data *vc5 = hwdata->vc5;
 
        /* Disable the clock buffer */
-       regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
-                          VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0);
+       regmap_clear_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
+                         VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
 }
 
 static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
@@ -656,8 +681,12 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
        const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
                          VC5_OUT_DIV_CONTROL_SEL_EXT;
        unsigned int src;
+       int ret;
+
+       ret = regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
+       if (ret)
+               return 0;
 
-       regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
        src &= mask;
 
        if (src == 0)   /* Input mux set to DISABLED */
@@ -725,6 +754,7 @@ static int vc5_map_index_to_output(const enum vc5_model model,
        case IDT_VC5_5P49V5935:
        case IDT_VC6_5P49V6901:
        case IDT_VC6_5P49V6965:
+       case IDT_VC6_5P49V6975:
        default:
                return n;
        }
@@ -819,22 +849,27 @@ static int vc5_update_cap_load(struct device_node *node, struct vc5_driver_data
 {
        u32 value;
        int mapped_value;
+       int ret;
 
-       if (!of_property_read_u32(node, "idt,xtal-load-femtofarads", &value)) {
-               mapped_value = vc5_map_cap_value(value);
-               if (mapped_value < 0)
-                       return mapped_value;
-
-               /*
-                * The mapped_value is really the high 6 bits of
-                * VC5_XTAL_X1_LOAD_CAP and VC5_XTAL_X2_LOAD_CAP, so
-                * shift the value 2 places.
-                */
-               regmap_update_bits(vc5->regmap, VC5_XTAL_X1_LOAD_CAP, ~0x03, mapped_value << 2);
-               regmap_update_bits(vc5->regmap, VC5_XTAL_X2_LOAD_CAP, ~0x03, mapped_value << 2);
-       }
+       if (of_property_read_u32(node, "idt,xtal-load-femtofarads", &value))
+               return 0;
 
-       return 0;
+       mapped_value = vc5_map_cap_value(value);
+       if (mapped_value < 0)
+               return mapped_value;
+
+       /*
+        * The mapped_value is really the high 6 bits of
+        * VC5_XTAL_X1_LOAD_CAP and VC5_XTAL_X2_LOAD_CAP, so
+        * shift the value 2 places.
+        */
+       ret = regmap_update_bits(vc5->regmap, VC5_XTAL_X1_LOAD_CAP, ~0x03,
+                                mapped_value << 2);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(vc5->regmap, VC5_XTAL_X2_LOAD_CAP, ~0x03,
+                                 mapped_value << 2);
 }
 
 static int vc5_update_slew(struct device_node *np_output,
@@ -956,7 +991,10 @@ static int vc5_probe(struct i2c_client *client)
                                     "could not read idt,output-enable-active\n");
        }
 
-       regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, src_mask, src_val);
+       ret = regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, src_mask,
+                                src_val);
+       if (ret)
+               return ret;
 
        /* Register clock input mux */
        memset(&init, 0, sizeof(init));
@@ -1214,6 +1252,13 @@ static const struct vc5_chip_info idt_5p49v6965_info = {
        .flags = VC5_HAS_BYPASS_SYNC_BIT,
 };
 
+static const struct vc5_chip_info idt_5p49v6975_info = {
+       .model = IDT_VC6_5P49V6975,
+       .clk_fod_cnt = 4,
+       .clk_out_cnt = 5,
+       .flags = VC5_HAS_BYPASS_SYNC_BIT | VC5_HAS_INTERNAL_XTAL,
+};
+
 static const struct i2c_device_id vc5_id[] = {
        { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
        { "5p49v5925", .driver_data = IDT_VC5_5P49V5925 },
@@ -1221,6 +1266,7 @@ static const struct i2c_device_id vc5_id[] = {
        { "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
        { "5p49v6901", .driver_data = IDT_VC6_5P49V6901 },
        { "5p49v6965", .driver_data = IDT_VC6_5P49V6965 },
+       { "5p49v6975", .driver_data = IDT_VC6_5P49V6975 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, vc5_id);
@@ -1232,6 +1278,7 @@ static const struct of_device_id clk_vc5_of_match[] = {
        { .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
        { .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info },
        { .compatible = "idt,5p49v6965", .data = &idt_5p49v6965_info },
+       { .compatible = "idt,5p49v6975", .data = &idt_5p49v6975_info },
        { },
 };
 MODULE_DEVICE_TABLE(of, clk_vc5_of_match);