| /* |
| * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) |
| * |
| * SPDX-License-Identifier: BSD-2-Clause |
| */ |
| |
| #include <errno.h> |
| |
| #include <platsupport/io.h> |
| #include <utils/util.h> |
| #include <clockserver_client.h> |
| |
| typedef struct clockserver_interface_data { |
| ps_io_ops_t *io_ops; |
| int (*clockserver_init_clock)(clk_id_t id); |
| int (*clockserver_set_gate_mode)(clock_gate_t gate, clock_gate_mode_t mode); |
| freq_t (*clockserver_get_freq)(clk_id_t clk_id); |
| freq_t (*clockserver_set_freq)(clk_id_t clk_id, freq_t hz); |
| int (*clockserver_register_child)(clk_id_t parent, clk_id_t child); |
| } clockserver_interface_data_t; |
| |
| static clockserver_interface_data_t clockserver_private_data; |
| |
| /* Note: No clk_t->init or clk_t->recal as these are handled by the server, |
| * also no register child for now as there are limitations */ |
| |
| static freq_t clockserver_get_freq_wrapper(clk_t *clk) |
| { |
| clock_sys_t *clock_sys = clk->clk_sys; |
| clockserver_interface_data_t *clockserver_data = clock_sys->priv; |
| |
| return clockserver_data->clockserver_get_freq(clk->id); |
| } |
| |
| static freq_t clockserver_set_freq_wrapper(clk_t *clk, freq_t hz) |
| { |
| clock_sys_t *clock_sys = clk->clk_sys; |
| clockserver_interface_data_t *clockserver_data = clock_sys->priv; |
| |
| freq_t set_freq = clockserver_data->clockserver_set_freq(clk->id, hz); |
| |
| /* Set the requested frequency */ |
| clk->req_freq = hz; |
| |
| return set_freq; |
| } |
| |
| static clk_t *clockserver_get_clock_wrapper(clock_sys_t *clock_sys, enum clk_id id) |
| { |
| clockserver_interface_data_t *clockserver_data = clock_sys->priv; |
| |
| int error = clockserver_data->clockserver_init_clock(id); |
| if (error) { |
| return NULL; |
| } |
| |
| /* Allocate a clk_t structure and fill it in */ |
| clk_t *ret_clk = NULL; |
| error = ps_calloc(&clockserver_data->io_ops->malloc_ops, 1, sizeof(clk_t), (void **) &ret_clk); |
| if (error) { |
| return NULL; |
| } |
| |
| ret_clk->id = id; |
| /* 'priv' needs to be setup for the function wrappers to not throw EINVAL, |
| * we actually use 'priv' */ |
| ret_clk->priv = (void *)((uintptr_t) 0xDEADBEEF); |
| ret_clk->clk_sys = clock_sys; |
| ret_clk->get_freq = clockserver_get_freq_wrapper; |
| ret_clk->set_freq = clockserver_set_freq_wrapper; |
| |
| return ret_clk; |
| } |
| |
| static int clockserver_gate_enable_wrapper(clock_sys_t *clock_sys, enum clock_gate gate, |
| enum clock_gate_mode mode) |
| { |
| clockserver_interface_data_t *clockserver_data = clock_sys->priv; |
| |
| return clockserver_data->clockserver_set_gate_mode(gate, mode); |
| } |
| |
| int clockserver_interface_init(ps_io_ops_t *io_ops, |
| int (*clockserver_init_clock)(clk_id_t id), |
| int (*clockserver_set_gate_mode)(clock_gate_t gate, clock_gate_mode_t mode), |
| freq_t (*clockserver_get_freq)(clk_id_t clk_id), |
| freq_t (*clockserver_set_freq)(clk_id_t clk_id, freq_t hz), |
| int (*clockserver_register_child)(clk_id_t parent, clk_id_t child), |
| clock_sys_t *clock_sys) |
| { |
| if (!io_ops) { |
| ZF_LOGE("io_ops is NULL"); |
| return -EINVAL; |
| } |
| |
| if (!clockserver_init_clock) { |
| ZF_LOGE("clockserver_init_clock is NULL"); |
| return -EINVAL; |
| } |
| |
| if (!clockserver_set_gate_mode) { |
| ZF_LOGE("clockserver_set_gate_mode is NULL"); |
| return -EINVAL; |
| } |
| |
| if (!clockserver_get_freq) { |
| ZF_LOGE("clockserver_get_freq is NULL"); |
| return -EINVAL; |
| } |
| |
| if (!clockserver_set_freq) { |
| ZF_LOGE("clockserver_set_freq is NULL"); |
| return -EINVAL; |
| } |
| |
| if (!clockserver_register_child) { |
| ZF_LOGE("clockserver_register_child is NULL"); |
| return -EINVAL; |
| } |
| |
| if (!clock_sys) { |
| ZF_LOGE("provided clock_sys_t is NULL"); |
| return -EINVAL; |
| } |
| |
| clockserver_private_data.io_ops = io_ops; |
| clockserver_private_data.clockserver_init_clock = clockserver_init_clock; |
| clockserver_private_data.clockserver_set_gate_mode = clockserver_set_gate_mode; |
| clockserver_private_data.clockserver_get_freq = clockserver_get_freq; |
| clockserver_private_data.clockserver_set_freq = clockserver_set_freq; |
| clockserver_private_data.clockserver_register_child = clockserver_register_child; |
| |
| clock_sys->priv = &clockserver_private_data; |
| clock_sys->get_clock = clockserver_get_clock_wrapper; |
| clock_sys->gate_enable = clockserver_gate_enable_wrapper; |
| |
| return 0; |
| } |