diff options
| author | Tom Rini <trini@konsulko.com> | 2020-09-30 16:11:11 -0400 | 
|---|---|---|
| committer | Tom Rini <trini@konsulko.com> | 2020-09-30 16:11:11 -0400 | 
| commit | 097bbf1ba97b8ece930deca663f05ea444e99e45 (patch) | |
| tree | ae4db71e77556f34f9fa7023205e4284c1d72c38 /drivers/clk/clk_scmi.c | |
| parent | 01114adfc1e0bf3cf5e2f3da858bb2c8e9810c1c (diff) | |
| parent | c0dd177a9986b97dab42f07b3db0ed1d2fe6e540 (diff) | |
Merge branch '2020-09-30-add-new-apis' into next
- SCMI firmware support
- regmap, GPIO, reset API enhancements
Diffstat (limited to 'drivers/clk/clk_scmi.c')
| -rw-r--r-- | drivers/clk/clk_scmi.c | 99 | 
1 files changed, 99 insertions, 0 deletions
| diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c new file mode 100644 index 00000000000..93a4819501c --- /dev/null +++ b/drivers/clk/clk_scmi.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019-2020 Linaro Limited + */ +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <scmi_agent.h> +#include <scmi_protocols.h> +#include <asm/types.h> + +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, +}; | 
