t
Fork of mbed-dev by
Diff: targets/hal/TARGET_Atmel/TARGET_SAM_CortexM4/drivers/tc/tc.c
- Revision:
- 107:414e9c822e99
diff -r c405d2eb506d -r 414e9c822e99 targets/hal/TARGET_Atmel/TARGET_SAM_CortexM4/drivers/tc/tc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_Atmel/TARGET_SAM_CortexM4/drivers/tc/tc.c Tue Apr 05 18:15:12 2016 +0100 @@ -0,0 +1,777 @@ +/** + * \file + * + * \brief SAM Timer Counter (TC) driver. + * + * Copyright (c) 2011-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> + */ + +#include <assert.h> +#include "tc.h" + +/// @cond +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +#ifndef TC_WPMR_WPKEY_PASSWD +#define TC_WPMR_WPKEY_PASSWD TC_WPMR_WPKEY((uint32_t)0x54494D) +#endif + + /** + * \brief Configure TC for timer, waveform generation, or capture. + * + * \param[in,out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to configure + * \param[in] ul_mode Control mode register bitmask value to set + * + * \note For more information regarding <i>ul_mode</i> configuration refer to + * the section entitled "Channel Mode Register: Capture Mode" and/or section + * "Waveform Operating Mode" in the device-specific datasheet. + * + * \note If the TC is configured for waveform generation then the external event + * selection (EEVT) should only be set to TC_CMR_EEVT_TIOB, or the + * equivalent value of 0, if it really is the intention to use TIOB as an + * external event trigger. This is because this setting forces TIOB to be + * an input, even if the external event trigger has not been enabled with + * TC_CMR_ENETRG, and thus prevents normal operation of TIOB. + */ + void tc_init( + Tc *p_tc, + uint32_t ul_channel, + uint32_t ul_mode) +{ + TcChannel *tc_channel; + + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + tc_channel = p_tc->TC_CHANNEL + ul_channel; + + /* Disable TC clock. */ + tc_channel->TC_CCR = TC_CCR_CLKDIS; + + /* Disable interrupts. */ + tc_channel->TC_IDR = 0xFFFFFFFF; + + /* Clear status register. */ + tc_channel->TC_SR; + + /* Set mode. */ + tc_channel->TC_CMR = ul_mode; +} + +/** + * \brief Asserts a SYNC signal to generate a software trigger on + * all channels. + * + * \param[out] p_tc Module hardware register base address pointer + * + */ +void tc_sync_trigger( + Tc *p_tc) +{ + /* Validate inputs. */ + Assert(p_tc); + + p_tc->TC_BCR = TC_BCR_SYNC; +} + +/** + * \brief Configure the TC Block mode. + * + * \note The function tc_init() must be called prior to this one. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_blockmode Block mode register value to set + * + * \note For more information regarding <i>ul_blockmode</i> configuration refer to + * the section entitled "TC Block Mode Register" in the device-specific datasheet. + */ +void tc_set_block_mode( + Tc *p_tc, + uint32_t ul_blockmode) +{ + /* Validate inputs. */ + Assert(p_tc); + + p_tc->TC_BMR = ul_blockmode; +} + +#if (!SAM3U) || defined(__DOXYGEN__) + +/** + * \brief Configure TC for 2-bit Gray Counter for Stepper Motor. + * \note The function tc_init() must be called prior to this one. + * + * \note This function is not available on SAM3U devices. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to configure + * \param[in] ul_steppermode Stepper motor mode register value to set + * + * \return 0 for OK. + */ +uint32_t tc_init_2bit_gray( + Tc *p_tc, + uint32_t ul_channel, + uint32_t ul_steppermode) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + p_tc->TC_CHANNEL[ul_channel].TC_SMMR = ul_steppermode; + return 0; +} + +#endif /* (!SAM3U) || defined(__DOXYGEN__) */ + +/** + * \brief Start the TC clock on the specified channel. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to configure + */ +void tc_start( + Tc *p_tc, + uint32_t ul_channel) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + p_tc->TC_CHANNEL[ul_channel].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; +} + +/** + * \brief Stop the TC clock on the specified channel. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to configure + */ +void tc_stop( + Tc *p_tc, + uint32_t ul_channel) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + p_tc->TC_CHANNEL[ul_channel].TC_CCR = TC_CCR_CLKDIS; +} + +/** + * \brief Read the counter value on the specified channel. + * + * \param[in] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to read + * + * \return The counter value. + */ +uint32_t tc_read_cv( + Tc *p_tc, + uint32_t ul_channel) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + return p_tc->TC_CHANNEL[ul_channel].TC_CV; +} + +/** + * \brief Read TC Register A (RA) on the specified channel. + * + * \param[in] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to read + * + * \return The TC Register A (RA) value. + */ +uint32_t tc_read_ra( + Tc *p_tc, + uint32_t ul_channel) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + return p_tc->TC_CHANNEL[ul_channel].TC_RA; +} + +/** + * \brief Read TC Register B (RB) on the specified channel. + * + * \param[in] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to read + * + * \return The TC Register B (RB) value. + */ +uint32_t tc_read_rb( + Tc *p_tc, + uint32_t ul_channel) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + return p_tc->TC_CHANNEL[ul_channel].TC_RB; +} + +/** + * \brief Read TC Register C (RC) on the specified channel. + * + * \param[in] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to read + * + * \return The Register C (RC) value. + */ +uint32_t tc_read_rc( + Tc *p_tc, + uint32_t ul_channel) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + return p_tc->TC_CHANNEL[ul_channel].TC_RC; +} + +/** + * \brief Write to TC Register A (RA) on the specified channel. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to write + * \param[in] ul_value Value to write + */ +void tc_write_ra( + Tc *p_tc, + uint32_t ul_channel, + uint32_t ul_value) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + p_tc->TC_CHANNEL[ul_channel].TC_RA = ul_value; +} + +/** + * \brief Write to TC Register B (RB) on the specified channel. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to write + * \param[in] ul_value Value to write + */ +void tc_write_rb( + Tc *p_tc, + uint32_t ul_channel, + uint32_t ul_value) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + p_tc->TC_CHANNEL[ul_channel].TC_RB = ul_value; +} + +/** + * \brief Write to TC Register C (RC) on the selected channel. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to write + * \param[in] ul_value Value to write + */ +void tc_write_rc( + Tc *p_tc, + uint32_t ul_channel, + uint32_t ul_value) +{ + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + p_tc->TC_CHANNEL[ul_channel].TC_RC = ul_value; +} + +/** + * \brief Enable the TC interrupts on the specified channel. + * + * \param[in,out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to configure + * \param[in] ul_sources Bitmask of interrupt sources + * + * Where the input parameter <i>ul_sources</i> can be one or more of the following: + * <table> + * <tr> + * <th>Parameter Value</th> + * <th>Description</th> + * </tr> + * <tr><td>TC_IER_COVFS</td><td>Enables the Counter Overflow Interrupt</td></tr> + * <tr><td>TC_IER_LOVRS</td><td>Enables the Load Overrun Interrupt</td></tr> + * <tr><td>TC_IER_CPAS</td><td>Enables the RA Compare Interrupt</td></tr> + * <tr><td>TC_IER_CPBS</td><td>Enables the RB Compare Interrupt</td></tr> + * <tr><td>TC_IER_CPCS</td><td>Enables the RC Compare Interrupt</td></tr> + * <tr><td>TC_IER_LDRAS</td><td>Enables the RA Load Interrupt</td></tr> + * <tr><td>TC_IER_LDRBS</td><td>Enables the RB Load Interrupt</td></tr> + * <tr><td>TC_IER_ETRGS</td><td>Enables the External Trigger Interrupt</td></tr> + * </table> + */ +void tc_enable_interrupt( + Tc *p_tc, + uint32_t ul_channel, + uint32_t ul_sources) +{ + TcChannel *tc_channel; + + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + tc_channel = p_tc->TC_CHANNEL + ul_channel; + tc_channel->TC_IER = ul_sources; +} + +/** + * \brief Disable TC interrupts on the specified channel. + * + * \param[in,out] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to configure + * \param[in] ul_sources A bitmask of Interrupt sources + * + * Where the input parameter <i>ul_sources</i> can be one or more of the following: + * <table> + * <tr> + * <th>Parameter Value</th> + * <th>Description</th> + * </tr> + * <tr><td>TC_IDR_COVFS</td><td>Disables the Counter Overflow Interrupt</td></tr> + * <tr><td>TC_IDR_LOVRS</td><td>Disables the Load Overrun Interrupt</td></tr> + * <tr><td>TC_IDR_CPAS</td><td>Disables the RA Compare Interrupt</td></tr> + * <tr><td>TC_IDR_CPBS</td><td>Disables the RB Compare Interrupt</td></tr> + * <tr><td>TC_IDR_CPCS</td><td>Disables the RC Compare Interrupt</td></tr> + * <tr><td>TC_IDR_LDRAS</td><td>Disables the RA Load Interrupt</td></tr> + * <tr><td>TC_IDR_LDRBS</td><td>Disables the RB Load Interrupt</td></tr> + * <tr><td>TC_IDR_ETRGS</td><td>Disables the External Trigger Interrupt</td></tr> + * </table> + */ +void tc_disable_interrupt( + Tc *p_tc, + uint32_t ul_channel, + uint32_t ul_sources) +{ + TcChannel *tc_channel; + + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + tc_channel = p_tc->TC_CHANNEL + ul_channel; + tc_channel->TC_IDR = ul_sources; +} + +/** + * \brief Read the TC interrupt mask for the specified channel. + * + * \param[in] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel to read + * + * \return The TC interrupt mask value. + */ +uint32_t tc_get_interrupt_mask( + Tc *p_tc, + uint32_t ul_channel) +{ + TcChannel *tc_channel; + + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + tc_channel = p_tc->TC_CHANNEL + ul_channel; + return tc_channel->TC_IMR; +} + +/** + * \brief Get the current status for the specified TC channel. + * + * \param[in] p_tc Module hardware register base address pointer + * \param[in] ul_channel Channel number + * + * \return The current TC status. + */ +uint32_t tc_get_status( + Tc *p_tc, + uint32_t ul_channel) +{ + TcChannel *tc_channel; + + /* Validate inputs. */ + Assert(p_tc); + Assert(ul_channel < + (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0]))); + + tc_channel = p_tc->TC_CHANNEL + ul_channel; + return tc_channel->TC_SR; +} + +/* TC divisor used to find the lowest acceptable timer frequency */ +#define TC_DIV_FACTOR 65536 + +#if (!SAM4L) && !defined(__DOXYGEN__) + +#ifndef FREQ_SLOW_CLOCK_EXT +#define FREQ_SLOW_CLOCK_EXT 32768 /* External slow clock frequency (hz) */ +#endif + +/** + * \brief Find the best MCK divisor. + * + * Finds the best MCK divisor given the timer frequency and MCK. The result + * is guaranteed to satisfy the following equation: + * \code (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) \endcode + * With DIV being the lowest possible value, to maximize timing adjust resolution. + * + * \param[in] ul_freq Desired timer frequency + * \param[in] ul_mck Master clock frequency + * \param[out] p_uldiv Divisor value + * \param[out] p_ultcclks TCCLKS field value for divisor + * \param[in] ul_boardmck Board clock frequency + * + * \return The divisor found status. + * \retval 0 No suitable divisor was found + * \retval 1 A divisor was found + */ +uint32_t tc_find_mck_divisor( + uint32_t ul_freq, + uint32_t ul_mck, + uint32_t *p_uldiv, + uint32_t *p_ultcclks, + uint32_t ul_boardmck) +{ + const uint32_t divisors[5] = { 2, 8, 32, 128, + ul_boardmck / FREQ_SLOW_CLOCK_EXT + }; + uint32_t ul_index; + uint32_t ul_high, ul_low; + + /* Satisfy frequency bound. */ + for (ul_index = 0; + ul_index < (sizeof(divisors) / sizeof(divisors[0])); + ul_index++) { + ul_high = ul_mck / divisors[ul_index]; + ul_low = ul_high / TC_DIV_FACTOR; + if (ul_freq > ul_high) { + return 0; + } else if (ul_freq >= ul_low) { + break; + } + } + if (ul_index >= (sizeof(divisors) / sizeof(divisors[0]))) { + return 0; + } + + /* Store results. */ + if (p_uldiv) { + *p_uldiv = divisors[ul_index]; + } + + if (p_ultcclks) { + *p_ultcclks = ul_index; + } + + return 1; +} + +#endif /* (!SAM4L) */ + +#if (SAM4L) || defined(__DOXYGEN__) +/** + * \brief Find the best PBA/MCK divisor. + * + * <b>For SAM4L devices:</b> Finds the best PBA divisor given the timer + * frequency and PBA clock. The result is guaranteed to satisfy the following equation: + * \code (ul_pbaclk / (2* DIV * 65536)) <= freq <= (ul_pbaclk / (2* DIV)) \endcode + * with DIV being the lowest possible value, to maximize timing adjust resolution. + * + * <b>For non SAM4L devices:</b> Finds the best MCK divisor given the timer frequency + * and MCK. The result is guaranteed to satisfy the following equation: + * \code (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) \endcode + * with DIV being the lowest possible value, to maximize timing adjust resolution. + * + * \param[in] ul_freq Desired timer frequency + * \param[in] ul_mck PBA clock frequency + * \param[out] p_uldiv Divisor value + * \param[out] p_ultcclks TCCLKS field value for divisor + * \param[in] ul_boardmck Board clock frequency (set to 0 for SAM4L devices) + * + * \return The divisor found status. + * \retval 0 No suitable divisor was found + * \retval 1 A divisor was found + */ +uint32_t tc_find_mck_divisor( + uint32_t ul_freq, + uint32_t ul_mck, + uint32_t *p_uldiv, + uint32_t *p_ultcclks, + uint32_t ul_boardmck) +{ + const uint32_t divisors[5] = { 0, 2, 8, 32, 128}; + uint32_t ul_index; + uint32_t ul_high, ul_low; + + UNUSED(ul_boardmck); + + /* Satisfy frequency bound. */ + for (ul_index = 1; + ul_index < (sizeof(divisors) / sizeof(divisors[0])); + ul_index++) { + ul_high = ul_mck / divisors[ul_index]; + ul_low = ul_high / TC_DIV_FACTOR; + if (ul_freq > ul_high) { + return 0; + } else if (ul_freq >= ul_low) { + break; + } + } + if (ul_index >= (sizeof(divisors) / sizeof(divisors[0]))) { + return 0; + } + + /* Store results. */ + if (p_uldiv) { + *p_uldiv = divisors[ul_index]; + } + + if (p_ultcclks) { + *p_ultcclks = ul_index; + } + + return 1; +} + +#endif /* (SAM4L) || defined(__DOXYGEN__) */ + +#if (!SAM4L && !SAMG) || defined(__DOXYGEN__) + +/** + * \brief Enable TC QDEC interrupts. + * + * \note This function is not available on SAM4L or SAMG devices. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_sources A bitmask of QDEC interrupts to be enabled + * + * Where the input parameter <i>ul_sources</i> can be one or more of the following: + * <table> + * <tr> + * <th>Parameter Value</th> + * <th>Description</th> + * </tr> + * <tr><td>TC_QIER_IDX</td><td>Enable the rising edge detected on IDX input interrupt</td></tr> + * <tr><td>TC_QIER_DIRCHG</td><td>Enable the change in rotation direction detected interrupt</td></tr> + * <tr><td>TC_QIER_QERR</td><td>Enable the quadrature error detected on PHA/PHB interrupt</td></tr> + * </table> + */ +void tc_enable_qdec_interrupt( + Tc *p_tc, + uint32_t ul_sources) +{ + /* Validate inputs. */ + Assert(p_tc); + + p_tc->TC_QIER = ul_sources; +} + +/** + * \brief Disable TC QDEC interrupts. + * + * \note This function is not available on SAM4L or SAMG devices. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_sources A bitmask of QDEC interrupts to be disabled + * + * Where the input parameter <i>ul_sources</i> can be one or more of the following: + * <table> + * <tr> + * <th>Parameter Value</th> + * <th>Description</th> + * </tr> + * <tr><td>TC_QIDR_IDX</td><td>Disable the rising edge detected on IDX input interrupt</td></tr> + * <tr><td>TC_QIDR_DIRCHG</td><td>Disable the change in rotation direction detected interrupt</td></tr> + * <tr><td>TC_QIDR_QERR</td><td>Disable the quadrature error detected on PHA/PHB interrupt</td></tr> + * </table> + */ +void tc_disable_qdec_interrupt( + Tc *p_tc, + uint32_t ul_sources) +{ + /* Validate inputs. */ + Assert(p_tc); + + p_tc->TC_QIDR = ul_sources; +} + +/** + * \brief Read TC QDEC interrupt mask. + * + * \note This function is not available on SAM4L or SAMG devices. + * + * \param[in] p_tc Module hardware register base address pointer + * + * \return The QDEC interrupt mask value. + */ +uint32_t tc_get_qdec_interrupt_mask( + Tc *p_tc) +{ + /* Validate inputs. */ + Assert(p_tc); + + return p_tc->TC_QIMR; +} + +/** + * \brief Get current TC QDEC interrupt status. + * + * \note This function is not available on SAM4L or SAMG devices. + * + * \param[in] p_tc Module hardware register base address pointer + * + * \return The TC QDEC interrupt status. + */ +uint32_t tc_get_qdec_interrupt_status( + Tc *p_tc) +{ + /* Validate inputs. */ + Assert(p_tc); + + return p_tc->TC_QISR; +} + +#endif /* (!SAM4L && !SAMG) || defined(__DOXYGEN__) */ + +#if (!SAM3U) || defined(__DOXYGEN__) + +/** + * \brief Enable or disable write protection of TC registers. + * + * \note This function is not available on SAM3U devices. + * + * \param[out] p_tc Module hardware register base address pointer + * \param[in] ul_enable 1 to enable, 0 to disable + */ +void tc_set_writeprotect( + Tc *p_tc, + uint32_t ul_enable) +{ + /* Validate inputs. */ + Assert(p_tc); + + if (ul_enable) { + p_tc->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN; + } else { + p_tc->TC_WPMR = TC_WPMR_WPKEY_PASSWD; + } +} + +#endif /* (!SAM3U) || defined(__DOXYGEN__) */ + +#if SAM4L || defined(__DOXYGEN__) + +/** + * \brief Indicate TC features. + * + * \note This function is only available on SAM4L devices. + * + * \param[in] p_tc Module hardware register base address pointer + * + * \return The TC FEATURES register contents. + */ +uint32_t tc_get_feature( + Tc *p_tc) +{ + /* Validate inputs. */ + Assert(p_tc); + + return p_tc->TC_FEATURES; +} + +/** + * \brief Indicate TC version. + * + * \note This function is only available on SAM4L devices. + * + * \param[in] p_tc Module hardware register base address pointer + * + * \return The TC VERSION register contents. + */ +uint32_t tc_get_version( + Tc *p_tc) +{ + /* Validate inputs. */ + Assert(p_tc); + + return p_tc->TC_VERSION; +} + +#endif /* SAM4L || defined(__DOXYGEN__) */ + +/// @cond +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond