17a12f838SNishad Kamdar /* SPDX-License-Identifier: GPL-2.0 */
2e3f05d3bSChunyan Zhang //
3e3f05d3bSChunyan Zhang // Spreadtrum divider clock driver
4e3f05d3bSChunyan Zhang //
5e3f05d3bSChunyan Zhang // Copyright (C) 2017 Spreadtrum, Inc.
6e3f05d3bSChunyan Zhang // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
7e3f05d3bSChunyan Zhang
8e3f05d3bSChunyan Zhang #ifndef _SPRD_DIV_H_
9e3f05d3bSChunyan Zhang #define _SPRD_DIV_H_
10e3f05d3bSChunyan Zhang
11e3f05d3bSChunyan Zhang #include "common.h"
12e3f05d3bSChunyan Zhang
13e3f05d3bSChunyan Zhang /**
14e3f05d3bSChunyan Zhang * struct sprd_div_internal - Internal divider description
15e3f05d3bSChunyan Zhang * @shift: Bit offset of the divider in its register
16e3f05d3bSChunyan Zhang * @width: Width of the divider field in its register
17e3f05d3bSChunyan Zhang *
18e3f05d3bSChunyan Zhang * That structure represents a single divider, and is meant to be
19e3f05d3bSChunyan Zhang * embedded in other structures representing the various clock
20e3f05d3bSChunyan Zhang * classes.
21e3f05d3bSChunyan Zhang */
22e3f05d3bSChunyan Zhang struct sprd_div_internal {
23e3f05d3bSChunyan Zhang u8 shift;
24e3f05d3bSChunyan Zhang u8 width;
25e3f05d3bSChunyan Zhang };
26e3f05d3bSChunyan Zhang
27e3f05d3bSChunyan Zhang #define _SPRD_DIV_CLK(_shift, _width) \
28e3f05d3bSChunyan Zhang { \
29e3f05d3bSChunyan Zhang .shift = _shift, \
30e3f05d3bSChunyan Zhang .width = _width, \
31e3f05d3bSChunyan Zhang }
32e3f05d3bSChunyan Zhang
33e3f05d3bSChunyan Zhang struct sprd_div {
34e3f05d3bSChunyan Zhang struct sprd_div_internal div;
35e3f05d3bSChunyan Zhang struct sprd_clk_common common;
36e3f05d3bSChunyan Zhang };
37e3f05d3bSChunyan Zhang
38*ea8ca310SChunyan Zhang #define SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
39*ea8ca310SChunyan Zhang _shift, _width, _flags, _fn) \
40e3f05d3bSChunyan Zhang struct sprd_div _struct = { \
41e3f05d3bSChunyan Zhang .div = _SPRD_DIV_CLK(_shift, _width), \
42e3f05d3bSChunyan Zhang .common = { \
43e3f05d3bSChunyan Zhang .regmap = NULL, \
44e3f05d3bSChunyan Zhang .reg = _reg, \
45*ea8ca310SChunyan Zhang .hw.init = _fn(_name, _parent, \
46*ea8ca310SChunyan Zhang &sprd_div_ops, _flags), \
47e3f05d3bSChunyan Zhang } \
48e3f05d3bSChunyan Zhang }
49e3f05d3bSChunyan Zhang
50*ea8ca310SChunyan Zhang #define SPRD_DIV_CLK(_struct, _name, _parent, _reg, \
51*ea8ca310SChunyan Zhang _shift, _width, _flags) \
52*ea8ca310SChunyan Zhang SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
53*ea8ca310SChunyan Zhang _shift, _width, _flags, CLK_HW_INIT)
54*ea8ca310SChunyan Zhang
55*ea8ca310SChunyan Zhang #define SPRD_DIV_CLK_HW(_struct, _name, _parent, _reg, \
56*ea8ca310SChunyan Zhang _shift, _width, _flags) \
57*ea8ca310SChunyan Zhang SPRD_DIV_CLK_HW_INIT_FN(_struct, _name, _parent, _reg, \
58*ea8ca310SChunyan Zhang _shift, _width, _flags, CLK_HW_INIT_HW)
59*ea8ca310SChunyan Zhang
hw_to_sprd_div(const struct clk_hw * hw)60e3f05d3bSChunyan Zhang static inline struct sprd_div *hw_to_sprd_div(const struct clk_hw *hw)
61e3f05d3bSChunyan Zhang {
62e3f05d3bSChunyan Zhang struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);
63e3f05d3bSChunyan Zhang
64e3f05d3bSChunyan Zhang return container_of(common, struct sprd_div, common);
65e3f05d3bSChunyan Zhang }
66e3f05d3bSChunyan Zhang
67e3f05d3bSChunyan Zhang unsigned long sprd_div_helper_recalc_rate(struct sprd_clk_common *common,
68e3f05d3bSChunyan Zhang const struct sprd_div_internal *div,
69e3f05d3bSChunyan Zhang unsigned long parent_rate);
70e3f05d3bSChunyan Zhang
71e3f05d3bSChunyan Zhang int sprd_div_helper_set_rate(const struct sprd_clk_common *common,
72e3f05d3bSChunyan Zhang const struct sprd_div_internal *div,
73e3f05d3bSChunyan Zhang unsigned long rate,
74e3f05d3bSChunyan Zhang unsigned long parent_rate);
75e3f05d3bSChunyan Zhang
76e3f05d3bSChunyan Zhang extern const struct clk_ops sprd_div_ops;
77e3f05d3bSChunyan Zhang
78e3f05d3bSChunyan Zhang #endif /* _SPRD_DIV_H_ */
79