1 /*
2 * Copyright (c) 2023 EPAM Systems
3 * Copyright (c) 2023 IoT.bzh
4 *
5 * r8a779f0 Clock Pulse Generator / Module Standby and Software Reset
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #define DT_DRV_COMPAT renesas_r8a779f0_cpg_mssr
11
12 #include <errno.h>
13 #include <zephyr/arch/cpu.h>
14 #include <zephyr/drivers/clock_control.h>
15 #include <zephyr/drivers/clock_control/renesas_cpg_mssr.h>
16 #include <zephyr/dt-bindings/clock/renesas_cpg_mssr.h>
17 #include <zephyr/dt-bindings/clock/r8a779f0_cpg_mssr.h>
18 #include <zephyr/irq.h>
19 #include "clock_control_renesas_cpg_mssr.h"
20
21 #define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
22 #include <zephyr/logging/log.h>
23 LOG_MODULE_DECLARE(clock_control_rcar);
24
25 struct r8a779f0_cpg_mssr_cfg {
26 DEVICE_MMIO_ROM; /* Must be first */
27 };
28
29 struct r8a779f0_cpg_mssr_data {
30 struct rcar_cpg_mssr_data cmn; /* Must be first */
31 };
32
33 /* NOTE: the array MUST be sorted by module field */
34 static struct cpg_clk_info_table core_props[] = {
35 RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_S0D12_PER, RCAR_CPG_NONE, RCAR_CPG_NONE,
36 RCAR_CPG_KHZ(66660)),
37
38 RCAR_CORE_CLK_INFO_ITEM(R8A779F0_CLK_CL16M, RCAR_CPG_NONE, RCAR_CPG_NONE,
39 RCAR_CPG_KHZ(16660)),
40 };
41
42 /* NOTE: the array MUST be sorted by module field */
43 static struct cpg_clk_info_table mod_props[] = {
44 RCAR_MOD_CLK_INFO_ITEM(702, R8A779F0_CLK_S0D12_PER),
45 RCAR_MOD_CLK_INFO_ITEM(704, R8A779F0_CLK_S0D12_PER),
46
47 RCAR_MOD_CLK_INFO_ITEM(915, R8A779F0_CLK_CL16M),
48 };
49
r8a779f0_cpg_enable_disable_core(const struct device * dev,struct cpg_clk_info_table * clk_info,uint32_t enable)50 static int r8a779f0_cpg_enable_disable_core(const struct device *dev,
51 struct cpg_clk_info_table *clk_info, uint32_t enable)
52 {
53 ARG_UNUSED(dev);
54 ARG_UNUSED(clk_info);
55 ARG_UNUSED(enable);
56
57 return -ENOTSUP;
58 }
59
r8a779f0_cpg_core_clock_endisable(const struct device * dev,struct rcar_cpg_clk * clk,bool enable)60 static int r8a779f0_cpg_core_clock_endisable(const struct device *dev, struct rcar_cpg_clk *clk,
61 bool enable)
62 {
63 struct cpg_clk_info_table *clk_info;
64 struct r8a779f0_cpg_mssr_data *data = dev->data;
65 k_spinlock_key_t key;
66
67 clk_info = rcar_cpg_find_clk_info_by_module_id(dev, clk->domain, clk->module);
68 if (!clk_info) {
69 return -EINVAL;
70 }
71
72 if (enable) {
73 if (clk->rate > 0) {
74 int ret;
75 uintptr_t rate = clk->rate;
76
77 ret = rcar_cpg_set_rate(dev, (clock_control_subsys_t)clk,
78 (clock_control_subsys_rate_t)rate);
79 if (ret < 0) {
80 return ret;
81 }
82 }
83 }
84
85 key = k_spin_lock(&data->cmn.lock);
86 r8a779f0_cpg_enable_disable_core(dev, clk_info, enable);
87 k_spin_unlock(&data->cmn.lock, key);
88
89 return 0;
90 }
91
r8a779f0_cpg_mssr_start_stop(const struct device * dev,clock_control_subsys_t sys,bool enable)92 int r8a779f0_cpg_mssr_start_stop(const struct device *dev, clock_control_subsys_t sys, bool enable)
93 {
94 struct rcar_cpg_clk *clk = (struct rcar_cpg_clk *)sys;
95 int ret;
96
97 if (!dev || !sys) {
98 return -EINVAL;
99 }
100
101 if (clk->domain == CPG_MOD) {
102 struct r8a779f0_cpg_mssr_data *data = dev->data;
103 k_spinlock_key_t key;
104
105 key = k_spin_lock(&data->cmn.lock);
106 ret = rcar_cpg_mstp_clock_endisable(DEVICE_MMIO_GET(dev), clk->module, enable);
107 k_spin_unlock(&data->cmn.lock, key);
108 } else if (clk->domain == CPG_CORE) {
109 ret = r8a779f0_cpg_core_clock_endisable(dev, clk, enable);
110 } else {
111 ret = -EINVAL;
112 }
113
114 return ret;
115 }
116
r8a779f0_get_div_helper(uint32_t reg_val,uint32_t module)117 static uint32_t r8a779f0_get_div_helper(uint32_t reg_val, uint32_t module)
118 {
119 switch (module) {
120 case R8A779F0_CLK_S0D12_PER:
121 case R8A779F0_CLK_CL16M:
122 return 1;
123 default:
124 return RCAR_CPG_NONE;
125 }
126 }
127
r8a779f0_set_rate_helper(uint32_t module,uint32_t * divider,uint32_t * div_mask)128 static int r8a779f0_set_rate_helper(uint32_t module, uint32_t *divider, uint32_t *div_mask)
129 {
130 ARG_UNUSED(module);
131 ARG_UNUSED(divider);
132 ARG_UNUSED(div_mask);
133
134 return -ENOTSUP;
135 }
136
r8a779f0_cpg_mssr_start(const struct device * dev,clock_control_subsys_t sys)137 static int r8a779f0_cpg_mssr_start(const struct device *dev, clock_control_subsys_t sys)
138 {
139 return r8a779f0_cpg_mssr_start_stop(dev, sys, true);
140 }
141
r8a779f0_cpg_mssr_stop(const struct device * dev,clock_control_subsys_t sys)142 static int r8a779f0_cpg_mssr_stop(const struct device *dev, clock_control_subsys_t sys)
143 {
144 return r8a779f0_cpg_mssr_start_stop(dev, sys, false);
145 }
146
r8a779f0_cpg_mssr_init(const struct device * dev)147 static int r8a779f0_cpg_mssr_init(const struct device *dev)
148 {
149 DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
150
151 rcar_cpg_build_clock_relationship(dev);
152 rcar_cpg_update_all_in_out_freq(dev);
153 return 0;
154 }
155
156 static const struct clock_control_driver_api r8a779f0_cpg_mssr_api = {
157 .on = r8a779f0_cpg_mssr_start,
158 .off = r8a779f0_cpg_mssr_stop,
159 .get_rate = rcar_cpg_get_rate,
160 .set_rate = rcar_cpg_set_rate,
161 };
162
163 #define R8A779F0_MSSR_INIT(inst) \
164 static struct r8a779f0_cpg_mssr_cfg cpg_mssr##inst##_cfg = { \
165 DEVICE_MMIO_ROM_INIT(DT_DRV_INST(inst)), \
166 }; \
167 \
168 static struct r8a779f0_cpg_mssr_data cpg_mssr##inst##_data = { \
169 .cmn.clk_info_table[CPG_CORE] = core_props, \
170 .cmn.clk_info_table_size[CPG_CORE] = ARRAY_SIZE(core_props), \
171 .cmn.clk_info_table[CPG_MOD] = mod_props, \
172 .cmn.clk_info_table_size[CPG_MOD] = ARRAY_SIZE(mod_props), \
173 .cmn.get_div_helper = r8a779f0_get_div_helper, \
174 .cmn.set_rate_helper = r8a779f0_set_rate_helper \
175 }; \
176 \
177 DEVICE_DT_INST_DEFINE(inst, \
178 &r8a779f0_cpg_mssr_init, \
179 NULL, \
180 &cpg_mssr##inst##_data, \
181 &cpg_mssr##inst##_cfg, \
182 PRE_KERNEL_1, \
183 CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \
184 &r8a779f0_cpg_mssr_api);
185
186 DT_INST_FOREACH_STATUS_OKAY(R8A779F0_MSSR_INIT)
187