添加rtthread相关代码
This commit is contained in:
		
							
								
								
									
										10
									
								
								riscv/rtthread/components/drivers/hwtimer/Kconfig
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								riscv/rtthread/components/drivers/hwtimer/Kconfig
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| menuconfig RT_USING_HWTIMER | ||||
|     bool "Using Hardware Timer device drivers" | ||||
|     default n | ||||
|  | ||||
| config RT_HWTIMER_ARM_ARCH | ||||
|     bool "ARM ARCH Timer" | ||||
|     depends on RT_USING_DM | ||||
|     depends on RT_USING_HWTIMER | ||||
|     depends on ARCH_ARM_CORTEX_A || ARCH_ARMV8 | ||||
|     default n | ||||
							
								
								
									
										18
									
								
								riscv/rtthread/components/drivers/hwtimer/SConscript
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								riscv/rtthread/components/drivers/hwtimer/SConscript
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| from building import * | ||||
|  | ||||
| group = [] | ||||
|  | ||||
| if not GetDepend(['RT_USING_HWTIMER']): | ||||
|     Return('group') | ||||
|  | ||||
| cwd = GetCurrentDir() | ||||
| CPPPATH = [cwd + '/../include'] | ||||
|  | ||||
| src = ['hwtimer.c'] | ||||
|  | ||||
| if GetDepend(['RT_HWTIMER_ARM_ARCH']): | ||||
|     src += ['hwtimer-arm_arch.c'] | ||||
|  | ||||
| group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) | ||||
|  | ||||
| Return('group') | ||||
							
								
								
									
										383
									
								
								riscv/rtthread/components/drivers/hwtimer/hwtimer-arm_arch.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										383
									
								
								riscv/rtthread/components/drivers/hwtimer/hwtimer-arm_arch.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,383 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2022, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author       Notes | ||||
|  * 2021-12-20     GuEe-GUI     first version | ||||
|  * 2022-08-24     GuEe-GUI     Add OFW support | ||||
|  */ | ||||
|  | ||||
| #include <rthw.h> | ||||
| #include <rtthread.h> | ||||
| #include <rtdevice.h> | ||||
|  | ||||
| /* support registers access and timer registers in libcpu */ | ||||
| #include <cpu.h> | ||||
| #include <cpuport.h> | ||||
|  | ||||
| typedef void (*timer_ctrl_handle)(rt_bool_t enable); | ||||
| typedef rt_uint64_t (*timer_value_handle)(rt_uint64_t val); | ||||
|  | ||||
| static volatile rt_uint64_t timer_step; | ||||
|  | ||||
| static int arm_arch_timer_irq = -1; | ||||
| static timer_ctrl_handle arm_arch_timer_ctrl_handle = RT_NULL; | ||||
| static timer_value_handle arm_arch_timer_value_handle = RT_NULL; | ||||
|  | ||||
| /* CTL */ | ||||
| static void mon_ptimer_ctrl(rt_bool_t enable) | ||||
| { | ||||
|     rt_hw_sysreg_write(CNTPS_CTL, !!enable); | ||||
| } | ||||
|  | ||||
| static void hyp_s_ptimer_ctrl(rt_bool_t enable) | ||||
| { | ||||
| #if ARCH_ARMV8_EXTENSIONS > 1 | ||||
|     rt_hw_sysreg_write(CNTHPS_CTL, !!enable); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void hyp_ns_ptimer_ctrl(rt_bool_t enable) | ||||
| { | ||||
|     rt_hw_sysreg_write(CNTHP_CTL, !!enable); | ||||
| } | ||||
|  | ||||
| static void hyp_s_vtimer_ctrl(rt_bool_t enable) | ||||
| { | ||||
| #if ARCH_ARMV8_EXTENSIONS > 1 | ||||
|     rt_hw_sysreg_write(CNTHVS_CTL, !!enable); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void hyp_ns_vtimer_ctrl(rt_bool_t enable) | ||||
| { | ||||
| #if ARCH_ARMV8_EXTENSIONS > 1 | ||||
|     rt_hw_sysreg_write(CNTHV_CTL, !!enable); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static void os_ptimer_ctrl(rt_bool_t enable) | ||||
| { | ||||
|     rt_hw_sysreg_write(CNTP_CTL, !!enable); | ||||
| } | ||||
|  | ||||
| static void os_vtimer_ctrl(rt_bool_t enable) | ||||
| { | ||||
|     rt_hw_sysreg_write(CNTV_CTL, !!enable); | ||||
| } | ||||
|  | ||||
| /* TVAL */ | ||||
| static rt_uint64_t mon_ptimer_value(rt_uint64_t val) | ||||
| { | ||||
|     if (val) | ||||
|     { | ||||
|         rt_hw_sysreg_write(CNTPS_TVAL, val); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_hw_sysreg_read(CNTPS_TVAL, val); | ||||
|     } | ||||
|  | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| static rt_uint64_t hyp_s_ptimer_value(rt_uint64_t val) | ||||
| { | ||||
| #if ARCH_ARMV8_EXTENSIONS > 1 | ||||
|     if (val) | ||||
|     { | ||||
|         rt_hw_sysreg_write(CNTHPS_TVAL, val); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_hw_sysreg_read(CNTHPS_TVAL, val); | ||||
|     } | ||||
|  | ||||
|     return val; | ||||
| #else | ||||
|     return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static rt_uint64_t hyp_ns_ptimer_value(rt_uint64_t val) | ||||
| { | ||||
|     if (val) | ||||
|     { | ||||
|         rt_hw_sysreg_write(CNTHP_TVAL, val); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_hw_sysreg_read(CNTHP_TVAL, val); | ||||
|     } | ||||
|  | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| static rt_uint64_t hyp_s_vtimer_value(rt_uint64_t val) | ||||
| { | ||||
| #if ARCH_ARMV8_EXTENSIONS > 1 | ||||
|     if (val) | ||||
|     { | ||||
|         rt_hw_sysreg_write(CNTHVS_TVAL, val); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_hw_sysreg_read(CNTHVS_TVAL, val); | ||||
|     } | ||||
|  | ||||
|     return val; | ||||
| #else | ||||
|     return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static rt_uint64_t hyp_ns_vtimer_value(rt_uint64_t val) | ||||
| { | ||||
| #if ARCH_ARMV8_EXTENSIONS > 1 | ||||
|     if (val) | ||||
|     { | ||||
|         rt_hw_sysreg_write(CNTHV_TVAL, val); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_hw_sysreg_read(CNTHV_TVAL, val); | ||||
|     } | ||||
|  | ||||
|     return val; | ||||
| #else | ||||
|     return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| static rt_uint64_t os_ptimer_value(rt_uint64_t val) | ||||
| { | ||||
|     if (val) | ||||
|     { | ||||
|         rt_hw_sysreg_write(CNTP_TVAL, val); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_hw_sysreg_read(CNTP_TVAL, val); | ||||
|     } | ||||
|  | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| static rt_uint64_t os_vtimer_value(rt_uint64_t val) | ||||
| { | ||||
|     if (val) | ||||
|     { | ||||
|         rt_hw_sysreg_write(CNTV_TVAL, val); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_hw_sysreg_read(CNTV_TVAL, val); | ||||
|     } | ||||
|  | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| static timer_ctrl_handle ctrl_handle[] = | ||||
| { | ||||
|     mon_ptimer_ctrl, | ||||
|     hyp_s_ptimer_ctrl, | ||||
|     hyp_ns_ptimer_ctrl, | ||||
|     hyp_s_vtimer_ctrl, | ||||
|     hyp_ns_vtimer_ctrl, | ||||
|     os_ptimer_ctrl, | ||||
|     os_vtimer_ctrl, | ||||
| }; | ||||
|  | ||||
| static timer_value_handle value_handle[] = | ||||
| { | ||||
|     mon_ptimer_value, | ||||
|     hyp_s_ptimer_value, | ||||
|     hyp_ns_ptimer_value, | ||||
|     hyp_s_vtimer_value, | ||||
|     hyp_ns_vtimer_value, | ||||
|     os_ptimer_value, | ||||
|     os_vtimer_value, | ||||
| }; | ||||
|  | ||||
| static rt_err_t arm_arch_timer_local_enable(void) | ||||
| { | ||||
|     rt_err_t ret = RT_EOK; | ||||
|  | ||||
|     if (arm_arch_timer_irq >= 0) | ||||
|     { | ||||
|         arm_arch_timer_ctrl_handle(RT_FALSE); | ||||
|         arm_arch_timer_value_handle(timer_step); | ||||
|  | ||||
|         rt_hw_interrupt_umask(arm_arch_timer_irq); | ||||
|  | ||||
|         arm_arch_timer_ctrl_handle(RT_TRUE); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ret = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| rt_used | ||||
| static rt_err_t arm_arch_timer_local_disable(void) | ||||
| { | ||||
|     rt_err_t ret = RT_EOK; | ||||
|  | ||||
|     if (arm_arch_timer_ctrl_handle) | ||||
|     { | ||||
|         arm_arch_timer_ctrl_handle(RT_FALSE); | ||||
|         rt_hw_interrupt_mask(arm_arch_timer_irq); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ret = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| rt_used | ||||
| static rt_err_t arm_arch_timer_set_frequency(rt_uint64_t frq) | ||||
| { | ||||
|     rt_err_t ret = RT_EOK; | ||||
|  | ||||
| #ifdef ARCH_SUPPORT_TEE | ||||
|     rt_hw_isb(); | ||||
|     rt_hw_sysreg_write(CNTFRQ, frq); | ||||
|     rt_hw_dsb(); | ||||
| #else | ||||
|     ret = -RT_ENOSYS; | ||||
| #endif | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| rt_used | ||||
| static rt_uint64_t arm_arch_timer_get_frequency(void) | ||||
| { | ||||
|     rt_uint64_t frq; | ||||
|  | ||||
|     rt_hw_isb(); | ||||
|     rt_hw_sysreg_read(CNTFRQ, frq); | ||||
|     rt_hw_isb(); | ||||
|  | ||||
|     return frq; | ||||
| } | ||||
|  | ||||
| rt_used | ||||
| static rt_err_t arm_arch_timer_set_value(rt_uint64_t val) | ||||
| { | ||||
|     rt_err_t ret = RT_EOK; | ||||
|  | ||||
|     if (arm_arch_timer_value_handle) | ||||
|     { | ||||
|         val = arm_arch_timer_value_handle(val); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ret = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| rt_used | ||||
| static rt_uint64_t arm_arch_timer_get_value(void) | ||||
| { | ||||
|     rt_uint64_t val = 0; | ||||
|  | ||||
|     if (arm_arch_timer_value_handle) | ||||
|     { | ||||
|         val = arm_arch_timer_value_handle(0); | ||||
|     } | ||||
|  | ||||
|     return val; | ||||
| } | ||||
|  | ||||
| static void arm_arch_timer_isr(int vector, void *param) | ||||
| { | ||||
|     arm_arch_timer_set_value(timer_step); | ||||
|  | ||||
|     rt_tick_increase(); | ||||
| } | ||||
|  | ||||
| static int arm_arch_timer_post_init(void) | ||||
| { | ||||
|     arm_arch_timer_local_enable(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| INIT_SECONDARY_CPU_EXPORT(arm_arch_timer_post_init); | ||||
|  | ||||
| static rt_err_t arm_arch_timer_probe(struct rt_platform_device *pdev) | ||||
| { | ||||
|     int mode_idx, irq_idx; | ||||
|     const char *irq_name[] = | ||||
|     { | ||||
|         "phys",     /* Secure Phys IRQ */ | ||||
|         "virt",     /* Non-secure Phys IRQ */ | ||||
|         "hyp-phys", /* Virt IRQ */ | ||||
|         "hyp-virt", /* Hyp IRQ */ | ||||
|     }; | ||||
|  | ||||
| #if defined(ARCH_SUPPORT_TEE) | ||||
|     mode_idx = 0; | ||||
|     irq_idx = 0; | ||||
| #elif defined(ARCH_SUPPORT_HYP) | ||||
|     mode_idx = 2; | ||||
|     irq_idx = 3; | ||||
| #else | ||||
|     mode_idx = 5; | ||||
|     irq_idx = 1; | ||||
| #endif | ||||
|  | ||||
|     arm_arch_timer_irq = rt_dm_dev_get_irq_by_name(&pdev->parent, irq_name[irq_idx]); | ||||
|  | ||||
|     if (arm_arch_timer_irq < 0) | ||||
|     { | ||||
|         arm_arch_timer_irq = rt_dm_dev_get_irq(&pdev->parent, irq_idx); | ||||
|     } | ||||
|  | ||||
|     if (arm_arch_timer_irq < 0) | ||||
|     { | ||||
|         return -RT_EEMPTY; | ||||
|     } | ||||
|  | ||||
|     arm_arch_timer_ctrl_handle = ctrl_handle[mode_idx]; | ||||
|     arm_arch_timer_value_handle = value_handle[mode_idx]; | ||||
|  | ||||
|     rt_hw_interrupt_install(arm_arch_timer_irq, arm_arch_timer_isr, RT_NULL, "tick-arm-timer"); | ||||
|  | ||||
|     timer_step = arm_arch_timer_get_frequency() / RT_TICK_PER_SECOND; | ||||
|  | ||||
|     arm_arch_timer_local_enable(); | ||||
|  | ||||
|     return RT_EOK; | ||||
| } | ||||
|  | ||||
| static const struct rt_ofw_node_id arm_arch_timer_ofw_ids[] = | ||||
| { | ||||
|     { .compatible = "arm,armv7-timer", }, | ||||
|     { .compatible = "arm,armv8-timer", }, | ||||
|     { /* sentinel */ } | ||||
| }; | ||||
|  | ||||
| static struct rt_platform_driver arm_arch_timer_driver = | ||||
| { | ||||
|     .name = "arm-arch-timer", | ||||
|     .ids = arm_arch_timer_ofw_ids, | ||||
|  | ||||
|     .probe = arm_arch_timer_probe, | ||||
| }; | ||||
|  | ||||
| static int arm_arch_timer_drv_register(void) | ||||
| { | ||||
|     rt_platform_driver_register(&arm_arch_timer_driver); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
| INIT_SUBSYS_EXPORT(arm_arch_timer_drv_register); | ||||
							
								
								
									
										410
									
								
								riscv/rtthread/components/drivers/hwtimer/hwtimer.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										410
									
								
								riscv/rtthread/components/drivers/hwtimer/hwtimer.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,410 @@ | ||||
| /* | ||||
|  * Copyright (c) 2006-2023, RT-Thread Development Team | ||||
|  * | ||||
|  * SPDX-License-Identifier: Apache-2.0 | ||||
|  * | ||||
|  * Change Logs: | ||||
|  * Date           Author         Notes | ||||
|  * 2015-08-31     heyuanjie87    first version | ||||
|  */ | ||||
|  | ||||
| #include <rtdevice.h> | ||||
| #include <rthw.h> | ||||
|  | ||||
| #define DBG_TAG "hwtimer" | ||||
| #define DBG_LVL DBG_INFO | ||||
| #include <rtdbg.h> | ||||
|  | ||||
| #ifdef RT_USING_DM | ||||
| void (*rt_device_hwtimer_us_delay)(rt_uint32_t us) = RT_NULL; | ||||
|  | ||||
| void rt_hw_us_delay(rt_uint32_t us) | ||||
| { | ||||
|     if (rt_device_hwtimer_us_delay) | ||||
|     { | ||||
|         rt_device_hwtimer_us_delay(us); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         LOG_E("Implemented at least in the libcpu"); | ||||
|  | ||||
|         RT_ASSERT(0); | ||||
|     } | ||||
| } | ||||
| #endif /* RT_USING_DM */ | ||||
|  | ||||
| rt_inline rt_uint32_t timeout_calc(rt_hwtimer_t *timer, rt_hwtimerval_t *tv) | ||||
| { | ||||
|     float overflow; | ||||
|     float timeout; | ||||
|     rt_uint32_t counter; | ||||
|     int i, index = 0; | ||||
|     float tv_sec; | ||||
|     float devi_min = 1; | ||||
|     float devi; | ||||
|  | ||||
|     /* changed to second */ | ||||
|     overflow = timer->info->maxcnt/(float)timer->freq; | ||||
|     tv_sec = tv->sec + tv->usec/(float)1000000; | ||||
|  | ||||
|     if (tv_sec < (1/(float)timer->freq)) | ||||
|     { | ||||
|         /* little timeout */ | ||||
|         i = 0; | ||||
|         timeout = 1/(float)timer->freq; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         for (i = 1; i > 0; i ++) | ||||
|         { | ||||
|             timeout = tv_sec/i; | ||||
|  | ||||
|             if (timeout <= overflow) | ||||
|             { | ||||
|                 counter = (rt_uint32_t)(timeout * timer->freq); | ||||
|                 devi = tv_sec - (counter / (float)timer->freq) * i; | ||||
|                 /* Minimum calculation error */ | ||||
|                 if (devi > devi_min) | ||||
|                 { | ||||
|                     i = index; | ||||
|                     timeout = tv_sec/i; | ||||
|                     break; | ||||
|                 } | ||||
|                 else if (devi == 0) | ||||
|                 { | ||||
|                     break; | ||||
|                 } | ||||
|                 else if (devi < devi_min) | ||||
|                 { | ||||
|                     devi_min = devi; | ||||
|                     index = i; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     timer->cycles = i; | ||||
|     timer->reload = i; | ||||
|     timer->period_sec = timeout; | ||||
|     counter = (rt_uint32_t)(timeout * timer->freq); | ||||
|  | ||||
|     return counter; | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_hwtimer_init(struct rt_device *dev) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     rt_hwtimer_t *timer; | ||||
|  | ||||
|     timer = (rt_hwtimer_t *)dev; | ||||
|     /* try to change to 1MHz */ | ||||
|     if ((1000000 <= timer->info->maxfreq) && (1000000 >= timer->info->minfreq)) | ||||
|     { | ||||
|         timer->freq = 1000000; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         timer->freq = timer->info->minfreq; | ||||
|     } | ||||
|     timer->mode = HWTIMER_MODE_ONESHOT; | ||||
|     timer->cycles = 0; | ||||
|     timer->overflow = 0; | ||||
|  | ||||
|     if (timer->ops->init) | ||||
|     { | ||||
|         timer->ops->init(timer, 1); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_hwtimer_open(struct rt_device *dev, rt_uint16_t oflag) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     rt_hwtimer_t *timer; | ||||
|  | ||||
|     timer = (rt_hwtimer_t *)dev; | ||||
|     if (timer->ops->control != RT_NULL) | ||||
|     { | ||||
|         timer->ops->control(timer, HWTIMER_CTRL_FREQ_SET, &timer->freq); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_hwtimer_close(struct rt_device *dev) | ||||
| { | ||||
|     rt_err_t result = RT_EOK; | ||||
|     rt_hwtimer_t *timer; | ||||
|  | ||||
|     timer = (rt_hwtimer_t*)dev; | ||||
|     if (timer->ops->init != RT_NULL) | ||||
|     { | ||||
|         timer->ops->init(timer, 0); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         result = -RT_ENOSYS; | ||||
|     } | ||||
|  | ||||
|     dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED; | ||||
|     dev->rx_indicate = RT_NULL; | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| static rt_ssize_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_hwtimer_t *timer; | ||||
|     rt_hwtimerval_t tv; | ||||
|     rt_uint32_t cnt; | ||||
|     rt_base_t level; | ||||
|     rt_int32_t overflow; | ||||
|     float t; | ||||
|  | ||||
|     timer = (rt_hwtimer_t *)dev; | ||||
|     if (timer->ops->count_get == RT_NULL) | ||||
|         return 0; | ||||
|  | ||||
|     level = rt_hw_interrupt_disable(); | ||||
|     cnt = timer->ops->count_get(timer); | ||||
|     overflow = timer->overflow; | ||||
|     rt_hw_interrupt_enable(level); | ||||
|  | ||||
|     if (timer->info->cntmode == HWTIMER_CNTMODE_DW) | ||||
|     { | ||||
|         cnt = (rt_uint32_t)(timer->freq * timer->period_sec) - cnt; | ||||
|     } | ||||
|     if (timer->mode == HWTIMER_MODE_ONESHOT) | ||||
|     { | ||||
|         overflow = 0; | ||||
|     } | ||||
|  | ||||
|     t = overflow * timer->period_sec + cnt/(float)timer->freq; | ||||
|     tv.sec = (rt_int32_t)t; | ||||
|     tv.usec = (rt_int32_t)((t - tv.sec) * 1000000); | ||||
|     size = size > sizeof(tv)? sizeof(tv) : size; | ||||
|     rt_memcpy(buffer, &tv, size); | ||||
|  | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| static rt_ssize_t rt_hwtimer_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size) | ||||
| { | ||||
|     rt_base_t level; | ||||
|     rt_uint32_t t; | ||||
|     rt_hwtimer_mode_t opm = HWTIMER_MODE_PERIOD; | ||||
|     rt_hwtimer_t *timer; | ||||
|  | ||||
|     timer = (rt_hwtimer_t *)dev; | ||||
|     if ((timer->ops->start == RT_NULL) || (timer->ops->stop == RT_NULL)) | ||||
|         return 0; | ||||
|  | ||||
|     if (size != sizeof(rt_hwtimerval_t)) | ||||
|         return 0; | ||||
|  | ||||
|     timer->ops->stop(timer); | ||||
|  | ||||
|     level = rt_hw_interrupt_disable(); | ||||
|     timer->overflow = 0; | ||||
|     rt_hw_interrupt_enable(level); | ||||
|  | ||||
|     t = timeout_calc(timer, (rt_hwtimerval_t*)buffer); | ||||
|     if ((timer->cycles <= 1) && (timer->mode == HWTIMER_MODE_ONESHOT)) | ||||
|     { | ||||
|         opm = HWTIMER_MODE_ONESHOT; | ||||
|     } | ||||
|  | ||||
|     if (timer->ops->start(timer, t, opm) != RT_EOK) | ||||
|         size = 0; | ||||
|  | ||||
|     return size; | ||||
| } | ||||
|  | ||||
| static rt_err_t rt_hwtimer_control(struct rt_device *dev, int cmd, void *args) | ||||
| { | ||||
|     rt_base_t level; | ||||
|     rt_err_t result = RT_EOK; | ||||
|     rt_hwtimer_t *timer; | ||||
|  | ||||
|     timer = (rt_hwtimer_t *)dev; | ||||
|  | ||||
|     switch (cmd) | ||||
|     { | ||||
|     case HWTIMER_CTRL_STOP: | ||||
|     { | ||||
|         if (timer->ops->stop != RT_NULL) | ||||
|         { | ||||
|             timer->ops->stop(timer); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             result = -RT_ENOSYS; | ||||
|         } | ||||
|     } | ||||
|     break; | ||||
|     case HWTIMER_CTRL_FREQ_SET: | ||||
|     { | ||||
|         rt_int32_t *f; | ||||
|  | ||||
|         if (args == RT_NULL) | ||||
|         { | ||||
|             result = -RT_EEMPTY; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         f = (rt_int32_t*)args; | ||||
|         if ((*f > timer->info->maxfreq) || (*f < timer->info->minfreq)) | ||||
|         { | ||||
|             LOG_W("frequency setting out of range! It will maintain at %d Hz", timer->freq); | ||||
|             result = -RT_EINVAL; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         if (timer->ops->control != RT_NULL) | ||||
|         { | ||||
|             result = timer->ops->control(timer, cmd, args); | ||||
|             if (result == RT_EOK) | ||||
|             { | ||||
|                 level = rt_hw_interrupt_disable(); | ||||
|                 timer->freq = *f; | ||||
|                 rt_hw_interrupt_enable(level); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             result = -RT_ENOSYS; | ||||
|         } | ||||
|     } | ||||
|     break; | ||||
|     case HWTIMER_CTRL_INFO_GET: | ||||
|     { | ||||
|         if (args == RT_NULL) | ||||
|         { | ||||
|             result = -RT_EEMPTY; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         *((struct rt_hwtimer_info*)args) = *timer->info; | ||||
|     } | ||||
|     break; | ||||
|     case HWTIMER_CTRL_MODE_SET: | ||||
|     { | ||||
|         rt_hwtimer_mode_t *m; | ||||
|  | ||||
|         if (args == RT_NULL) | ||||
|         { | ||||
|             result = -RT_EEMPTY; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         m = (rt_hwtimer_mode_t*)args; | ||||
|  | ||||
|         if ((*m != HWTIMER_MODE_ONESHOT) && (*m != HWTIMER_MODE_PERIOD)) | ||||
|         { | ||||
|             result = -RT_ERROR; | ||||
|             break; | ||||
|         } | ||||
|         level = rt_hw_interrupt_disable(); | ||||
|         timer->mode = *m; | ||||
|         rt_hw_interrupt_enable(level); | ||||
|     } | ||||
|     break; | ||||
|     default: | ||||
|     { | ||||
|         result = -RT_ENOSYS; | ||||
|     } | ||||
|     break; | ||||
|     } | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| void rt_device_hwtimer_isr(rt_hwtimer_t *timer) | ||||
| { | ||||
|     rt_base_t level; | ||||
|  | ||||
|     RT_ASSERT(timer != RT_NULL); | ||||
|  | ||||
|     level = rt_hw_interrupt_disable(); | ||||
|  | ||||
|     timer->overflow ++; | ||||
|  | ||||
|     if (timer->cycles != 0) | ||||
|     { | ||||
|         timer->cycles --; | ||||
|     } | ||||
|  | ||||
|     if (timer->cycles == 0) | ||||
|     { | ||||
|         timer->cycles = timer->reload; | ||||
|  | ||||
|         rt_hw_interrupt_enable(level); | ||||
|  | ||||
|         if (timer->mode == HWTIMER_MODE_ONESHOT) | ||||
|         { | ||||
|             if (timer->ops->stop != RT_NULL) | ||||
|             { | ||||
|                 timer->ops->stop(timer); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (timer->parent.rx_indicate != RT_NULL) | ||||
|         { | ||||
|             timer->parent.rx_indicate(&timer->parent, sizeof(struct rt_hwtimerval)); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         rt_hw_interrupt_enable(level); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
| const static struct rt_device_ops hwtimer_ops = | ||||
| { | ||||
|     rt_hwtimer_init, | ||||
|     rt_hwtimer_open, | ||||
|     rt_hwtimer_close, | ||||
|     rt_hwtimer_read, | ||||
|     rt_hwtimer_write, | ||||
|     rt_hwtimer_control | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data) | ||||
| { | ||||
|     struct rt_device *device; | ||||
|  | ||||
|     RT_ASSERT(timer != RT_NULL); | ||||
|     RT_ASSERT(timer->ops != RT_NULL); | ||||
|     RT_ASSERT(timer->info != RT_NULL); | ||||
|  | ||||
|     device = &(timer->parent); | ||||
|  | ||||
|     device->type        = RT_Device_Class_Timer; | ||||
|     device->rx_indicate = RT_NULL; | ||||
|     device->tx_complete = RT_NULL; | ||||
|  | ||||
| #ifdef RT_USING_DEVICE_OPS | ||||
|     device->ops         = &hwtimer_ops; | ||||
| #else | ||||
|     device->init        = rt_hwtimer_init; | ||||
|     device->open        = rt_hwtimer_open; | ||||
|     device->close       = rt_hwtimer_close; | ||||
|     device->read        = rt_hwtimer_read; | ||||
|     device->write       = rt_hwtimer_write; | ||||
|     device->control     = rt_hwtimer_control; | ||||
| #endif | ||||
|     device->user_data   = user_data; | ||||
|  | ||||
|     return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user