| /* |
| * Copyright (c) 2020 Linaro Ltd. |
| * Copyright (c) 2020-2021 ATL Electronics |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** @file |
| * @brief Cypress PSoC-6 MCU family devicetree helper macros |
| */ |
| |
| #ifndef _CYPRESS_PSOC6_DT_H_ |
| #define _CYPRESS_PSOC6_DT_H_ |
| |
| #include <devicetree.h> |
| |
| /* |
| * Devicetree macros related to interrupt |
| * |
| * The main "API" macro is CY_PSOC6_IRQ_CONFIG. It is an internal definition |
| * used to configure the PSoC-6 interrupts in a generic way. This is necessary |
| * because Cortex-M0+ can handle a limited number of interrupts and have |
| * multiplexers in front of any NVIC interrupt line. |
| * |
| * The CY_PSOC6_IRQ_CONFIG expands from CY_PSOC6_DT_INST_NVIC_INSTALL, the |
| * public API used by drivers. See below code fragment: |
| * |
| * static void <driver>_psoc6_isr(const struct device *dev) |
| * { |
| * ... |
| * } |
| * |
| * #define <DRIVER>_PSOC6_INIT(n) \ |
| * ... \ |
| * static void <driver>_psoc6_irq_config(const struct device *port) \ |
| * { \ |
| * CY_PSOC6_DT_INST_NVIC_INSTALL(n, \ |
| * <driver>_psoc6_isr); \ |
| * }; \ |
| * }; |
| * |
| * where: |
| * n - driver instance number |
| * isr - isr function to be called |
| * |
| * Cortex-M4 simple pass the parameter and constructs an usual NVIC |
| * configuration code. |
| * |
| * The Cortex-M0+ must get from interrupt parent the interrupt line and |
| * configure the interrupt channel to connect PSoC-6 peripheral interrupt to |
| * Cortex-M0+ NVIC. The multiplexer is configured by CY_PSOC6_DT_NVIC_MUX_MAP |
| * using the interrupt value from the interrupt parent. |
| * |
| * see cypress,psoc6-int-mux.yaml for devicetree documentation. |
| */ |
| #ifdef CONFIG_CPU_CORTEX_M0PLUS |
| /* Cortex-M0+ |
| * - install config only when exists an interrupt_parent property |
| * - get peripheral irq using PROP_BY_INDEX, to avoid translation from |
| * interrupt-parent node property. |
| * - configure interrupt channel using the channel number register value from |
| * interrupt-parent node. |
| */ |
| #define CY_PSOC6_DT_INST_NVIC_INSTALL(n, isr) \ |
| IF_ENABLED(DT_INST_NODE_HAS_PROP(n, interrupt_parent),\ |
| (CY_PSOC6_IRQ_CONFIG(n, isr))) |
| #define CY_PSOC6_NVIC_MUX_IRQN(n) DT_IRQN(DT_INST_PHANDLE_BY_IDX(n,\ |
| interrupt_parent, 0)) |
| |
| #define CY_PSOC6_NVIC_MUX_IRQ_PRIO(n) DT_IRQ(DT_INST_PHANDLE_BY_IDX(n,\ |
| interrupt_parent, 0), priority) |
| /* |
| * DT_INST_PROP_BY_IDX should be used get interrupt and configure, instead |
| * DT_INST_IRQN. The DT_INST_IRQN return IRQ number with level translation, |
| * since it uses interrupt-parent, and the value at Cortex-M0 NVIC multiplexers |
| * will be wrong. |
| * |
| * See multi-level-interrupt-handling. |
| */ |
| #define CY_PSOC6_NVIC_MUX_MAP(n) Cy_SysInt_SetInterruptSource( \ |
| DT_IRQN(DT_INST_PHANDLE_BY_IDX(n,\ |
| interrupt_parent, 0)), \ |
| DT_INST_PROP_BY_IDX(n, interrupts, 0)) |
| #else |
| /* Cortex-M4 |
| * - bypass config |
| * - uses irq directly from peripheral devicetree definition |
| * - no map/translations |
| */ |
| #define CY_PSOC6_DT_INST_NVIC_INSTALL(n, isr) CY_PSOC6_IRQ_CONFIG(n, isr) |
| #define CY_PSOC6_NVIC_MUX_IRQN(n) DT_INST_IRQN(n) |
| #define CY_PSOC6_NVIC_MUX_IRQ_PRIO(n) DT_INST_IRQ(n, priority) |
| #define CY_PSOC6_NVIC_MUX_MAP(n) |
| #endif |
| |
| #define CY_PSOC6_IRQ_CONFIG(n, isr) \ |
| do { \ |
| IRQ_CONNECT(CY_PSOC6_NVIC_MUX_IRQN(n), \ |
| CY_PSOC6_NVIC_MUX_IRQ_PRIO(n),\ |
| isr, DEVICE_DT_INST_GET(n), 0);\ |
| CY_PSOC6_NVIC_MUX_MAP(n); \ |
| irq_enable(CY_PSOC6_NVIC_MUX_IRQN(n)); \ |
| } while (0) |
| |
| /* |
| * Devicetree related macros to construct pin control config data |
| */ |
| |
| /* 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(DT_INST_PINCTRL_0(inst, i), cypress_pins)) |
| |
| /* Get PIN associated with pinctrl-0 pin at index 'i' */ |
| #define CY_PSOC6_PIN(inst, i) \ |
| DT_PHA(DT_INST_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(DT_INST_PINCTRL_0(inst, i), cypress_pins, hsiom) |
| |
| /* Helper function for CY_PSOC6_PIN_FLAGS */ |
| #define CY_PSOC6_PIN_FLAG(inst, i, flag) \ |
| DT_PROP(DT_INST_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_NUM_PINCTRLS_BY_IDX(inst, 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_ */ |