/* * Copyright 2023 Ambiq Micro Inc. * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT ambiq_clkctrl #include #include #include #include #include #include #include LOG_MODULE_REGISTER(clock_control_ambiq, CONFIG_CLOCK_CONTROL_LOG_LEVEL); struct ambiq_clock_config { uint32_t clock_freq; const struct pinctrl_dev_config *pcfg; }; static int ambiq_clock_on(const struct device *dev, clock_control_subsys_t sub_system) { ARG_UNUSED(dev); int ret; uint32_t clock_name = (uint32_t)sub_system; am_hal_mcuctrl_control_arg_t arg = { .b_arg_hfxtal_in_use = true, .b_arg_apply_ext_source = false, .b_arg_force_update = false, }; if (clock_name >= CLOCK_CONTROL_AMBIQ_TYPE_MAX) { return -EINVAL; } switch (clock_name) { case CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE: arg.ui32_arg_hfxtal_user_mask = BIT(AM_HAL_HFXTAL_BLE_CONTROLLER_EN); arg.b_arg_enable_HfXtalClockout = true; ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32M_KICK_START, &arg); break; case CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL: ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32K_ENABLE, 0); default: ret = -ENOTSUP; break; } return ret; } static int ambiq_clock_off(const struct device *dev, clock_control_subsys_t sub_system) { ARG_UNUSED(dev); int ret; uint32_t clock_name = (uint32_t)sub_system; am_hal_mcuctrl_control_arg_t arg = { .b_arg_hfxtal_in_use = true, .b_arg_apply_ext_source = false, .b_arg_force_update = false, }; if (clock_name >= CLOCK_CONTROL_AMBIQ_TYPE_MAX) { return -EINVAL; } switch (clock_name) { case CLOCK_CONTROL_AMBIQ_TYPE_HFXTAL_BLE: arg.ui32_arg_hfxtal_user_mask = BIT(AM_HAL_HFXTAL_BLE_CONTROLLER_EN); arg.b_arg_enable_HfXtalClockout = true; ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32M_DISABLE, &arg); break; case CLOCK_CONTROL_AMBIQ_TYPE_LFXTAL: ret = am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_EXTCLK32K_DISABLE, 0); break; default: ret = -ENOTSUP; break; } return ret; } static inline int ambiq_clock_get_rate(const struct device *dev, clock_control_subsys_t sub_system, uint32_t *rate) { ARG_UNUSED(sub_system); const struct ambiq_clock_config *cfg = dev->config; *rate = cfg->clock_freq; return 0; } static inline int ambiq_clock_configure(const struct device *dev, clock_control_subsys_t sub_system, void *data) { ARG_UNUSED(sub_system); ARG_UNUSED(data); const struct ambiq_clock_config *cfg = dev->config; int ret; ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); return ret; } static int ambiq_clock_init(const struct device *dev) { ARG_UNUSED(dev); /* Nothing to do.*/ return 0; } static const struct clock_control_driver_api ambiq_clock_driver_api = { .on = ambiq_clock_on, .off = ambiq_clock_off, .get_rate = ambiq_clock_get_rate, .configure = ambiq_clock_configure, }; #define AMBIQ_CLOCK_INIT(n) \ PINCTRL_DT_INST_DEFINE(n); \ static const struct ambiq_clock_config ambiq_clock_config##n = { \ .clock_freq = DT_INST_PROP(n, clock_frequency), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n)}; \ DEVICE_DT_INST_DEFINE(n, ambiq_clock_init, NULL, NULL, &ambiq_clock_config##n, \ POST_KERNEL, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \ &ambiq_clock_driver_api); DT_INST_FOREACH_STATUS_OKAY(AMBIQ_CLOCK_INIT)