+static unsigned long uniphier_clk_get_rate(struct clk *clk)
+{
+ struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
+ const struct uniphier_clk_data *data;
+
+ data = uniphier_clk_get_data(priv, clk->id);
+ if (!data)
+ return -ENODEV;
+
+ return __uniphier_clk_get_rate(priv, data);
+}
+
+static unsigned long __uniphier_clk_set_rate(
+ struct uniphier_clk_priv *priv,
+ const struct uniphier_clk_data *data,
+ unsigned long rate, bool set)
+{
+ const struct uniphier_clk_data *best_parent_data = NULL;
+ const struct uniphier_clk_data *parent_data;
+ unsigned long best_rate = 0;
+ unsigned long parent_rate;
+ u8 parent_id;
+ int i;
+
+ if (data->type == UNIPHIER_CLK_TYPE_FIXED_RATE)
+ return data->data.rate.fixed_rate;
+
+ if (data->type == UNIPHIER_CLK_TYPE_GATE) {
+ parent_data = uniphier_clk_get_parent_data(priv, data);
+ if (!parent_data)
+ return 0;
+
+ return __uniphier_clk_set_rate(priv, parent_data, rate, set);
+ }
+
+ if (WARN_ON(data->type != UNIPHIER_CLK_TYPE_MUX))
+ return -EINVAL;
+
+ for (i = 0; i < data->data.mux.num_parents; i++) {
+ parent_id = data->data.mux.parent_ids[i];
+ parent_data = uniphier_clk_get_data(priv, parent_id);
+ if (WARN_ON(!parent_data))
+ return -EINVAL;
+
+ parent_rate = __uniphier_clk_set_rate(priv, parent_data, rate,
+ false);
+
+ if (parent_rate <= rate && best_rate < parent_rate) {
+ best_rate = parent_rate;
+ best_parent_data = parent_data;