1 /*
2 * Copyright 2023 Ambiq Micro Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ambiq_clkctrl
8
9 #include <errno.h>
10 #include <zephyr/init.h>
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/drivers/clock_control/clock_control_ambiq.h>
14 #include <am_mcu_apollo.h>
15
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_REGISTER(clock_control_ambiq, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
18
19 struct ambiq_clock_config {
20 uint32_t clock_freq;
21 const struct pinctrl_dev_config *pcfg;
22 };
23
ambiq_clock_on(const struct device * dev,clock_control_subsys_t sub_system)24 static int ambiq_clock_on(const struct device *dev, clock_control_subsys_t sub_system)
25 {
26 ARG_UNUSED(dev);
27
28 int ret;
29 uint32_t clock_name = (uint32_t)sub_system;
30 am_hal_mcuctrl_control_arg_t arg = {
31 .b_arg_hfxtal_in_use = true,
32 .b_arg_apply_ext_source = false,
33 .b_arg_force_update = false,
34 };
35
36 if (clock_name >= CLOCK_CONTROL_AMBIQ_TYPE_MAX) {
37 return -EINVAL;
38 }
39
40 switch (clock_name) {
41 case CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE:
42 arg.ui32_arg_hfxtal_user_mask = BIT(AM_HAL_HFXTAL_BLE_CONTROLLER_EN);
43 arg.b_arg_enable_HfXtalClockout = true;
44 ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32M_KICK_START, &arg);
45 break;
46 case CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL:
47 ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32K_ENABLE, 0);
48 default:
49 ret = -ENOTSUP;
50 break;
51 }
52
53 return ret;
54 }
55
ambiq_clock_off(const struct device * dev,clock_control_subsys_t sub_system)56 static int ambiq_clock_off(const struct device *dev, clock_control_subsys_t sub_system)
57 {
58 ARG_UNUSED(dev);
59
60 int ret;
61 uint32_t clock_name = (uint32_t)sub_system;
62 am_hal_mcuctrl_control_arg_t arg = {
63 .b_arg_hfxtal_in_use = true,
64 .b_arg_apply_ext_source = false,
65 .b_arg_force_update = false,
66 };
67
68 if (clock_name >= CLOCK_CONTROL_AMBIQ_TYPE_MAX) {
69 return -EINVAL;
70 }
71
72 switch (clock_name) {
73 case CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE:
74 arg.ui32_arg_hfxtal_user_mask = BIT(AM_HAL_HFXTAL_BLE_CONTROLLER_EN);
75 arg.b_arg_enable_HfXtalClockout = true;
76 ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32M_DISABLE, &arg);
77 break;
78 case CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL:
79 ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32K_DISABLE, 0);
80 break;
81 default:
82 ret = -ENOTSUP;
83 break;
84 }
85
86 return ret;
87 }
88
ambiq_clock_get_rate(const struct device * dev,clock_control_subsys_t sub_system,uint32_t * rate)89 static inline int ambiq_clock_get_rate(const struct device *dev, clock_control_subsys_t sub_system,
90 uint32_t *rate)
91 {
92 ARG_UNUSED(sub_system);
93
94 const struct ambiq_clock_config *cfg = dev->config;
95 *rate = cfg->clock_freq;
96
97 return 0;
98 }
99
ambiq_clock_configure(const struct device * dev,clock_control_subsys_t sub_system,void * data)100 static inline int ambiq_clock_configure(const struct device *dev, clock_control_subsys_t sub_system,
101 void *data)
102 {
103 ARG_UNUSED(sub_system);
104 ARG_UNUSED(data);
105
106 const struct ambiq_clock_config *cfg = dev->config;
107 int ret;
108
109 ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
110
111 return ret;
112 }
113
ambiq_clock_init(const struct device * dev)114 static int ambiq_clock_init(const struct device *dev)
115 {
116 ARG_UNUSED(dev);
117
118 /* Nothing to do.*/
119 return 0;
120 }
121
122 static const struct clock_control_driver_api ambiq_clock_driver_api = {
123 .on = ambiq_clock_on,
124 .off = ambiq_clock_off,
125 .get_rate = ambiq_clock_get_rate,
126 .configure = ambiq_clock_configure,
127 };
128
129 #define AMBIQ_CLOCK_INIT(n) \
130 PINCTRL_DT_INST_DEFINE(n); \
131 static const struct ambiq_clock_config ambiq_clock_config##n = { \
132 .clock_freq = DT_INST_PROP(n, clock_frequency), \
133 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n)}; \
134 DEVICE_DT_INST_DEFINE(n, ambiq_clock_init, NULL, NULL, &ambiq_clock_config##n, \
135 POST_KERNEL, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \
136 &ambiq_clock_driver_api);
137
138 DT_INST_FOREACH_STATUS_OKAY(AMBIQ_CLOCK_INIT)
139