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