194 lines
4.1 KiB
C
Executable File
194 lines
4.1 KiB
C
Executable File
/*
|
|
* 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,
|
|
};
|