lineage_kernel_xcoverpro/drivers/vision/vipx/platform/exynos9610/vipx-clk-exynos9610.c

194 lines
4.1 KiB
C
Raw Normal View History

2023-06-18 22:53:49 +00:00
/*
* Samsung Exynos SoC series VIPX driver
*
* Copyright (c) 2018 Samsung Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "vipx-log.h"
#include "vipx-system.h"
#include "platform/vipx-clk.h"
enum vipx_clk_id {
VIPX_CLK_UMUX_CLKCMU_VIPX1_BUS,
VIPX_CLK_GATE_VIPX1_QCH,
VIPX_CLK_UMUX_CLKCMU_VIPX2_BUS,
VIPX_CLK_GATE_VIPX2_QCH,
VIPX_CLK_GATE_VIPX2_QCH_LOCAL,
VIPX_CLK_MAX
};
static struct vipx_clk vipx_exynos9610_clk_array[] = {
{ NULL, "UMUX_CLKCMU_VIPX1_BUS" },
{ NULL, "GATE_VIPX1_QCH" },
{ NULL, "UMUX_CLKCMU_VIPX2_BUS" },
{ NULL, "GATE_VIPX2_QCH" },
{ NULL, "GATE_VIPX2_QCH_LOCAL" },
};
static int vipx_exynos9610_clk_init(struct vipx_system *sys)
{
int ret;
int index;
const char *name;
struct clk *clk;
vipx_enter();
if (ARRAY_SIZE(vipx_exynos9610_clk_array) != VIPX_CLK_MAX) {
ret = -EINVAL;
vipx_err("clock array size is invalid (%zu/%d)\n",
ARRAY_SIZE(vipx_exynos9610_clk_array),
VIPX_CLK_MAX);
goto p_err;
}
for (index = 0; index < VIPX_CLK_MAX; ++index) {
name = vipx_exynos9610_clk_array[index].name;
if (!name) {
ret = -EINVAL;
vipx_err("clock name is NULL (%d)\n", index);
goto p_err;
}
clk = devm_clk_get(sys->dev, name);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
vipx_err("Failed to get clock(%s/%d) (%d)\n",
name, index, ret);
goto p_err;
}
vipx_exynos9610_clk_array[index].clk = clk;
}
vipx_leave();
return 0;
p_err:
return ret;
}
static void vipx_exynos9610_clk_deinit(struct vipx_system *sys)
{
vipx_enter();
vipx_leave();
}
static int vipx_exynos9610_clk_on(struct vipx_system *sys)
{
int ret;
int index;
const char *name;
struct clk *clk;
vipx_enter();
for (index = 0; index < VIPX_CLK_MAX; ++index) {
name = vipx_exynos9610_clk_array[index].name;
clk = vipx_exynos9610_clk_array[index].clk;
ret = clk_prepare_enable(clk);
if (ret) {
vipx_err("Failed to enable clock(%s/%d) (%d)\n",
name, index, ret);
goto p_err;
}
}
vipx_leave();
return 0;
p_err:
return ret;
}
static int vipx_exynos9610_clk_off(struct vipx_system *sys)
{
int index;
const char *name;
struct clk *clk;
vipx_enter();
for (index = VIPX_CLK_MAX - 1; index >= 0; --index) {
name = vipx_exynos9610_clk_array[index].name;
clk = vipx_exynos9610_clk_array[index].clk;
clk_disable_unprepare(clk);
}
vipx_leave();
return 0;
}
static int vipx_exynos9610_clk_get_count(struct vipx_system *sys)
{
vipx_check();
return VIPX_CLK_MAX;
}
static unsigned long vipx_exynos9610_clk_get_freq(struct vipx_system *sys,
int id)
{
unsigned long freq;
vipx_enter();
if ((id < 0) || (id >= VIPX_CLK_MAX)) {
vipx_warn("request id(%d). clk id is valid from 0 to %d\n",
id, VIPX_CLK_MAX - 1);
return -EINVAL;
}
freq = clk_get_rate(vipx_exynos9610_clk_array[id].clk);
vipx_leave();
return freq;
}
static const char *vipx_exynos9610_clk_get_name(struct vipx_system *sys,
int id)
{
const char *name;
vipx_enter();
if ((id < 0) || (id >= VIPX_CLK_MAX)) {
vipx_warn("request id(%d). clk id is valid from 0 to %d\n",
id, VIPX_CLK_MAX - 1);
return NULL;
}
name = vipx_exynos9610_clk_array[id].name;
vipx_leave();
return name;
}
static int vipx_exynos9610_clk_dump(struct vipx_system *sys)
{
int index;
const char *name;
struct clk *clk;
unsigned long freq;
vipx_enter();
for (index = 0; index < VIPX_CLK_MAX; ++index) {
name = vipx_exynos9610_clk_array[index].name;
clk = vipx_exynos9610_clk_array[index].clk;
freq = clk_get_rate(clk);
vipx_info("%30s(%d) : %3lu.%06lu MHz\n",
name, index, freq / 1000000, freq % 1000000);
}
vipx_leave();
return 0;
}
const struct vipx_clk_ops vipx_clk_ops = {
.init = vipx_exynos9610_clk_init,
.deinit = vipx_exynos9610_clk_deinit,
.on = vipx_exynos9610_clk_on,
.off = vipx_exynos9610_clk_off,
.dump = vipx_exynos9610_clk_dump,
.get_count = vipx_exynos9610_clk_get_count,
.get_freq = vipx_exynos9610_clk_get_freq,
.get_name = vipx_exynos9610_clk_get_name,
};