* Copyright (C) 2018-2022 ARM Ltd.
*/
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/limits.h>
#include <linux/sort.h>
return ret;
}
+static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
+ u32 clk_id, unsigned long *rate)
+{
+ u64 fmin, fmax, ftmp;
+ struct scmi_clock_info *clk;
+ struct clock_info *ci = ph->get_priv(ph);
+
+ if (!rate)
+ return -EINVAL;
+
+ clk = scmi_clock_domain_lookup(ci, clk_id);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ /*
+ * If we can't figure out what rate it will be, so just return the
+ * rate back to the caller.
+ */
+ if (clk->rate_discrete)
+ return 0;
+
+ fmin = clk->range.min_rate;
+ fmax = clk->range.max_rate;
+ if (*rate <= fmin) {
+ *rate = fmin;
+ return 0;
+ } else if (*rate >= fmax) {
+ *rate = fmax;
+ return 0;
+ }
+
+ ftmp = *rate - fmin;
+ ftmp += clk->range.step_size - 1; /* to round up */
+ ftmp = div64_ul(ftmp, clk->range.step_size);
+
+ *rate = ftmp * clk->range.step_size + fmin;
+
+ return 0;
+}
+
static int
scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
enum clk_state state,
.info_get = scmi_clock_info_get,
.rate_get = scmi_clock_rate_get,
.rate_set = scmi_clock_rate_set,
+ .determine_rate = scmi_clock_determine_rate,
.enable = scmi_clock_enable,
.disable = scmi_clock_disable,
.state_get = scmi_clock_state_get,
* @info_get: get the information of the specified clock
* @rate_get: request the current clock rate of a clock
* @rate_set: set the clock rate of a clock
+ * @determine_rate: determine the effective rate that can be supported by a
+ * clock calculating the closest allowed rate.
+ * Note that @rate is an input/output parameter used both to
+ * describe the requested rate and report the closest match
* @enable: enables the specified clock
* @disable: disables the specified clock
* @state_get: get the status of the specified clock
u64 *rate);
int (*rate_set)(const struct scmi_protocol_handle *ph, u32 clk_id,
u64 rate);
+ int (*determine_rate)(const struct scmi_protocol_handle *ph, u32 clk_id,
+ unsigned long *rate);
int (*enable)(const struct scmi_protocol_handle *ph, u32 clk_id,
bool atomic);
int (*disable)(const struct scmi_protocol_handle *ph, u32 clk_id,