arch: Add pmc, gpio internal Atmel SAM drivers
Added common, internal, always available SAM HAL drivers: pmc, gpio. Note: these drivers are meant to be used by other SAM drivers, not by a user space program directly. Tested on Atmel SMART SAM E70 Xplained board Origin: Original Jira: ZEP-978 Change-Id: I00cca358f27790dc94cf79f840584b85ff5191f6 Signed-off-by: Piotr Mienkowski <Piotr.Mienkowski@schmid-telecom.ch>
This commit is contained in:
parent
5e916f1c8a
commit
427996050a
8 changed files with 423 additions and 0 deletions
|
@ -5,3 +5,4 @@
|
|||
#
|
||||
|
||||
obj-y += $(SOC_SERIES)/
|
||||
obj-y += common/
|
||||
|
|
8
arch/arm/soc/atmel_sam/common/Makefile
Normal file
8
arch/arm/soc/atmel_sam/common/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Makefile - Atmel SAM MCU family common functions
|
||||
#
|
||||
# Copyright (c) 2016 Piotr Mienkowski
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
obj-y += soc_pmc.o
|
||||
obj-y += soc_gpio.o
|
173
arch/arm/soc/atmel_sam/common/soc_gpio.c
Normal file
173
arch/arm/soc/atmel_sam/common/soc_gpio.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Piotr Mienkowski
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Atmel SAM MCU family General Purpose Input Output (GPIO)
|
||||
* module HAL driver.
|
||||
*/
|
||||
|
||||
#include <misc/__assert.h>
|
||||
#include "soc_gpio.h"
|
||||
|
||||
static void configure_common_attr(Pio *pio, uint32_t mask, uint32_t flags)
|
||||
{
|
||||
/* Disable interrupts on the pin(s) */
|
||||
pio->PIO_IDR = mask;
|
||||
|
||||
/* Configure pull-up(s) */
|
||||
if (flags & SOC_GPIO_PULLUP) {
|
||||
pio->PIO_PUER = mask;
|
||||
} else {
|
||||
pio->PIO_PUDR = mask;
|
||||
}
|
||||
|
||||
/* Configure pull-down(s) */
|
||||
if (flags & SOC_GPIO_PULLDOWN) {
|
||||
pio->PIO_PPDER = mask;
|
||||
} else {
|
||||
pio->PIO_PPDDR = mask;
|
||||
}
|
||||
|
||||
/* Configure open drain (multi-drive) */
|
||||
if (flags & SOC_GPIO_OPENDRAIN) {
|
||||
pio->PIO_MDER = mask;
|
||||
} else {
|
||||
pio->PIO_MDDR = mask;
|
||||
}
|
||||
}
|
||||
|
||||
static void configure_input_attr(Pio *pio, uint32_t mask, uint32_t flags)
|
||||
{
|
||||
/* Configure input filter */
|
||||
if ((flags & SOC_GPIO_IN_FILTER_MASK) != 0) {
|
||||
if ((flags & SOC_GPIO_IN_FILTER_MASK) == SOC_GPIO_IN_FILTER_DEBOUNCE) {
|
||||
/* Enable de-bounce, disable de-glitch */
|
||||
pio->PIO_IFSCER = mask;
|
||||
} else {
|
||||
/* Disable de-bounce, enable de-glitch */
|
||||
pio->PIO_IFSCDR = mask;
|
||||
}
|
||||
pio->PIO_IFER = mask;
|
||||
} else {
|
||||
pio->PIO_IFDR = mask;
|
||||
}
|
||||
|
||||
/* Configure interrupt */
|
||||
if (flags & SOC_GPIO_INT_ENABLE) {
|
||||
if ((flags & SOC_GPIO_INT_TRIG_MASK) == SOC_GPIO_INT_TRIG_DOUBLE_EDGE) {
|
||||
/* Disable additional interrupt modes, enable the default */
|
||||
pio->PIO_AIMDR = mask;
|
||||
} else {
|
||||
/* Configure additional interrupt mode */
|
||||
if ((flags & SOC_GPIO_INT_TRIG_MASK) == SOC_GPIO_INT_TRIG_EDGE) {
|
||||
/* Select edge detection event */
|
||||
pio->PIO_ESR = mask;
|
||||
} else {
|
||||
/* Select level detection event */
|
||||
pio->PIO_LSR = mask;
|
||||
}
|
||||
|
||||
if (flags & SOC_GPIO_INT_ACTIVE_HIGH) {
|
||||
pio->PIO_REHLSR = mask;
|
||||
} else {
|
||||
pio->PIO_FELLSR = mask;
|
||||
}
|
||||
/* Enable additional interrupt mode */
|
||||
pio->PIO_AIMER = mask;
|
||||
}
|
||||
/* Enable interrupts on the pin(s) */
|
||||
pio->PIO_IER = mask;
|
||||
} else {
|
||||
/* Nothing to do. All interrupts were disabled in the
|
||||
* beginning.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
static void configure_output_attr(Pio *pio, uint32_t mask, uint32_t flags)
|
||||
{
|
||||
/* Enable control of the I/O line by the PIO_ODSR register */
|
||||
pio->PIO_OWER = mask;
|
||||
}
|
||||
|
||||
void soc_gpio_configure(const struct soc_gpio_pin *pin)
|
||||
{
|
||||
uint32_t mask = pin->mask;
|
||||
Pio *pio = pin->regs;
|
||||
uint8_t periph_id = pin->periph_id;
|
||||
uint32_t flags = pin->flags;
|
||||
uint32_t type = pin->flags & SOC_GPIO_FUNC_MASK;
|
||||
|
||||
/* Configure pin attributes common to all functions */
|
||||
configure_common_attr(pio, mask, flags);
|
||||
|
||||
switch (type) {
|
||||
case SOC_GPIO_FUNC_A:
|
||||
pio->PIO_ABCDSR[0] &= ~mask;
|
||||
pio->PIO_ABCDSR[1] &= ~mask;
|
||||
/* Connect pin to the peripheral (disconnect PIO block) */
|
||||
pio->PIO_PDR = mask;
|
||||
break;
|
||||
|
||||
case SOC_GPIO_FUNC_B:
|
||||
pio->PIO_ABCDSR[0] |= mask;
|
||||
pio->PIO_ABCDSR[1] &= ~mask;
|
||||
/* Connect pin to the peripheral (disconnect PIO block) */
|
||||
pio->PIO_PDR = mask;
|
||||
break;
|
||||
|
||||
case SOC_GPIO_FUNC_C:
|
||||
pio->PIO_ABCDSR[0] &= ~mask;
|
||||
pio->PIO_ABCDSR[1] |= mask;
|
||||
/* Connect pin to the peripheral (disconnect PIO block) */
|
||||
pio->PIO_PDR = mask;
|
||||
break;
|
||||
|
||||
case SOC_GPIO_FUNC_D:
|
||||
pio->PIO_ABCDSR[0] |= mask;
|
||||
pio->PIO_ABCDSR[1] |= mask;
|
||||
/* Connect pin to the peripheral (disconnect PIO block) */
|
||||
pio->PIO_PDR = mask;
|
||||
break;
|
||||
|
||||
case SOC_GPIO_FUNC_IN:
|
||||
/* Enable module's clock */
|
||||
soc_pmc_peripheral_enable(periph_id);
|
||||
/* Configure pin attributes related to input function */
|
||||
configure_input_attr(pio, mask, flags);
|
||||
/* Configure pin as input */
|
||||
pio->PIO_ODR = mask;
|
||||
pio->PIO_PER = mask;
|
||||
break;
|
||||
|
||||
case SOC_GPIO_FUNC_OUT_1:
|
||||
case SOC_GPIO_FUNC_OUT_0:
|
||||
/* Set initial pin value */
|
||||
if (type == SOC_GPIO_FUNC_OUT_1) {
|
||||
pio->PIO_SODR = mask;
|
||||
} else {
|
||||
pio->PIO_CODR = mask;
|
||||
}
|
||||
|
||||
/* Configure pin attributes related to output function */
|
||||
configure_output_attr(pio, mask, flags);
|
||||
/* Configure pin(s) as output(s) */
|
||||
pio->PIO_OER = mask;
|
||||
pio->PIO_PER = mask;
|
||||
break;
|
||||
|
||||
default:
|
||||
__ASSERT(0, "Unsupported pin function, check pin.flags value");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void soc_gpio_list_configure(const struct soc_gpio_pin pins[],
|
||||
unsigned int size)
|
||||
{
|
||||
for (int i = 0; i < size; i++) {
|
||||
soc_gpio_configure(&pins[i]);
|
||||
}
|
||||
}
|
142
arch/arm/soc/atmel_sam/common/soc_gpio.h
Normal file
142
arch/arm/soc/atmel_sam/common/soc_gpio.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Piotr Mienkowski
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Atmel SAM MCU family General Purpose Input Output (GPIO)
|
||||
* module HAL driver.
|
||||
*/
|
||||
|
||||
#ifndef _ATMEL_SAM_SOC_GPIO_H_
|
||||
#define _ATMEL_SAM_SOC_GPIO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <soc.h>
|
||||
#include <gpio.h>
|
||||
|
||||
/*
|
||||
* Pin flags/attributes
|
||||
*/
|
||||
|
||||
/* TODO: replace hard coded pin attribute values with defines provided
|
||||
* in gpio.h, once the official API is clean.
|
||||
*/
|
||||
|
||||
#define SOC_GPIO_DEFAULT (0)
|
||||
|
||||
#define SOC_GPIO_PULLUP (1 << 0)
|
||||
#define SOC_GPIO_PULLDOWN (1 << 1)
|
||||
#define SOC_GPIO_OPENDRAIN (1 << 2)
|
||||
|
||||
/* Bit field: SOC_GPIO_IN_FILTER */
|
||||
#define SOC_GPIO_IN_FILTER_POS 3
|
||||
#define SOC_GPIO_IN_FILTER_MASK (3 << SOC_GPIO_IN_FILTER_POS)
|
||||
#define SOC_GPIO_IN_FILTER_NONE (0 << SOC_GPIO_IN_FILTER_POS)
|
||||
#define SOC_GPIO_IN_FILTER_DEBOUNCE (1 << SOC_GPIO_IN_FILTER_POS)
|
||||
#define SOC_GPIO_IN_FILTER_DEGLITCH (2 << SOC_GPIO_IN_FILTER_POS)
|
||||
|
||||
#define SOC_GPIO_INT_ENABLE (1 << 5)
|
||||
|
||||
/* Bit field: SOC_GPIO_INT_TRIG */
|
||||
#define SOC_GPIO_INT_TRIG_POS 6
|
||||
#define SOC_GPIO_INT_TRIG_MASK (3 << SOC_GPIO_INT_TRIG_POS)
|
||||
/** Interrupt is triggered by a level detection event. */
|
||||
#define SOC_GPIO_INT_TRIG_LEVEL (0 << SOC_GPIO_INT_TRIG_POS)
|
||||
/** Interrupt is triggered by an edge detection event. */
|
||||
#define SOC_GPIO_INT_TRIG_EDGE (1 << SOC_GPIO_INT_TRIG_POS)
|
||||
/** Interrupt is triggered by any edge detection event. */
|
||||
#define SOC_GPIO_INT_TRIG_DOUBLE_EDGE (2 << SOC_GPIO_INT_TRIG_POS)
|
||||
|
||||
/** Interrupt is triggered by a high level / rising edge detection event */
|
||||
#define SOC_GPIO_INT_ACTIVE_HIGH (1 << 8)
|
||||
|
||||
/* Bit field: SOC_GPIO_FUNC */
|
||||
#define SOC_GPIO_FUNC_POS 16
|
||||
#define SOC_GPIO_FUNC_MASK (7 << SOC_GPIO_FUNC_POS)
|
||||
/** Connect pin to peripheral A. */
|
||||
#define SOC_GPIO_FUNC_A (0 << SOC_GPIO_FUNC_POS)
|
||||
/** Connect pin to peripheral B. */
|
||||
#define SOC_GPIO_FUNC_B (1 << SOC_GPIO_FUNC_POS)
|
||||
/** Connect pin to peripheral C. */
|
||||
#define SOC_GPIO_FUNC_C (2 << SOC_GPIO_FUNC_POS)
|
||||
/** Connect pin to peripheral D. */
|
||||
#define SOC_GPIO_FUNC_D (3 << SOC_GPIO_FUNC_POS)
|
||||
/** Configure pin as input. */
|
||||
#define SOC_GPIO_FUNC_IN (4 << SOC_GPIO_FUNC_POS)
|
||||
/** Configure pin as output and set it initial value to 0. */
|
||||
#define SOC_GPIO_FUNC_OUT_0 (5 << SOC_GPIO_FUNC_POS)
|
||||
/** Configure pin as output and set it initial value to 1. */
|
||||
#define SOC_GPIO_FUNC_OUT_1 (6 << SOC_GPIO_FUNC_POS)
|
||||
|
||||
struct soc_gpio_pin {
|
||||
uint32_t mask; /** pin(s) bit mask */
|
||||
Pio *regs; /** pointer to registers of the PIO controller */
|
||||
uint8_t periph_id; /** peripheral ID of the PIO controller */
|
||||
uint32_t flags; /** pin flags/attributes */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Configure GPIO pin(s).
|
||||
*
|
||||
* Configure one or several pins belonging to the same GPIO port.
|
||||
* Example scenarios:
|
||||
* - configure pin(s) as input with debounce filter enabled.
|
||||
* - connect pin(s) to a peripheral B and enable pull-up.
|
||||
* - configure pin(s) as open drain output.
|
||||
* All pins are configured in the same way.
|
||||
*
|
||||
* @remark The function will enable the GPIO module's clock only if
|
||||
* any of its pins is configured as an input. This is typically what
|
||||
* a user wants. A pin will function correctly without clock enabled
|
||||
* when configured as an output or connected to a peripheral.
|
||||
* In some cases, e.g. when a pin is configured as an output with
|
||||
* a pull-up and user wants to read pin's input value it is necessary
|
||||
* to enable GPIO module's clock separately.
|
||||
*
|
||||
* @param pin pin's configuration data such as pin mask, pin attributes, etc.
|
||||
*/
|
||||
void soc_gpio_configure(const struct soc_gpio_pin *pin);
|
||||
|
||||
/**
|
||||
* @brief Configure a list of GPIO pin(s).
|
||||
*
|
||||
* Configure an arbitrary amount of pins in an arbitrary way. Each
|
||||
* configuration entry is a single item in an array passed as an
|
||||
* argument to the function.
|
||||
*
|
||||
* @param pins an array where each item contains pin's configuration data.
|
||||
* @param size size of the pin list.
|
||||
*/
|
||||
void soc_gpio_list_configure(const struct soc_gpio_pin pins[],
|
||||
unsigned int size);
|
||||
|
||||
/**
|
||||
* \brief Set pin(s) high.
|
||||
*
|
||||
* Set pin(s) defined in the mask parameter to high. The pin(s) have to be
|
||||
* configured as output by the configure function. The flags field which
|
||||
* is part of pin struct is ignored.
|
||||
*
|
||||
* \param pin pointer to a pin instance describing one or more pins.
|
||||
*/
|
||||
static inline void soc_gpio_set(const struct soc_gpio_pin *pin)
|
||||
{
|
||||
pin->regs->PIO_SODR = pin->mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set pin(s) low.
|
||||
*
|
||||
* Set pin(s) defined in the mask field to low. The pin(s) have to be
|
||||
* configured as output by the configure function. The flags field which
|
||||
* is part of pin struct is ignored.
|
||||
*
|
||||
* \param pin pointer to a pin instance describing one or more pins.
|
||||
*/
|
||||
static inline void soc_gpio_clear(const struct soc_gpio_pin *pin)
|
||||
{
|
||||
pin->regs->PIO_CODR = pin->mask;
|
||||
}
|
||||
|
||||
#endif /* _ATMEL_SAM_SOC_GPIO_H_ */
|
56
arch/arm/soc/atmel_sam/common/soc_pmc.c
Normal file
56
arch/arm/soc/atmel_sam/common/soc_pmc.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Piotr Mienkowski
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Atmel SAM MCU family Power Management Controller (PMC) module
|
||||
* HAL driver.
|
||||
*/
|
||||
|
||||
#include <soc.h>
|
||||
#include <misc/__assert.h>
|
||||
#include <misc/util.h>
|
||||
|
||||
#if ID_PERIPH_COUNT > 64
|
||||
#error "Unsupported SoC, update soc_pmc.c functions"
|
||||
#endif
|
||||
|
||||
void soc_pmc_peripheral_enable(uint32_t id)
|
||||
{
|
||||
__ASSERT(id < ID_PERIPH_COUNT, "Invalid peripheral id");
|
||||
|
||||
if (id < 32) {
|
||||
PMC->PMC_PCER0 = BIT(id);
|
||||
#if ID_PERIPH_COUNT > 32
|
||||
} else {
|
||||
PMC->PMC_PCER1 = BIT(id & 0x1F);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void soc_pmc_peripheral_disable(uint32_t id)
|
||||
{
|
||||
__ASSERT(id < ID_PERIPH_COUNT, "Invalid peripheral id");
|
||||
|
||||
if (id < 32) {
|
||||
PMC->PMC_PCDR0 = BIT(id);
|
||||
#if ID_PERIPH_COUNT > 32
|
||||
} else {
|
||||
PMC->PMC_PCDR1 = BIT(id & 0x1F);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t soc_pmc_peripheral_is_enabled(uint32_t id)
|
||||
{
|
||||
__ASSERT(id < ID_PERIPH_COUNT, "Invalid peripheral id");
|
||||
|
||||
if (id < 32) {
|
||||
return (PMC->PMC_PCSR0 & BIT(id)) != 0;
|
||||
#if ID_PERIPH_COUNT > 32
|
||||
} else {
|
||||
return (PMC->PMC_PCSR1 & BIT(id & 0x1F)) != 0;
|
||||
#endif
|
||||
}
|
||||
}
|
38
arch/arm/soc/atmel_sam/common/soc_pmc.h
Normal file
38
arch/arm/soc/atmel_sam/common/soc_pmc.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Piotr Mienkowski
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Atmel SAM MCU family Power Management Controller (PMC) module
|
||||
* HAL driver.
|
||||
*/
|
||||
|
||||
#ifndef _ATMEL_SAM_SOC_PMC_H_
|
||||
#define _ATMEL_SAM_SOC_PMC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Enable the clock of specified peripheral module.
|
||||
*
|
||||
* @param id peripheral module id, as defined in data sheet.
|
||||
*/
|
||||
void soc_pmc_peripheral_enable(uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief Disable the clock of specified peripheral module.
|
||||
*
|
||||
* @param id peripheral module id, as defined in data sheet.
|
||||
*/
|
||||
void soc_pmc_peripheral_disable(uint32_t id);
|
||||
|
||||
/**
|
||||
* @brief Check if specified peripheral module is enabled.
|
||||
*
|
||||
* @param id peripheral module id, as defined in data sheet.
|
||||
* @return 1 if peripheral is enabled, 0 otherwise
|
||||
*/
|
||||
uint32_t soc_pmc_peripheral_is_enabled(uint32_t id);
|
||||
|
||||
#endif /* _ATMEL_SAM_SOC_PMC_H_ */
|
|
@ -4,5 +4,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
ZEPHYRINCLUDE += -I$(srctree)/arch/arm/soc/atmel_sam/common
|
||||
|
||||
obj-y += soc.o
|
||||
obj-y += soc_config.o
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#error Library does not support the specified device.
|
||||
#endif
|
||||
|
||||
#include "../common/soc_pmc.h"
|
||||
#include "../common/soc_gpio.h"
|
||||
|
||||
/****** Cortex-M7 Processor Exceptions Numbers ******************************/
|
||||
|
||||
/** 2 Non Maskable Interrupt */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue