You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
2.7 KiB
124 lines
2.7 KiB
/* |
|
* Copyright 2024-2025 NXP |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/drivers/firmware/scmi/clk.h> |
|
#include <zephyr/drivers/clock_control.h> |
|
#include <zephyr/logging/log.h> |
|
|
|
LOG_MODULE_REGISTER(arm_scmi_clock); |
|
|
|
#define DT_DRV_COMPAT arm_scmi_clock |
|
|
|
struct scmi_clock_data { |
|
uint32_t clk_num; |
|
}; |
|
|
|
static int scmi_clock_on_off(const struct device *dev, |
|
clock_control_subsys_t clk, bool on) |
|
{ |
|
struct scmi_clock_data *data; |
|
struct scmi_protocol *proto; |
|
uint32_t clk_id; |
|
struct scmi_clock_config cfg; |
|
|
|
proto = dev->data; |
|
data = proto->data; |
|
clk_id = POINTER_TO_UINT(clk); |
|
|
|
if (clk_id >= data->clk_num) { |
|
return -EINVAL; |
|
} |
|
|
|
memset(&cfg, 0, sizeof(cfg)); |
|
|
|
cfg.attributes = SCMI_CLK_CONFIG_ENABLE_DISABLE(on); |
|
cfg.clk_id = clk_id; |
|
|
|
return scmi_clock_config_set(proto, &cfg); |
|
} |
|
|
|
static int scmi_clock_on(const struct device *dev, clock_control_subsys_t clk) |
|
{ |
|
return scmi_clock_on_off(dev, clk, true); |
|
} |
|
|
|
static int scmi_clock_off(const struct device *dev, clock_control_subsys_t clk) |
|
{ |
|
return scmi_clock_on_off(dev, clk, false); |
|
} |
|
|
|
static int scmi_clock_get_rate(const struct device *dev, |
|
clock_control_subsys_t clk, uint32_t *rate) |
|
{ |
|
struct scmi_clock_data *data; |
|
struct scmi_protocol *proto; |
|
uint32_t clk_id; |
|
|
|
proto = dev->data; |
|
data = proto->data; |
|
clk_id = POINTER_TO_UINT(clk); |
|
|
|
if (clk_id >= data->clk_num) { |
|
return -EINVAL; |
|
} |
|
|
|
return scmi_clock_rate_get(proto, clk_id, rate); |
|
} |
|
|
|
static int scmi_clock_set_rate(const struct device *dev, |
|
clock_control_subsys_t clk, |
|
clock_control_subsys_rate_t rate) |
|
{ |
|
struct scmi_clock_data *data; |
|
struct scmi_protocol *proto; |
|
struct scmi_clock_rate_config cfg = {0}; |
|
|
|
proto = dev->data; |
|
data = proto->data; |
|
cfg.flags = SCMI_CLK_RATE_SET_FLAGS_ROUNDS_AUTO; |
|
cfg.clk_id = POINTER_TO_UINT(clk); |
|
cfg.rate[0] = (uintptr_t)rate; |
|
|
|
if (cfg.clk_id >= data->clk_num) { |
|
return -EINVAL; |
|
} |
|
|
|
return scmi_clock_rate_set(proto, &cfg); |
|
} |
|
|
|
static DEVICE_API(clock_control, scmi_clock_api) = { |
|
.on = scmi_clock_on, |
|
.off = scmi_clock_off, |
|
.get_rate = scmi_clock_get_rate, |
|
.set_rate = scmi_clock_set_rate, |
|
}; |
|
|
|
static int scmi_clock_init(const struct device *dev) |
|
{ |
|
struct scmi_protocol *proto; |
|
struct scmi_clock_data *data; |
|
int ret; |
|
uint32_t attributes; |
|
|
|
proto = dev->data; |
|
data = proto->data; |
|
|
|
ret = scmi_clock_protocol_attributes(proto, &attributes); |
|
if (ret < 0) { |
|
LOG_ERR("failed to fetch clock attributes: %d", ret); |
|
return ret; |
|
} |
|
|
|
data->clk_num = SCMI_CLK_ATTRIBUTES_CLK_NUM(attributes); |
|
|
|
return 0; |
|
} |
|
|
|
static struct scmi_clock_data data; |
|
|
|
DT_INST_SCMI_PROTOCOL_DEFINE(0, &scmi_clock_init, NULL, &data, NULL, |
|
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, |
|
&scmi_clock_api);
|
|
|