*/
 
 #include <dt-bindings/phy/phy.h>
+#include <dt-bindings/phy/phy-ti.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/gpio.h>
 #define WIZ_SERDES_TYPEC       0x410
 #define WIZ_LANECTL(n)         (0x480 + (0x40 * (n)))
 
+#define WIZ_MAX_INPUT_CLOCKS   4
+/* To include mux clocks, divider clocks and gate clocks */
+#define WIZ_MAX_OUTPUT_CLOCKS  32
+
 #define WIZ_MAX_LANES          4
 #define WIZ_MUX_NUM_CLOCKS     3
 #define WIZ_DIV_NUM_CLOCKS_16G 2
        CMN_REFCLK1_DIG_DIV,
 };
 
+enum wiz_clock_input {
+       WIZ_CORE_REFCLK,
+       WIZ_EXT_REFCLK,
+       WIZ_CORE_REFCLK1,
+       WIZ_EXT_REFCLK1,
+};
+
 static const struct reg_field por_en = REG_FIELD(WIZ_SERDES_CTRL, 31, 31);
 static const struct reg_field phy_reset_n = REG_FIELD(WIZ_SERDES_RST, 31, 31);
 static const struct reg_field pll1_refclk_mux_sel =
                                        REG_FIELD(WIZ_SERDES_TOP_CTRL, 26, 27);
 static const struct reg_field pma_cmn_refclk1_dig_div =
                                        REG_FIELD(WIZ_SERDES_TOP_CTRL, 24, 25);
+static const char * const output_clk_names[] = {
+       [TI_WIZ_PLL0_REFCLK] = "pll0-refclk",
+       [TI_WIZ_PLL1_REFCLK] = "pll1-refclk",
+       [TI_WIZ_REFCLK_DIG] = "refclk-dig",
+};
 
 static const struct reg_field p_enable[WIZ_MAX_LANES] = {
        REG_FIELD(WIZ_LANECTL(0), 30, 31),
 #define to_wiz_clk_div(_hw) container_of(_hw, struct wiz_clk_divider, hw)
 
 struct wiz_clk_mux_sel {
-       u32                     table[4];
+       u32                     table[WIZ_MAX_INPUT_CLOCKS];
        const char              *node_name;
+       u32                     num_parents;
+       u32                     parents[WIZ_MAX_INPUT_CLOCKS];
 };
 
 struct wiz_clk_div_sel {
                 * Mux value to be configured for each of the input clocks
                 * in the order populated in device tree
                 */
+               .num_parents = 2,
+               .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK },
                .table = { 1, 0 },
                .node_name = "pll0-refclk",
        },
        {
+               .num_parents = 2,
+               .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK },
                .table = { 1, 0 },
                .node_name = "pll1-refclk",
        },
        {
+               .num_parents = 2,
+               .parents = { WIZ_CORE_REFCLK, WIZ_EXT_REFCLK },
                .table = { 1, 0 },
                .node_name = "refclk-dig",
        },
        struct gpio_desc        *gpio_typec_dir;
        int                     typec_dir_delay;
        u32 lane_phy_type[WIZ_MAX_LANES];
+       struct clk              *input_clks[WIZ_MAX_INPUT_CLOCKS];
+       struct clk              *output_clks[WIZ_MAX_OUTPUT_CLOCKS];
+       struct clk_onecell_data clk_data;
 };
 
 static int wiz_reset(struct wiz *wiz)
        .get_parent = wiz_clk_mux_get_parent,
 };
 
-static int wiz_mux_clk_register(struct wiz *wiz, struct device_node *node,
-                               struct regmap_field *field, const u32 *table)
+static int wiz_mux_clk_register(struct wiz *wiz, struct regmap_field *field,
+                               const struct wiz_clk_mux_sel *mux_sel, int clk_index)
+{
+       struct device *dev = wiz->dev;
+       struct clk_init_data *init;
+       const char **parent_names;
+       unsigned int num_parents;
+       struct wiz_clk_mux *mux;
+       char clk_name[100];
+       struct clk *clk;
+       int ret = 0, i;
+
+       mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+       if (!mux)
+               return -ENOMEM;
+
+       num_parents = mux_sel->num_parents;
+
+       parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
+       if (!parent_names)
+               return -ENOMEM;
+
+       for (i = 0; i < num_parents; i++) {
+               clk = wiz->input_clks[mux_sel->parents[i]];
+               if (IS_ERR_OR_NULL(clk)) {
+                       dev_err(dev, "Failed to get parent clk for %s\n",
+                               output_clk_names[clk_index]);
+                       ret = -EINVAL;
+                       goto err;
+               }
+               parent_names[i] = __clk_get_name(clk);
+       }
+
+       snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), output_clk_names[clk_index]);
+
+       init = &mux->clk_data;
+
+       init->ops = &wiz_clk_mux_ops;
+       init->flags = CLK_SET_RATE_NO_REPARENT;
+       init->parent_names = parent_names;
+       init->num_parents = num_parents;
+       init->name = clk_name;
+
+       mux->field = field;
+       mux->table = mux_sel->table;
+       mux->hw.init = init;
+
+       clk = devm_clk_register(dev, &mux->hw);
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               goto err;
+       }
+
+       wiz->output_clks[clk_index] = clk;
+
+err:
+       kfree(parent_names);
+
+       return ret;
+}
+
+static int wiz_mux_of_clk_register(struct wiz *wiz, struct device_node *node,
+                                  struct regmap_field *field, const u32 *table)
 {
        struct device *dev = wiz->dev;
        struct clk_init_data *init;
 static void wiz_clock_cleanup(struct wiz *wiz, struct device_node *node)
 {
        const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
+       struct device *dev = wiz->dev;
        struct device_node *clk_node;
        int i;
 
+       if (wiz->type == AM64_WIZ_10G) {
+               of_clk_del_provider(dev->of_node);
+               return;
+       }
+
        for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) {
                clk_node = of_get_child_by_name(node, clk_mux_sel[i].node_name);
                of_clk_del_provider(clk_node);
        }
 }
 
+static int wiz_clock_register(struct wiz *wiz)
+{
+       const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
+       struct device *dev = wiz->dev;
+       struct device_node *node = dev->of_node;
+       int clk_index;
+       int ret;
+       int i;
+
+       if (wiz->type != AM64_WIZ_10G)
+               return 0;
+
+       clk_index = TI_WIZ_PLL0_REFCLK;
+       for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++, clk_index++) {
+               ret = wiz_mux_clk_register(wiz, wiz->mux_sel_field[i], &clk_mux_sel[i], clk_index);
+               if (ret) {
+                       dev_err(dev, "Failed to register clk: %s\n", output_clk_names[clk_index]);
+                       return ret;
+               }
+       }
+
+       wiz->clk_data.clks = wiz->output_clks;
+       wiz->clk_data.clk_num = WIZ_MAX_OUTPUT_CLOCKS;
+       ret = of_clk_add_provider(node, of_clk_src_onecell_get, &wiz->clk_data);
+       if (ret)
+               dev_err(dev, "Failed to add clock provider: %s\n", node->name);
+
+       return ret;
+}
+
 static int wiz_clock_init(struct wiz *wiz, struct device_node *node)
 {
        const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel;
                ret = PTR_ERR(clk);
                return ret;
        }
+       wiz->input_clks[WIZ_CORE_REFCLK] = clk;
 
        rate = clk_get_rate(clk);
        if (rate >= 100000000)
                ret = PTR_ERR(clk);
                return ret;
        }
+       wiz->input_clks[WIZ_EXT_REFCLK] = clk;
 
        rate = clk_get_rate(clk);
        if (rate >= 100000000)
        else
                regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2);
 
+       if (wiz->type == AM64_WIZ_10G) {
+               ret = wiz_clock_register(wiz);
+               if (ret)
+                       dev_err(dev, "Failed to register wiz clocks\n");
+               return ret;
+       }
+
        for (i = 0; i < WIZ_MUX_NUM_CLOCKS; i++) {
                node_name = clk_mux_sel[i].node_name;
                clk_node = of_get_child_by_name(node, node_name);
                        goto err;
                }
 
-               ret = wiz_mux_clk_register(wiz, clk_node, wiz->mux_sel_field[i],
-                                          clk_mux_sel[i].table);
+               ret = wiz_mux_of_clk_register(wiz, clk_node, wiz->mux_sel_field[i],
+                                             clk_mux_sel[i].table);
                if (ret) {
                        dev_err(dev, "Failed to register %s clock\n",
                                node_name);