mbed library sources. Supersedes mbed-src.
Fork of mbed-dev by
Diff: targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0P/drivers/system/pinmux/pinmux.c
- Revision:
- 15:a81a8d6c1dfe
diff -r d797fbdad187 -r a81a8d6c1dfe targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0P/drivers/system/pinmux/pinmux.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0P/drivers/system/pinmux/pinmux.c Wed Nov 04 16:30:11 2015 +0000 @@ -0,0 +1,311 @@ +/** + * \file + * + * \brief SAM Pin Multiplexer Driver + * + * Copyright (C) 2012-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 <pinmux.h> + +/** + * \internal + * Writes out a given configuration of a Port pin configuration to the + * hardware module. + * + * \note If the pin direction is set as an output, the pull-up/pull-down input + * configuration setting is ignored. + * + * \param[in] port Base of the PORT module to configure + * \param[in] pin_mask Mask of the port pin to configure + * \param[in] config Configuration settings for the pin + */ +static void _system_pinmux_config( + PortGroup *const port, + const uint32_t pin_mask, + const struct system_pinmux_config *const config) +{ + Assert(port); + Assert(config); + + /* Track the configuration bits into a temporary variable before writing */ + uint32_t pin_cfg = 0; + + /* Enabled powersave mode, don't create configuration */ + if (!config->powersave) { + /* Enable the pin peripheral MUX flag if non-GPIO selected (pinmux will + * be written later) and store the new MUX mask */ + if (config->mux_position != SYSTEM_PINMUX_GPIO) { + pin_cfg |= PORT_WRCONFIG_PMUXEN; + pin_cfg |= (config->mux_position << PORT_WRCONFIG_PMUX_Pos); + } + + /* Check if the user has requested that the input buffer be enabled */ + if ((config->direction == SYSTEM_PINMUX_PIN_DIR_INPUT) || + (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) { + /* Enable input buffer flag */ + pin_cfg |= PORT_WRCONFIG_INEN; + + /* Enable pull-up/pull-down control flag if requested */ + if (config->input_pull != SYSTEM_PINMUX_PIN_PULL_NONE) { + pin_cfg |= PORT_WRCONFIG_PULLEN; + } + + /* Clear the port DIR bits to disable the output buffer */ + port->DIRCLR.reg = pin_mask; + } + + /* Check if the user has requested that the output buffer be enabled */ + if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) || + (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) { + /* Cannot use a pull-up if the output driver is enabled, + * if requested the input buffer can only sample the current + * output state */ + pin_cfg &= ~PORT_WRCONFIG_PULLEN; + } + } else { + port->DIRCLR.reg = pin_mask; + } + + /* The Write Configuration register (WRCONFIG) requires the + * pins to to grouped into two 16-bit half-words - split them out here */ + uint32_t lower_pin_mask = (pin_mask & 0xFFFF); + uint32_t upper_pin_mask = (pin_mask >> 16); + + /* Configure the lower 16-bits of the port to the desired configuration, + * including the pin peripheral multiplexer just in case it is enabled */ + port->WRCONFIG.reg + = (lower_pin_mask << PORT_WRCONFIG_PINMASK_Pos) | + pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG; + + /* Configure the upper 16-bits of the port to the desired configuration, + * including the pin peripheral multiplexer just in case it is enabled */ + port->WRCONFIG.reg + = (upper_pin_mask << PORT_WRCONFIG_PINMASK_Pos) | + pin_cfg | PORT_WRCONFIG_WRPMUX | PORT_WRCONFIG_WRPINCFG | + PORT_WRCONFIG_HWSEL; + + if(!config->powersave) { + /* Set the pull-up state once the port pins are configured if one was + * requested and it does not violate the valid set of port + * configurations */ + if (pin_cfg & PORT_WRCONFIG_PULLEN) { + /* Set the OUT register bits to enable the pull-up if requested, + * clear to enable pull-down */ + if (config->input_pull == SYSTEM_PINMUX_PIN_PULL_UP) { + port->OUTSET.reg = pin_mask; + } else { + port->OUTCLR.reg = pin_mask; + } + } + + /* Check if the user has requested that the output buffer be enabled */ + if ((config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT) || + (config->direction == SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK)) { + /* Set the port DIR bits to enable the output buffer */ + port->DIRSET.reg = pin_mask; + } + } +} + +/** + * \brief Writes a Port pin configuration to the hardware module. + * + * Writes out a given configuration of a Port pin configuration to the hardware + * module. + * + * \note If the pin direction is set as an output, the pull-up/pull-down input + * configuration setting is ignored. + * + * \param[in] gpio_pin Index of the GPIO pin to configure + * \param[in] config Configuration settings for the pin + */ +void system_pinmux_pin_set_config( + const uint8_t gpio_pin, + const struct system_pinmux_config *const config) +{ + PortGroup *const port = system_pinmux_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_mask = (1UL << (gpio_pin % 32)); + + _system_pinmux_config(port, pin_mask, config); +} + +/** + * \brief Writes a Port pin group configuration to the hardware module. + * + * Writes out a given configuration of a Port pin group configuration to the + * hardware module. + * + * \note If the pin direction is set as an output, the pull-up/pull-down input + * configuration setting is ignored. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] config Configuration settings for the pin + */ +void system_pinmux_group_set_config( + PortGroup *const port, + const uint32_t mask, + const struct system_pinmux_config *const config) +{ + Assert(port); + + for (int i = 0; i < 32; i++) { + if (mask & (1UL << i)) { + _system_pinmux_config(port, (1UL << i), config); + } + } +} + +/** + * \brief Configures the input sampling mode for a group of pins. + * + * Configures the input sampling mode for a group of pins, to + * control when the physical I/O pin value is sampled and + * stored inside the microcontroller. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] mode New pin sampling mode to configure + */ +void system_pinmux_group_set_input_sample_mode( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_sample mode) +{ + Assert(port); + + if (mode == SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND) { + port->CTRL.reg |= mask; + } else { + port->CTRL.reg &= ~mask; + } +} + +#ifdef FEATURE_SYSTEM_PINMUX_SLEWRATE_LIMITER +/** + * \brief Configures the output slew rate mode for a group of pins. + * + * Configures the output slew rate mode for a group of pins, to + * control the speed at which the physical output pin can react to + * logical changes of the I/O pin value. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] mode New pin slew rate mode to configure + */ +void system_pinmux_group_set_output_slew_rate( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_slew_rate mode) +{ + Assert(port); + + for (int i = 0; i < 32; i++) { + if (mask & (1UL << i)) { + if (mode == SYSTEM_PINMUX_PIN_SLEW_RATE_LIMITED) { + port->PINCFG[i].reg |= PORT_PINCFG_SLEWLIM; + } else { + port->PINCFG[i].reg &= ~PORT_PINCFG_SLEWLIM; + } + } + } +} +#endif + +#ifdef FEATURE_SYSTEM_PINMUX_DRIVE_STRENGTH +/** + * \brief Configures the output driver strength mode for a group of pins. + * + * Configures the output drive strength for a group of pins, to + * control the amount of current the pad is able to sink/source. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] mode New output driver strength mode to configure + */ +void system_pinmux_group_set_output_strength( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_strength mode) +{ + Assert(port); + + for (int i = 0; i < 32; i++) { + if (mask & (1UL << i)) { + if (mode == SYSTEM_PINMUX_PIN_STRENGTH_HIGH) { + port->PINCFG[i].reg |= PORT_PINCFG_DRVSTR; + } else { + port->PINCFG[i].reg &= ~PORT_PINCFG_DRVSTR; + } + } + } +} +#endif + +#ifdef FEATURE_SYSTEM_PINMUX_OPEN_DRAIN +/** + * \brief Configures the output driver mode for a group of pins. + * + * Configures the output driver mode for a group of pins, to + * control the pad behavior. + * + * \param[in] port Base of the PORT module to configure + * \param[in] mask Mask of the port pin(s) to configure + * \param[in] mode New pad output driver mode to configure + */ +void system_pinmux_group_set_output_drive( + PortGroup *const port, + const uint32_t mask, + const enum system_pinmux_pin_drive mode) +{ + Assert(port); + + for (int i = 0; i < 32; i++) { + if (mask & (1UL << i)) { + if (mode == SYSTEM_PINMUX_PIN_DRIVE_OPEN_DRAIN) { + port->PINCFG[i].reg |= PORT_PINCFG_ODRAIN; + } else { + port->PINCFG[i].reg &= ~PORT_PINCFG_ODRAIN; + } + } + } +} +#endif