// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2019-2020 Linaro Limited */ #include #include #include #include #include #include static int scmi_clk_gate(struct clk *clk, int enable) { struct scmi_clk_state_in in = { .clock_id = clk->id, .attributes = enable, }; struct scmi_clk_state_out out; struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, SCMI_CLOCK_CONFIG_SET, in, out); int ret; ret = devm_scmi_process_msg(clk->dev->parent, &msg); if (ret) return ret; return scmi_to_linux_errno(out.status); } static int scmi_clk_enable(struct clk *clk) { return scmi_clk_gate(clk, 1); } static int scmi_clk_disable(struct clk *clk) { return scmi_clk_gate(clk, 0); } static ulong scmi_clk_get_rate(struct clk *clk) { struct scmi_clk_rate_get_in in = { .clock_id = clk->id, }; struct scmi_clk_rate_get_out out; struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, SCMI_CLOCK_RATE_GET, in, out); int ret; ret = devm_scmi_process_msg(clk->dev->parent, &msg); if (ret < 0) return ret; ret = scmi_to_linux_errno(out.status); if (ret < 0) return ret; return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb); } static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) { struct scmi_clk_rate_set_in in = { .clock_id = clk->id, .flags = SCMI_CLK_RATE_ROUND_CLOSEST, .rate_lsb = (u32)rate, .rate_msb = (u32)((u64)rate >> 32), }; struct scmi_clk_rate_set_out out; struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, SCMI_CLOCK_RATE_SET, in, out); int ret; ret = devm_scmi_process_msg(clk->dev->parent, &msg); if (ret < 0) return ret; ret = scmi_to_linux_errno(out.status); if (ret < 0) return ret; return scmi_clk_get_rate(clk); } static const struct clk_ops scmi_clk_ops = { .enable = scmi_clk_enable, .disable = scmi_clk_disable, .get_rate = scmi_clk_get_rate, .set_rate = scmi_clk_set_rate, }; U_BOOT_DRIVER(scmi_clock) = { .name = "scmi_clk", .id = UCLASS_CLK, .ops = &scmi_clk_ops, };