diff options
Diffstat (limited to 'bsps/arm/imxrt/mcux-sdk/drivers/kpp')
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.c | 203 | ||||
-rw-r--r-- | bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.h | 180 |
2 files changed, 383 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.c b/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.c new file mode 100644 index 0000000000..8c0b1958be --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.c @@ -0,0 +1,203 @@ +/* + * Copyright 2017, 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_kpp.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.kpp" +#endif + +#define KPP_KEYPAD_SCAN_TIMES (3U) +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to SEMC clocks for each instance. */ +static const clock_ip_name_t s_kppClock[FSL_FEATURE_SOC_KPP_COUNT] = KPP_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointers to SEMC bases for each instance. */ +static KPP_Type *const s_kppBases[] = KPP_BASE_PTRS; + +/*! @brief Pointers to KPP IRQ number for each instance. */ +static const IRQn_Type s_kppIrqs[] = KPP_IRQS; +/******************************************************************************* + * Code + ******************************************************************************/ +static uint32_t KPP_GetInstance(KPP_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_kppBases); instance++) + { + if (s_kppBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_kppBases)); + + return instance; +} +static void KPP_Mdelay(uint64_t tickets) +{ + while ((tickets--) != 0UL) + { + __NOP(); + } +} + +/*! + * brief KPP initialize. + * This function ungates the KPP clock and initializes KPP. + * This function must be called before calling any other KPP driver functions. + * + * param base KPP peripheral base address. + * param configure The KPP configuration structure pointer. + */ +void KPP_Init(KPP_Type *base, kpp_config_t *configure) +{ + assert(configure); + + uint32_t instance = KPP_GetInstance(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Un-gate sdram controller clock. */ + CLOCK_EnableClock(s_kppClock[KPP_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Clear all. */ + base->KPSR &= (uint16_t)(~(KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK)); + + /* Enable the keypad row and set the column strobe output to open drain. */ + base->KPCR = KPP_KPCR_KRE(configure->activeRow); + base->KPDR = KPP_KPDR_KCD((uint8_t) ~(configure->activeColumn)); + base->KPCR |= KPP_KPCR_KCO(configure->activeColumn); + + /* Set the input direction for row and output direction for column. */ + base->KDDR = KPP_KDDR_KCDD(configure->activeColumn) | KPP_KDDR_KRDD((uint8_t) ~(configure->activeRow)); + + /* Clear the status flag and enable the interrupt. */ + base->KPSR = KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK | KPP_KPSR_KDSC_MASK | configure->interrupt; + + if ((configure->interrupt) != 0U) + { + /* Enable at the Interrupt */ + (void)EnableIRQ(s_kppIrqs[instance]); + } +} + +/*! + * brief Deinitializes the KPP module and gates the clock. + * This function gates the KPP clock. As a result, the KPP + * module doesn't work after calling this function. + * + * param base KPP peripheral base address. + */ +void KPP_Deinit(KPP_Type *base) +{ + /* Disable interrupts and disable all rows. */ + base->KPSR &= (uint16_t)(~(KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK)); + base->KPCR = 0; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disable KPP clock. */ + CLOCK_DisableClock(s_kppClock[KPP_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Keypad press scanning. + * + * This function will scanning all columns and rows. so + * all scanning data will be stored in the data pointer. + * + * param base KPP peripheral base address. + * param data KPP key press scanning data. The data buffer should be prepared with + * length at least equal to KPP_KEYPAD_COLUMNNUM_MAX * KPP_KEYPAD_ROWNUM_MAX. + * the data pointer is recommended to be a array like uint8_t data[KPP_KEYPAD_COLUMNNUM_MAX]. + * for example the data[2] = 4, that means in column 1 row 2 has a key press event. + * param clockSrc_Hz Source clock. + */ +void KPP_keyPressScanning(KPP_Type *base, uint8_t *data, uint32_t clockSrc_Hz) +{ + assert(data); + + uint16_t kppKCO = base->KPCR & KPP_KPCR_KCO_MASK; + uint8_t columIndex = 0; + uint8_t activeColumn = (uint8_t)((base->KPCR & KPP_KPCR_KCO_MASK) >> KPP_KPCR_KCO_SHIFT); + uint8_t times; + uint8_t rowData[KPP_KEYPAD_SCAN_TIMES][KPP_KEYPAD_COLUMNNUM_MAX]; + bool press = false; + uint8_t column; + + /* Initialize row data to zero. */ + (void)memset(&rowData[0][0], 0, sizeof(rowData)); + + /* Scanning. */ + /* Configure the column data to 1 according to column numbers. */ + base->KPDR = KPP_KPDR_KCD_MASK; + /* Configure column to totem pole for quick discharge of keypad capacitance. */ + base->KPCR &= (uint16_t)(((uint16_t)~kppKCO) | KPP_KPCR_KRE_MASK); + /* Recover. */ + base->KPCR |= kppKCO; + /* Three times scanning. */ + for (times = 0; times < KPP_KEYPAD_SCAN_TIMES; times++) + { + for (columIndex = 0; columIndex < KPP_KEYPAD_COLUMNNUM_MAX; columIndex++) + { + column = activeColumn & (1U << columIndex); + if (column != 0U) + { + /* Set the single column line to 0. */ + base->KPDR = KPP_KPDR_KCD(~(uint16_t)column); + /* Take 100us delays. */ + KPP_Mdelay(((uint64_t)clockSrc_Hz / 10000000UL)); + /* Read row data. */ + rowData[times][columIndex] = (uint8_t)(~(base->KPDR & KPP_KPDR_KRD_MASK)); + } + else + { + /* Read row data. */ + rowData[times][columIndex] = 0; + } + } + } + + /* Return all columns to 0 in preparation for standby mode. */ + base->KPDR &= (uint16_t)(~KPP_KPDR_KCD_MASK); + + /* Check if three time scan data is the same. */ + for (columIndex = 0; columIndex < KPP_KEYPAD_COLUMNNUM_MAX; columIndex++) + { + if (((uint8_t)(rowData[0][columIndex] & rowData[1][columIndex]) & rowData[2][columIndex]) != 0U) + { + press = true; + } + } + + if (press) + { + (void)memcpy(data, &rowData[0][0], sizeof(rowData[0])); + } + else + { + (void)memset(data, 0, sizeof(rowData[0])); + } +} diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.h b/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.h new file mode 100644 index 0000000000..dc65aaf8d7 --- /dev/null +++ b/bsps/arm/imxrt/mcux-sdk/drivers/kpp/fsl_kpp.h @@ -0,0 +1,180 @@ +/* + * Copyright 2017, 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_KPP_H_ +#define _FSL_KPP_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup kpp + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief KPP driver version 2.0.0. */ +#define FSL_KPP_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) +/*@}*/ + +#define KPP_KEYPAD_COLUMNNUM_MAX (8U) +#define KPP_KEYPAD_ROWNUM_MAX (8U) + +/*! @brief List of interrupts supported by the peripheral. This + * enumeration uses one-bot encoding to allow a logical OR of multiple + * members. Members usually map to interrupt enable bits in one or more + * peripheral registers. + */ +typedef enum _kpp_interrupt_enable +{ + kKPP_keyDepressInterrupt = KPP_KPSR_KDIE_MASK, /*!< Keypad depress interrupt source */ + kKPP_keyReleaseInterrupt = KPP_KPSR_KRIE_MASK /*!< Keypad release interrupt source */ +} kpp_interrupt_enable_t; + +/*! @brief Lists of KPP synchronize chain operation. */ +typedef enum _kpp_sync_operation +{ + kKPP_ClearKeyDepressSyncChain = KPP_KPSR_KDSC_MASK, /*!< Keypad depress interrupt status. */ + kKPP_SetKeyReleasesSyncChain = KPP_KPSR_KRSS_MASK, /*!< Keypad release interrupt status. */ +} kpp_sync_operation_t; + +/*! @brief Lists of KPP status. */ +typedef struct _kpp_config +{ + uint8_t activeRow; /*!< The row number: bit 7 ~ 0 represents the row 7 ~ 0. */ + uint8_t activeColumn; /*!< The column number: bit 7 ~ 0 represents the column 7 ~ 0. */ + uint16_t interrupt; /*!< KPP interrupt source. A logical OR of "kpp_interrupt_enable_t". */ +} kpp_config_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Initialization and De-initialization + * @{ + */ + +/*! + * @brief KPP initialize. + * This function ungates the KPP clock and initializes KPP. + * This function must be called before calling any other KPP driver functions. + * + * @param base KPP peripheral base address. + * @param configure The KPP configuration structure pointer. + */ +void KPP_Init(KPP_Type *base, kpp_config_t *configure); + +/*! + * @brief Deinitializes the KPP module and gates the clock. + * This function gates the KPP clock. As a result, the KPP + * module doesn't work after calling this function. + * + * @param base KPP peripheral base address. + */ +void KPP_Deinit(KPP_Type *base); + +/* @} */ + +/*! + * @name KPP Basic Operation + * @{ + */ + +/*! + * @brief Enable the interrupt. + * + * @param base KPP peripheral base address. + * @param mask KPP interrupts to enable. This is a logical OR of the + * enumeration :: kpp_interrupt_enable_t. + */ +static inline void KPP_EnableInterrupts(KPP_Type *base, uint16_t mask) +{ + uint16_t data = (uint16_t)(base->KPSR & ~(KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK)); + base->KPSR = data | mask; +} + +/*! + * @brief Disable the interrupt. + * + * @param base KPP peripheral base address. + * @param mask KPP interrupts to disable. This is a logical OR of the + * enumeration :: kpp_interrupt_enable_t. + */ +static inline void KPP_DisableInterrupts(KPP_Type *base, uint16_t mask) +{ + base->KPSR &= ~(mask | KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK); +} + +/*! + * @brief Gets the KPP interrupt event status. + * + * @param base KPP peripheral base address. + * @return The status of the KPP. Application can use the enum type in the "kpp_interrupt_enable_t" + * to get the right status of the related event. + */ +static inline uint16_t KPP_GetStatusFlag(KPP_Type *base) +{ + return (base->KPSR & (KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK)) << KPP_KPSR_KDIE_SHIFT; +} + +/*! + * @brief Clears KPP status flag. + * + * @param base KPP peripheral base address. + * @param mask KPP mask to be cleared. This is a logical OR of the + * enumeration :: kpp_interrupt_enable_t. + */ +static inline void KPP_ClearStatusFlag(KPP_Type *base, uint16_t mask) +{ + base->KPSR |= (uint16_t)((mask) >> KPP_KPSR_KDIE_SHIFT); +} + +/*! + * @brief Set KPP synchronization chain. + * + * @param base KPP peripheral base address. + * @param mask KPP mask to be cleared. This is a logical OR of the + * enumeration :: kpp_sync_operation_t. + */ +static inline void KPP_SetSynchronizeChain(KPP_Type *base, uint16_t mask) +{ + uint16_t data = base->KPSR & (KPP_KPSR_KRSS_MASK | KPP_KPSR_KDSC_MASK | KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK); + base->KPSR = data | mask; +} + +/*! + * @brief Keypad press scanning. + * + * This function will scanning all columns and rows. so + * all scanning data will be stored in the data pointer. + * + * @param base KPP peripheral base address. + * @param data KPP key press scanning data. The data buffer should be prepared with + * length at least equal to KPP_KEYPAD_COLUMNNUM_MAX * KPP_KEYPAD_ROWNUM_MAX. + * the data pointer is recommended to be a array like uint8_t data[KPP_KEYPAD_COLUMNNUM_MAX]. + * for example the data[2] = 4, that means in column 1 row 2 has a key press event. + * @param clockSrc_Hz Source clock. + */ +void KPP_keyPressScanning(KPP_Type *base, uint8_t *data, uint32_t clockSrc_Hz); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_KPP_H_*/ |