mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
The request function performs a simple check if the clock with the provided ID is present or not. This is done with a simple call to clk_get_by_id(). A non-zero return value indicates that the requested clock is not available. In some cases, clk->dev points to the clock bank device instead of the clock device. This pointer is therefore overwritten in order to reference to the correct device instance. Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org> Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
312 lines
7.9 KiB
C
312 lines
7.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2023 Linaro Ltd.
|
|
* Sam Protsenko <semen.protsenko@linaro.org>
|
|
*
|
|
* Common Clock Framework support for all Samsung platforms.
|
|
*/
|
|
|
|
#ifndef __EXYNOS_CLK_H
|
|
#define __EXYNOS_CLK_H
|
|
|
|
#include <clk.h>
|
|
#include <errno.h>
|
|
#include <linux/clk-provider.h>
|
|
#include "clk-pll.h"
|
|
|
|
int samsung_clk_request(struct clk *clk);
|
|
|
|
#define _SAMSUNG_CLK_OPS(_name, _cmu) \
|
|
static int _name##_of_xlate(struct clk *clk, \
|
|
struct ofnode_phandle_args *args) \
|
|
{ \
|
|
if (args->args_count > 1) { \
|
|
debug("Invalid args_count: %d\n", args->args_count); \
|
|
return -EINVAL; \
|
|
} \
|
|
\
|
|
if (args->args_count) \
|
|
clk->id = SAMSUNG_TO_CLK_ID(_cmu, args->args[0]); \
|
|
else \
|
|
clk->id = 0; \
|
|
\
|
|
return 0; \
|
|
} \
|
|
\
|
|
static const struct clk_ops _name##_clk_ops = { \
|
|
.set_rate = ccf_clk_set_rate, \
|
|
.get_rate = ccf_clk_get_rate, \
|
|
.set_parent = ccf_clk_set_parent, \
|
|
.enable = ccf_clk_enable, \
|
|
.disable = ccf_clk_disable, \
|
|
.of_xlate = _name##_of_xlate, \
|
|
.request = samsung_clk_request, \
|
|
}
|
|
|
|
/**
|
|
* SAMSUNG_CLK_OPS - Define clock operations structure for specified CMU.
|
|
* @name: name of generated structure
|
|
* @cmu: CMU index
|
|
*
|
|
* Like ccf_clk_ops, but with custom .of_xlate callback.
|
|
*/
|
|
#define SAMSUNG_CLK_OPS(name, cmu) _SAMSUNG_CLK_OPS(name, cmu)
|
|
|
|
/**
|
|
* SAMSUNG_TO_CLK_ID - Calculate a global clock index.
|
|
* @_cmu: CMU index
|
|
* @_id: local clock index (unique across @_cmu)
|
|
*
|
|
* Return: A global clock index unique across all CMUs.
|
|
* Keeps a range of 256 available clocks for every CMU.
|
|
*/
|
|
#define SAMSUNG_TO_CLK_ID(_cmu, _id) (((_cmu) << 8) | ((_id) & 0xff))
|
|
|
|
/**
|
|
* struct samsung_fixed_rate_clock - information about fixed-rate clock
|
|
* @id: platform specific id of the clock
|
|
* @name: name of this fixed-rate clock
|
|
* @fixed_rate: fixed clock rate of this clock
|
|
*/
|
|
struct samsung_fixed_rate_clock {
|
|
unsigned int id;
|
|
const char *name;
|
|
unsigned long fixed_rate;
|
|
};
|
|
|
|
#define FRATE(_id, cname, frate) \
|
|
{ \
|
|
.id = _id, \
|
|
.name = cname, \
|
|
.fixed_rate = frate, \
|
|
}
|
|
|
|
/**
|
|
* struct samsung_fixed_factor_clock - information about fixed-factor clock
|
|
* @id: platform specific id of the clock
|
|
* @name: name of this fixed-factor clock
|
|
* @parent_name: parent clock name
|
|
* @mult: fixed multiplication factor
|
|
* @div: fixed division factor
|
|
* @flags: optional fixed-factor clock flags
|
|
*/
|
|
struct samsung_fixed_factor_clock {
|
|
unsigned int id;
|
|
const char *name;
|
|
const char *parent_name;
|
|
unsigned long mult;
|
|
unsigned long div;
|
|
unsigned long flags;
|
|
};
|
|
|
|
#define FFACTOR(_id, cname, pname, m, d, f) \
|
|
{ \
|
|
.id = _id, \
|
|
.name = cname, \
|
|
.parent_name = pname, \
|
|
.mult = m, \
|
|
.div = d, \
|
|
.flags = f, \
|
|
}
|
|
|
|
/**
|
|
* struct samsung_mux_clock - information about mux clock
|
|
* @id: platform specific id of the clock
|
|
* @name: name of this mux clock
|
|
* @parent_names: array of pointer to parent clock names
|
|
* @num_parents: number of parents listed in @parent_names
|
|
* @flags: optional flags for basic clock
|
|
* @offset: offset of the register for configuring the mux
|
|
* @shift: starting bit location of the mux control bit-field in @reg
|
|
* @width: width of the mux control bit-field in @reg
|
|
* @mux_flags: flags for mux-type clock
|
|
*/
|
|
struct samsung_mux_clock {
|
|
unsigned int id;
|
|
const char *name;
|
|
const char * const *parent_names;
|
|
u8 num_parents;
|
|
unsigned long flags;
|
|
unsigned long offset;
|
|
u8 shift;
|
|
u8 width;
|
|
u8 mux_flags;
|
|
};
|
|
|
|
#define PNAME(x) static const char * const x[]
|
|
|
|
#define __MUX(_id, cname, pnames, o, s, w, f, mf) \
|
|
{ \
|
|
.id = _id, \
|
|
.name = cname, \
|
|
.parent_names = pnames, \
|
|
.num_parents = ARRAY_SIZE(pnames), \
|
|
.flags = (f) | CLK_SET_RATE_NO_REPARENT, \
|
|
.offset = o, \
|
|
.shift = s, \
|
|
.width = w, \
|
|
.mux_flags = mf, \
|
|
}
|
|
|
|
#define MUX(_id, cname, pnames, o, s, w) \
|
|
__MUX(_id, cname, pnames, o, s, w, 0, 0)
|
|
|
|
#define MUX_F(_id, cname, pnames, o, s, w, f, mf) \
|
|
__MUX(_id, cname, pnames, o, s, w, f, mf)
|
|
|
|
/**
|
|
* struct samsung_div_clock - information about div clock
|
|
* @id: platform specific id of the clock
|
|
* @name: name of this div clock
|
|
* @parent_name: name of the parent clock
|
|
* @flags: optional flags for basic clock
|
|
* @offset: offset of the register for configuring the div
|
|
* @shift: starting bit location of the div control bit-field in @reg
|
|
* @width: width of the bitfield
|
|
* @div_flags: flags for div-type clock
|
|
*/
|
|
struct samsung_div_clock {
|
|
unsigned int id;
|
|
const char *name;
|
|
const char *parent_name;
|
|
unsigned long flags;
|
|
unsigned long offset;
|
|
u8 shift;
|
|
u8 width;
|
|
u8 div_flags;
|
|
};
|
|
|
|
#define __DIV(_id, cname, pname, o, s, w, f, df) \
|
|
{ \
|
|
.id = _id, \
|
|
.name = cname, \
|
|
.parent_name = pname, \
|
|
.flags = f, \
|
|
.offset = o, \
|
|
.shift = s, \
|
|
.width = w, \
|
|
.div_flags = df, \
|
|
}
|
|
|
|
#define DIV(_id, cname, pname, o, s, w) \
|
|
__DIV(_id, cname, pname, o, s, w, 0, 0)
|
|
|
|
#define DIV_F(_id, cname, pname, o, s, w, f, df) \
|
|
__DIV(_id, cname, pname, o, s, w, f, df)
|
|
|
|
/**
|
|
* struct samsung_gate_clock - information about gate clock
|
|
* @id: platform specific id of the clock
|
|
* @name: name of this gate clock
|
|
* @parent_name: name of the parent clock
|
|
* @flags: optional flags for basic clock
|
|
* @offset: offset of the register for configuring the gate
|
|
* @bit_idx: bit index of the gate control bit-field in @reg
|
|
* @gate_flags: flags for gate-type clock
|
|
*/
|
|
struct samsung_gate_clock {
|
|
unsigned int id;
|
|
const char *name;
|
|
const char *parent_name;
|
|
unsigned long flags;
|
|
unsigned long offset;
|
|
u8 bit_idx;
|
|
u8 gate_flags;
|
|
};
|
|
|
|
#define __GATE(_id, cname, pname, o, b, f, gf) \
|
|
{ \
|
|
.id = _id, \
|
|
.name = cname, \
|
|
.parent_name = pname, \
|
|
.flags = f, \
|
|
.offset = o, \
|
|
.bit_idx = b, \
|
|
.gate_flags = gf, \
|
|
}
|
|
|
|
#define GATE(_id, cname, pname, o, b, f, gf) \
|
|
__GATE(_id, cname, pname, o, b, f, gf)
|
|
|
|
/**
|
|
* struct samsung_pll_clock - information about pll clock
|
|
* @id: platform specific id of the clock
|
|
* @name: name of this pll clock
|
|
* @parent_name: name of the parent clock
|
|
* @flags: optional flags for basic clock
|
|
* @con_offset: offset of the register for configuring the PLL
|
|
* @type: type of PLL to be registered
|
|
*/
|
|
struct samsung_pll_clock {
|
|
unsigned int id;
|
|
const char *name;
|
|
const char *parent_name;
|
|
unsigned long flags;
|
|
int con_offset;
|
|
enum samsung_pll_type type;
|
|
};
|
|
|
|
#define PLL(_typ, _id, _name, _pname, _con) \
|
|
{ \
|
|
.id = _id, \
|
|
.name = _name, \
|
|
.parent_name = _pname, \
|
|
.flags = CLK_GET_RATE_NOCACHE, \
|
|
.con_offset = _con, \
|
|
.type = _typ, \
|
|
}
|
|
|
|
enum samsung_clock_type {
|
|
S_CLK_FRATE,
|
|
S_CLK_FFACTOR,
|
|
S_CLK_MUX,
|
|
S_CLK_DIV,
|
|
S_CLK_GATE,
|
|
S_CLK_PLL,
|
|
};
|
|
|
|
/**
|
|
* struct samsung_clock_group - contains a list of clocks of one type
|
|
* @type: type of clocks this structure contains
|
|
* @clk_list: list of clocks
|
|
* @nr_clk: count of clocks in @clk_list
|
|
*/
|
|
struct samsung_clk_group {
|
|
enum samsung_clock_type type;
|
|
const void *clk_list;
|
|
unsigned int nr_clk;
|
|
};
|
|
|
|
int samsung_cmu_register_one(struct udevice *dev, unsigned int cmu_id,
|
|
const struct samsung_clk_group *clk_groups,
|
|
unsigned int nr_groups);
|
|
|
|
/**
|
|
* samsung_register_cmu - Register CMU clocks ensuring parent CMU is present
|
|
* @dev: CMU device
|
|
* @cmu_id: CMU index number
|
|
* @clk_groups: list of CMU clock groups
|
|
* @parent_drv: name of parent CMU driver
|
|
*
|
|
* Register provided CMU clocks, but make sure CMU_TOP driver is instantiated
|
|
* first.
|
|
*
|
|
* Return: 0 on success or negative value on error.
|
|
*/
|
|
#define samsung_register_cmu(dev, cmu_id, clk_groups, parent_drv) \
|
|
({ \
|
|
struct udevice *__parent; \
|
|
int __ret; \
|
|
\
|
|
__ret = uclass_get_device_by_driver(UCLASS_CLK, \
|
|
DM_DRIVER_GET(parent_drv), &__parent); \
|
|
if (__ret || !__parent) \
|
|
__ret = -ENOENT; \
|
|
else \
|
|
__ret = samsung_cmu_register_one(dev, cmu_id, \
|
|
clk_groups, ARRAY_SIZE(clk_groups)); \
|
|
__ret; \
|
|
})
|
|
|
|
#endif /* __EXYNOS_CLK_H */
|