diff --git a/soc/arm/cypress/CMakeLists.txt b/soc/arm/cypress/CMakeLists.txt index eaa3f08b8a..95451afda6 100644 --- a/soc/arm/cypress/CMakeLists.txt +++ b/soc/arm/cypress/CMakeLists.txt @@ -1,7 +1,9 @@ # # Copyright (c) 2018, Cypress +# Copyright (c) 2021, ATL Electronics # # SPDX-License-Identifier: Apache-2.0 # add_subdirectory(${SOC_SERIES}) +add_subdirectory(common) diff --git a/soc/arm/cypress/common/CMakeLists.txt b/soc/arm/cypress/common/CMakeLists.txt new file mode 100644 index 0000000000..aad2f32b66 --- /dev/null +++ b/soc/arm/cypress/common/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2021 ATL Electronics +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(.) + +zephyr_library_sources_ifdef(CONFIG_SOC_FAMILY_PSOC6 soc_gpio.c) diff --git a/soc/arm/cypress/common/cypress_psoc6_dt.h b/soc/arm/cypress/common/cypress_psoc6_dt.h index 292764814d..b4e818da5d 100644 --- a/soc/arm/cypress/common/cypress_psoc6_dt.h +++ b/soc/arm/cypress/common/cypress_psoc6_dt.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2020 Linaro Ltd. - * Copyright (c) 2020 ATL Electronics + * Copyright (c) 2020-2021 ATL Electronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -98,4 +98,64 @@ irq_enable(CY_PSOC6_NVIC_MUX_IRQN(n)); \ } while (0) +/* + * Devicetree related macros to construct pin control config data + */ + +/* Get a node id from a pinctrl-0 prop at index 'i' */ +#define NODE_ID_FROM_PINCTRL_0(inst, i) \ + DT_INST_PHANDLE_BY_IDX(inst, pinctrl_0, i) + +/* Get GPIO register address associated with pinctrl-0 pin at index 'i' */ +#define CY_PSOC6_PIN_TO_GPIO_REG_ADDR(inst, i) \ + DT_REG_ADDR(DT_PHANDLE(NODE_ID_FROM_PINCTRL_0(inst, i), cypress_pins)) + +/* Get PIN associated with pinctrl-0 pin at index 'i' */ +#define CY_PSOC6_PIN(inst, i) \ + DT_PHA(NODE_ID_FROM_PINCTRL_0(inst, i), cypress_pins, pin) + +/* Get HSIOM value associated with pinctrl-0 pin at index 'i' */ +#define CY_PSOC6_PIN_HSIOM(inst, i) \ + DT_PHA(NODE_ID_FROM_PINCTRL_0(inst, i), cypress_pins, hsiom) + +/* Helper function for CY_PSOC6_PIN_FLAGS */ +#define CY_PSOC6_PIN_FLAG(inst, i, flag) \ + DT_PROP(NODE_ID_FROM_PINCTRL_0(inst, i), flag) + +/* Convert DT flags to SoC flags */ +#define CY_PSOC6_PIN_FLAGS(inst, i) \ + (CY_PSOC6_PIN_FLAG(inst, i, bias_pull_up) << \ + SOC_GPIO_PULLUP_POS | \ + CY_PSOC6_PIN_FLAG(inst, i, bias_pull_down) << \ + SOC_GPIO_PULLUP_POS | \ + CY_PSOC6_PIN_FLAG(inst, i, drive_open_drain) << \ + SOC_GPIO_OPENDRAIN_POS | \ + CY_PSOC6_PIN_FLAG(inst, i, drive_open_source) << \ + SOC_GPIO_OPENSOURCE_POS | \ + CY_PSOC6_PIN_FLAG(inst, i, drive_push_pull) << \ + SOC_GPIO_PUSHPULL_POS | \ + CY_PSOC6_PIN_FLAG(inst, i, input_enable) << \ + SOC_GPIO_INPUTENABLE_POS) + +/* Construct a soc_pio_pin element for pin cfg */ +#define CY_PSOC6_DT_INST_PIN(inst, idx) \ + { \ + (GPIO_PRT_Type *)CY_PSOC6_PIN_TO_GPIO_REG_ADDR(inst, idx), \ + CY_PSOC6_PIN(inst, idx), \ + CY_PSOC6_PIN_HSIOM(inst, idx) << SOC_GPIO_FUNC_POS | \ + CY_PSOC6_PIN_FLAGS(inst, idx) \ + } + +/* Get the number of pins for pinctrl-0 */ +#define CY_PSOC6_DT_INST_NUM_PINS(inst) DT_INST_PROP_LEN(inst, pinctrl_0) + +/* internal macro to structure things for use with UTIL_LISTIFY */ +#define CY_PSOC6_PIN_ELEM(idx, inst) CY_PSOC6_DT_INST_PIN(inst, idx), + +/* Construct an array intializer for soc_gpio_pin for a device instance */ +#define CY_PSOC6_DT_INST_PINS(inst) \ + { UTIL_LISTIFY(CY_PSOC6_DT_INST_NUM_PINS(inst), \ + CY_PSOC6_PIN_ELEM, inst) \ + } + #endif /* _CYPRESS_PSOC6_SOC_DT_H_ */ diff --git a/soc/arm/cypress/common/soc_gpio.c b/soc/arm/cypress/common/soc_gpio.c new file mode 100644 index 0000000000..dead06352a --- /dev/null +++ b/soc/arm/cypress/common/soc_gpio.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Piotr Mienkowski + * Copyright (c) 2021 ATL Electronics + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Cypress PSoC-6 MCU family General Purpose Input Output (GPIO) + * module HAL driver. + */ + +#include "soc_gpio.h" +#include "cy_gpio.h" + +static uint32_t soc_gpio_get_drv_mode(uint32_t flags) +{ + uint32_t drv_mode = CY_GPIO_DM_ANALOG; + + flags = ((flags & SOC_GPIO_FLAGS_MASK) >> SOC_GPIO_FLAGS_POS); + + if (flags & SOC_GPIO_OPENDRAIN) { + drv_mode = CY_GPIO_DM_OD_DRIVESLOW_IN_OFF; + } else if (flags & SOC_GPIO_OPENSOURCE) { + drv_mode = CY_GPIO_DM_OD_DRIVESHIGH_IN_OFF; + } else if (flags & SOC_GPIO_PUSHPULL) { + drv_mode = CY_GPIO_DM_STRONG_IN_OFF; + } else if ((flags & SOC_GPIO_PULLUP) && (flags & SOC_GPIO_PULLDOWN)) { + drv_mode = CY_GPIO_DM_PULLUP_DOWN_IN_OFF; + } else if (flags & SOC_GPIO_PULLUP) { + drv_mode = CY_GPIO_DM_PULLUP_IN_OFF; + } else if (flags & SOC_GPIO_PULLDOWN) { + drv_mode = CY_GPIO_DM_PULLDOWN_IN_OFF; + } + + if (flags & SOC_GPIO_INPUTENABLE) { + drv_mode |= CY_GPIO_DM_HIGHZ; + } + + return drv_mode; +} + +void soc_gpio_configure(const struct soc_gpio_pin *pin) +{ + uint32_t drv_mode = soc_gpio_get_drv_mode(pin->flags); + uint32_t function = ((pin->flags & SOC_GPIO_FUNC_MASK) >> + SOC_GPIO_FUNC_POS); + + Cy_GPIO_SetHSIOM(pin->regs, pin->pinum, function); + Cy_GPIO_SetDrivemode(pin->regs, pin->pinum, drv_mode); +} + +void soc_gpio_list_configure(const struct soc_gpio_pin pins[], size_t size) +{ + for (size_t i = 0; i < size; i++) { + soc_gpio_configure(&pins[i]); + } +} diff --git a/soc/arm/cypress/common/soc_gpio.h b/soc/arm/cypress/common/soc_gpio.h new file mode 100644 index 0000000000..b14bcee4f7 --- /dev/null +++ b/soc/arm/cypress/common/soc_gpio.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016-2017 Piotr Mienkowski + * Copyright (c) 2021 ATL Electronics + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Cypress PSoC-6 MCU family General Purpose Input Output (GPIO) + * module HAL driver. + */ + +#ifndef _CYPRESS_PSOC6_SOC_GPIO_H_ +#define _CYPRESS_PSOC6_SOC_GPIO_H_ + +#include +#include + +/* + * Pin flags/attributes + */ + +#define SOC_GPIO_DEFAULT (0) + +#define SOC_GPIO_FLAGS_POS (0) +#define SOC_GPIO_FLAGS_MASK (0x3F << SOC_GPIO_FLAGS_POS) +#define SOC_GPIO_PULLUP_POS (0) +#define SOC_GPIO_PULLUP (1 << SOC_GPIO_PULLUP_POS) +#define SOC_GPIO_PULLDOWN_POS (1) +#define SOC_GPIO_PULLDOWN (1 << SOC_GPIO_PULLDOWN_POS) +#define SOC_GPIO_OPENDRAIN_POS (2) +#define SOC_GPIO_OPENDRAIN (1 << SOC_GPIO_OPENDRAIN_POS) +#define SOC_GPIO_OPENSOURCE_POS (3) +#define SOC_GPIO_OPENSOURCE (1 << SOC_GPIO_OPENSOURCE_POS) +/* Push-Pull means Strong, see dts/pinctrl/pincfg-node.yaml */ +#define SOC_GPIO_PUSHPULL_POS (4) +#define SOC_GPIO_PUSHPULL (1 << SOC_GPIO_PUSHPULL_POS) +/* Input-Enable means Input-Buffer, see dts/pinctrl/pincfg-node.yaml */ +#define SOC_GPIO_INPUTENABLE_POS (5) +#define SOC_GPIO_INPUTENABLE (1 << SOC_GPIO_INPUTENABLE_POS) + +/* Bit field: SOC_GPIO_IN_FILTER */ +#define SOC_GPIO_IN_FILTER_POS (6) +#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 << 8) + +/* Bit field: SOC_GPIO_INT_TRIG */ +#define SOC_GPIO_INT_TRIG_POS (9) +#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 << 11) + +/* Bit field: SOC_GPIO_FUNC */ +#define SOC_GPIO_FUNC_POS (16) +#define SOC_GPIO_FUNC_MASK (0x1F << SOC_GPIO_FUNC_POS) + +struct soc_gpio_pin { + GPIO_PRT_Type *regs; /** pointer to registers of the GPIO controller */ + uint32_t pinum; /** pin number */ + 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 HSIOM function and enable pull-up. + * - configure pin(s) as open drain output. + * All pins are configured in the same way. + * + * @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[], size_t size); + +#endif /* _CYPRESS_PSOC6_SOC_GPIO_H_ */ diff --git a/soc/arm/cypress/psoc6/soc.h b/soc/arm/cypress/psoc6/soc.h index 867e60f3ea..eabed08127 100644 --- a/soc/arm/cypress/psoc6/soc.h +++ b/soc/arm/cypress/psoc6/soc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, Cypress - * Copyright (c) 2020, ATL Electronics + * Copyright (c) 2020-2021, ATL Electronics * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,6 +24,7 @@ #include +#include "../common/soc_gpio.h" #include "../common/cypress_psoc6_dt.h" #endif /* !_ASMLANGUAGE */