rt-thread/bsp/imx6ul/platform/drivers/gpt.c

240 lines
6.8 KiB
C

/*
* Copyright (c) 2011-2012, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*!
* @file gpt.c
* @brief GPT driver source file.
*
* @ingroup diag_timer
*/
#include "sdk.h"
#include "gpt.h"
#include "imx_timer.h"
#include "registers/regsgpt.h"
#include "interrupt.h"
#include "ccm_pll.h"
////////////////////////////////////////////////////////////////////////////////
// Code
////////////////////////////////////////////////////////////////////////////////
static inline void gpt_clear_all_events(void)
{
HW_GPT_SR_WR(kGPTAllEvents);
}
uint32_t gpt_get_rollover_event(void)
{
// clear it if found set
if (HW_GPT_SR.B.ROV)
{
HW_GPT_SR_WR(BM_GPT_SR_ROV);
return kGPTRollover;
}
// return the read value before the bit was cleared
return 0;
}
uint32_t gpt_get_capture_event(uint8_t flag, uint32_t * capture_val)
{
// get the capture status bit
flag &= kGPTInputCapture1 | kGPTInputCapture2;
uint32_t status_register = HW_GPT_SR_RD() & flag;
// Read the captured timer value.
if (capture_val)
{
if (status_register == kGPTInputCapture1)
{
*(uint32_t *) capture_val = HW_GPT_ICR1.B.CAPT;
}
else if (status_register == kGPTInputCapture2)
{
*(uint32_t *) capture_val = HW_GPT_ICR2.B.CAPT;
}
}
// Clear the flag.
HW_GPT_SR_WR(status_register);
// return the read value before the bit was cleared
return status_register;
}
void gpt_set_capture_event(uint8_t cap_input, uint8_t cap_input_mode)
{
// set the new input mode
switch (cap_input)
{
case kGPTInputCapture1:
HW_GPT_CR.B.IM1 = cap_input_mode;
break;
case kGPTInputCapture2:
HW_GPT_CR.B.IM2 = cap_input_mode;
break;
}
}
uint32_t gpt_get_compare_event(uint8_t flag)
{
// get the active compare flags
flag &= kGPTOutputCompare1 | kGPTOutputCompare2 | kGPTOutputCompare3;
uint32_t status_register = HW_GPT_SR_RD() & flag;
// clear flags which are active
if (status_register)
{
HW_GPT_SR_WR(status_register);
}
// return the read value before the flags were cleared
return status_register;
}
void gpt_set_compare_event(uint8_t cmp_output, uint8_t cmp_output_mode, uint32_t cmp_value)
{
// set the value to compare with
switch (cmp_output)
{
case kGPTOutputCompare1:
BW_GPT_CR_OM1(cmp_output_mode);
HW_GPT_OCR1_WR(cmp_value);
break;
case kGPTOutputCompare2:
BW_GPT_CR_OM2(cmp_output_mode);
HW_GPT_OCR2_WR(cmp_value);
break;
case kGPTOutputCompare3:
BW_GPT_CR_OM3(cmp_output_mode);
HW_GPT_OCR3_WR(cmp_value);
break;
}
}
void gpt_counter_disable(void)
{
// disable the counter
HW_GPT_CR.B.EN = 0;
// ensure to leave the counter in a proper state by disabling the interrupt sources
HW_GPT_IR_WR(0);
// and by clearing possible remaining events
gpt_clear_all_events();
}
void gpt_counter_enable(uint32_t irq_mode)
{
// ensure to start the counter in a proper state by clearing possible remaining events
gpt_clear_all_events();
// enable the interrupts or clear the register for polling
HW_GPT_IR_WR(irq_mode & kGPTAllEvents);
// finally, enable the counter
HW_GPT_CR.B.EN = 1;
}
void gpt_setup_interrupt(void (*irq_subroutine)(void), bool enableIt)
{
uint32_t irq_id = IMX_INT_GPT;
if (enableIt)
{
// register the IRQ sub-routine
register_interrupt_routine(irq_id, irq_subroutine);
// enable the IRQ
enable_interrupt(irq_id, CPU_0, 0);
}
else
{
// disable the IRQ
disable_interrupt(irq_id, CPU_0);
}
}
void gpt_init(uint32_t clock_src, uint32_t prescaler, uint32_t counter_mode, uint32_t low_power_mode)
{
uint32_t control_reg_tmp = 0;
uint32_t base = GPT_BASE_ADDR;
// enable the source clocks to the GPT port
clock_gating_config(base, CLOCK_ON);
// start with a known state by disabling and reseting the module
HW_GPT_CR_WR(BM_GPT_CR_SWR);
// wait for the reset to complete
while (HW_GPT_CR.B.SWR != 0) ;
// set the reference source clock for the counter
if (clock_src == CLKSRC_CKIL)
{
// CKIL source is 0x4 for GPT but 0x3 for EPIT
clock_src++;
}
control_reg_tmp |= BF_GPT_CR_CLKSRC(clock_src);
// the prescaler can be changed at any time, and
// this affects the output clock immediately
HW_GPT_PR_WR(BF_GPT_PR_PRESCALER(prescaler - 1));
// set the counter mode
control_reg_tmp |= BF_GPT_CR_FRR(counter_mode);
// set behavior for low power mode
if (low_power_mode & WAIT_MODE_EN)
{
control_reg_tmp |= BM_GPT_CR_WAITEN;
}
if (low_power_mode & STOP_MODE_EN)
{
control_reg_tmp |= BM_GPT_CR_STOPEN;
}
// specify from where the counter starts to count when enabled
// this code makes it start from 0
control_reg_tmp |= BM_GPT_CR_ENMOD;
// finally write the control register
HW_GPT_CR_WR(control_reg_tmp);
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////