123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2022-07-15 Emuzit first version
- */
- #include <rthw.h>
- #include <rtdebug.h>
- #include <drivers/hwtimer.h>
- #include "ch56x_sys.h"
- #include "ch56x_timer.h"
- #include "isr_sp.h"
- #if !defined(BSP_USING_TMR0) && !defined(BSP_USING_TMR1) && !defined(BSP_USING_TMR2)
- #error "Please define at least one TMRx"
- #endif
- struct hwtimer_device
- {
- struct rt_hwtimer_device parent;
- struct rt_hwtimer_info hwtimer_info;
- volatile struct timer_registers *reg_base;
- rt_hwtimer_mode_t tmode;
- irq_number_t irqn;
- char *name;
- };
- #ifdef BSP_USING_TMR0
- static struct hwtimer_device hwtimer_device_0 =
- {
- .hwtimer_info =
- {
- .maxfreq = 80000000,
- .minfreq = 80000000,
- .maxcnt = 0x3ffffff,
- .cntmode = HWTIMER_CNTMODE_UP,
- },
- .reg_base = (struct timer_registers *)TMR0_REG_BASE,
- .tmode = HWTIMER_MODE_PERIOD,
- .irqn = TMR0_IRQn,
- .name = "timer0",
- };
- #endif
- #ifdef BSP_USING_TMR1
- static struct hwtimer_device hwtimer_device_1 =
- {
- .hwtimer_info =
- {
- .maxfreq = 80000000,
- .minfreq = 80000000,
- .maxcnt = 0x3ffffff,
- .cntmode = HWTIMER_CNTMODE_UP,
- },
- .reg_base = (struct timer_registers *)TMR1_REG_BASE,
- .tmode = HWTIMER_MODE_PERIOD,
- .irqn = TMR1_IRQn,
- .name = "timer1",
- };
- #endif
- #ifdef BSP_USING_TMR2
- static struct hwtimer_device hwtimer_device_2 =
- {
- .hwtimer_info =
- {
- .maxfreq = 80000000,
- .minfreq = 80000000,
- .maxcnt = 0x3ffffff,
- .cntmode = HWTIMER_CNTMODE_UP,
- },
- .reg_base = (struct timer_registers *)TMR2_REG_BASE,
- .tmode = HWTIMER_MODE_PERIOD,
- .irqn = TMR2_IRQn,
- .name = "timer2",
- };
- #endif
- static void hwtimer_stop(struct rt_hwtimer_device *timer);
- static void hwtimer_init(struct rt_hwtimer_device *timer, uint32_t state)
- {
- struct hwtimer_device *hwtimer_device = (void *)timer;
- RT_ASSERT(hwtimer_device != RT_NULL);
- /* no resource processing, `state` ignored */
- hwtimer_stop(timer);
- if (hwtimer_device->irqn != TMR0_IRQn)
- {
- hwtimer_device->reg_base->CTRL_DMA.reg = 0;
- }
- }
- static rt_err_t hwtimer_start(struct rt_hwtimer_device *timer, uint32_t cnt, rt_hwtimer_mode_t mode)
- {
- struct hwtimer_device *hwtimer_device = (void *)timer;
- volatile struct timer_registers *txreg;
- RT_ASSERT(hwtimer_device != RT_NULL);
- /* hwtimer_device->tmode may be different from timer->mode.
- * For multi-cycle ONESHOT, tmode is set to PERIOD at hwtimer_start.
- */
- hwtimer_device->tmode = mode;
- sys_clk_off_by_irqn(hwtimer_device->irqn, SYS_SLP_CLK_ON);
- txreg = hwtimer_device->reg_base;
- txreg->CNT_END = cnt;
- txreg->CTRL_MOD.reg = RB_TMR_ALL_CLEAR;
- txreg->CTRL_MOD.reg = RB_TMR_COUNT_EN;
- txreg->INTER_EN.cyc_end = 1;
- rt_hw_interrupt_umask(hwtimer_device->irqn);
- return RT_EOK;
- }
- static void hwtimer_stop(struct rt_hwtimer_device *timer)
- {
- struct hwtimer_device *hwtimer_device = (void *)timer;
- volatile struct timer_registers *txreg;
- RT_ASSERT(hwtimer_device != RT_NULL);
- rt_hw_interrupt_mask(hwtimer_device->irqn);
- /* note: RB_TMR_COUNT_EN cleared */
- txreg = hwtimer_device->reg_base;
- txreg->CTRL_MOD.reg = RB_TMR_ALL_CLEAR;
- txreg->INTER_EN.reg = 0;
- sys_clk_off_by_irqn(hwtimer_device->irqn, SYS_SLP_CLK_OFF);
- }
- static uint32_t hwtimer_count_get(struct rt_hwtimer_device *timer)
- {
- struct hwtimer_device *hwtimer_device = (void *)timer;
- RT_ASSERT(hwtimer_device != RT_NULL);
- return hwtimer_device->reg_base->COUNT;
- }
- static rt_err_t hwtimer_control(
- struct rt_hwtimer_device *timer, uint32_t cmd, void *args)
- {
- struct hwtimer_device *hwtimer_device = (void *)timer;
- rt_err_t result = RT_EOK;
- RT_ASSERT(hwtimer_device != RT_NULL);
- switch (cmd)
- {
- case HWTIMER_CTRL_FREQ_SET:
- /* clocking for ch56x timers are fixed to Fsys */
- if (args == RT_NULL || *(uint32_t *)args != timer->info->minfreq)
- {
- result = -RT_EINVAL;
- }
- break;
- case HWTIMER_CTRL_STOP:
- case HWTIMER_CTRL_INFO_GET:
- case HWTIMER_CTRL_MODE_SET:
- default:
- result = -RT_ENOSYS;
- }
- return result;
- }
- static const struct rt_hwtimer_ops hwtimer_ops =
- {
- .init = hwtimer_init,
- .start = hwtimer_start,
- .stop = hwtimer_stop,
- .count_get = hwtimer_count_get,
- .control = hwtimer_control,
- };
- static int rt_hw_hwtimer_init(void)
- {
- struct hwtimer_device *devices[3];
- uint32_t Fsys = sys_hclk_get();
- int n = 0;
- #ifdef BSP_USING_TMR2
- devices[n++] = &hwtimer_device_2;
- #endif
- #ifdef BSP_USING_TMR1
- devices[n++] = &hwtimer_device_1;
- #endif
- #ifdef BSP_USING_TMR0
- devices[n++] = &hwtimer_device_0;
- #endif
- while (--n >= 0)
- {
- struct hwtimer_device *hwtimer_device = devices[n];
- /* counting frequency is fixed to Fsys */
- hwtimer_device->hwtimer_info.maxfreq = Fsys;
- hwtimer_device->hwtimer_info.minfreq = Fsys;
- hwtimer_device->parent.info = &hwtimer_device->hwtimer_info;
- hwtimer_device->parent.ops = &hwtimer_ops;
- rt_device_hwtimer_register(
- &hwtimer_device->parent, hwtimer_device->name, RT_NULL);
- }
- return RT_EOK;
- }
- INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
- static void _hwtimer_isr_common(struct hwtimer_device *hwtimer_device)
- {
- volatile struct timer_registers *txreg = hwtimer_device->reg_base;
- if (txreg->INT_FLAG.cyc_end)
- {
- if (hwtimer_device->tmode == HWTIMER_MODE_ONESHOT)
- {
- /* disable timer to emulate oneshot */
- txreg->CTRL_MOD.reg = 0;
- }
- rt_device_hwtimer_isr(&hwtimer_device->parent);
- txreg->INT_FLAG.cyc_end = 1;
- }
- }
- #ifdef BSP_USING_TMR0
- void tmr0_irq_handler(void) __attribute__((interrupt()));
- void tmr0_irq_handler(void)
- {
- isr_sp_enter();
- rt_interrupt_enter();
- _hwtimer_isr_common(&hwtimer_device_0);
- rt_interrupt_leave();
- isr_sp_leave();
- }
- #endif
- #ifdef BSP_USING_TMR1
- void tmr1_irq_handler(void) __attribute__((interrupt()));
- void tmr1_irq_handler(void)
- {
- isr_sp_enter();
- rt_interrupt_enter();
- _hwtimer_isr_common(&hwtimer_device_1);
- rt_interrupt_leave();
- isr_sp_leave();
- }
- #endif
- #ifdef BSP_USING_TMR2
- void tmr2_irq_handler(void) __attribute__((interrupt()));
- void tmr2_irq_handler(void)
- {
- isr_sp_enter();
- rt_interrupt_enter();
- _hwtimer_isr_common(&hwtimer_device_2);
- rt_interrupt_leave();
- isr_sp_leave();
- }
- #endif
|