/* * 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 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 _psoc6_isr(const struct device *dev) * { * ... * } * * #define _PSOC6_INIT(n) \ * ... \ * static void _psoc6_irq_config(const struct device *port) \ * { \ * CY_PSOC6_DT_INST_NVIC_INSTALL(n, \ * _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_ */