1 /* 2 * Copyright (c) 2020 Linaro Ltd. 3 * Copyright (c) 2020-2021 ATL Electronics 4 * 5 * SPDX-License-Identifier: Apache-2.0 6 */ 7 8 /** @file 9 * @brief Cypress PSoC-6 MCU family devicetree helper macros 10 */ 11 12 #ifndef _CYPRESS_PSOC6_DT_H_ 13 #define _CYPRESS_PSOC6_DT_H_ 14 15 #include <zephyr/devicetree.h> 16 #include <zephyr/irq.h> 17 18 /* 19 * Devicetree macros related to interrupt 20 * 21 * The main "API" macro is CY_PSOC6_IRQ_CONFIG. It is an internal definition 22 * used to configure the PSoC-6 interrupts in a generic way. This is necessary 23 * because Cortex-M0+ can handle a limited number of interrupts and have 24 * multiplexers in front of any NVIC interrupt line. 25 * 26 * The CY_PSOC6_IRQ_CONFIG expands from CY_PSOC6_DT_INST_NVIC_INSTALL, the 27 * public API used by drivers. See below code fragment: 28 * 29 * static void <driver>_psoc6_isr(const struct device *dev) 30 * { 31 * ... 32 * } 33 * 34 * #define <DRIVER>_PSOC6_INIT(n) \ 35 * ... \ 36 * static void <driver>_psoc6_irq_config(const struct device *port) \ 37 * { \ 38 * CY_PSOC6_DT_INST_NVIC_INSTALL(n, \ 39 * <driver>_psoc6_isr); \ 40 * }; \ 41 * }; 42 * 43 * where: 44 * n - driver instance number 45 * isr - isr function to be called 46 * 47 * Cortex-M4 simple pass the parameter and constructs an usual NVIC 48 * configuration code. 49 * 50 * The Cortex-M0+ must get from interrupt parent the interrupt line and 51 * configure the interrupt channel to connect PSoC-6 peripheral interrupt to 52 * Cortex-M0+ NVIC. The multiplexer is configured by CY_PSOC6_DT_NVIC_MUX_MAP 53 * using the interrupt value from the interrupt parent. 54 * 55 * see cypress,psoc6-int-mux.yaml for devicetree documentation. 56 */ 57 #ifdef CONFIG_CPU_CORTEX_M0PLUS 58 /* Cortex-M0+ 59 * - install config only when exists an interrupt_parent property 60 * - get peripheral irq using PROP_BY_INDEX, to avoid translation from 61 * interrupt-parent node property. 62 * - configure interrupt channel using the channel number register value from 63 * interrupt-parent node. 64 */ 65 #define CY_PSOC6_DT_INST_NVIC_INSTALL(n, isr) \ 66 IF_ENABLED(DT_INST_NODE_HAS_PROP(n, interrupt_parent),\ 67 (CY_PSOC6_IRQ_CONFIG(n, isr))) 68 #define CY_PSOC6_NVIC_MUX_IRQN(n) DT_IRQN(DT_INST_PHANDLE_BY_IDX(n,\ 69 interrupt_parent, 0)) 70 71 #define CY_PSOC6_NVIC_MUX_IRQ_PRIO(n) DT_IRQ(DT_INST_PHANDLE_BY_IDX(n,\ 72 interrupt_parent, 0), priority) 73 /* 74 * DT_INST_PROP_BY_IDX should be used get interrupt and configure, instead 75 * DT_INST_IRQN. The DT_INST_IRQN return IRQ number with level translation, 76 * since it uses interrupt-parent, and the value at Cortex-M0 NVIC multiplexers 77 * will be wrong. 78 * 79 * See multi-level-interrupt-handling. 80 */ 81 #define CY_PSOC6_NVIC_MUX_MAP(n) Cy_SysInt_SetInterruptSource( \ 82 DT_IRQN(DT_INST_PHANDLE_BY_IDX(n,\ 83 interrupt_parent, 0)), \ 84 DT_INST_PROP_BY_IDX(n, interrupts, 0)) 85 #else 86 /* Cortex-M4 87 * - bypass config 88 * - uses irq directly from peripheral devicetree definition 89 * - no map/translations 90 */ 91 #define CY_PSOC6_DT_INST_NVIC_INSTALL(n, isr) CY_PSOC6_IRQ_CONFIG(n, isr) 92 #define CY_PSOC6_NVIC_MUX_IRQN(n) DT_INST_IRQN(n) 93 #define CY_PSOC6_NVIC_MUX_IRQ_PRIO(n) DT_INST_IRQ(n, priority) 94 #define CY_PSOC6_NVIC_MUX_MAP(n) 95 #endif 96 97 #define CY_PSOC6_IRQ_CONFIG(n, isr) \ 98 do { \ 99 IRQ_CONNECT(CY_PSOC6_NVIC_MUX_IRQN(n), \ 100 CY_PSOC6_NVIC_MUX_IRQ_PRIO(n),\ 101 isr, DEVICE_DT_INST_GET(n), 0);\ 102 CY_PSOC6_NVIC_MUX_MAP(n); \ 103 irq_enable(CY_PSOC6_NVIC_MUX_IRQN(n)); \ 104 } while (false) 105 106 /* 107 * Devicetree related macros to construct pin control config data 108 */ 109 110 /* Get GPIO register address associated with pinctrl-0 pin at index 'i' */ 111 #define CY_PSOC6_PIN_TO_GPIO_REG_ADDR(inst, i) \ 112 DT_REG_ADDR(DT_PHANDLE(DT_INST_PINCTRL_0(inst, i), cypress_pins)) 113 114 /* Get PIN associated with pinctrl-0 pin at index 'i' */ 115 #define CY_PSOC6_PIN(inst, i) \ 116 DT_PHA(DT_INST_PINCTRL_0(inst, i), cypress_pins, pin) 117 118 /* Get HSIOM value associated with pinctrl-0 pin at index 'i' */ 119 #define CY_PSOC6_PIN_HSIOM(inst, i) \ 120 DT_PHA(DT_INST_PINCTRL_0(inst, i), cypress_pins, hsiom) 121 122 /* Helper function for CY_PSOC6_PIN_FLAGS */ 123 #define CY_PSOC6_PIN_FLAG(inst, i, flag) \ 124 DT_PROP(DT_INST_PINCTRL_0(inst, i), flag) 125 126 /* Convert DT flags to SoC flags */ 127 #define CY_PSOC6_PIN_FLAGS(inst, i) \ 128 (CY_PSOC6_PIN_FLAG(inst, i, bias_pull_up) << \ 129 SOC_GPIO_PULLUP_POS | \ 130 CY_PSOC6_PIN_FLAG(inst, i, bias_pull_down) << \ 131 SOC_GPIO_PULLUP_POS | \ 132 CY_PSOC6_PIN_FLAG(inst, i, drive_open_drain) << \ 133 SOC_GPIO_OPENDRAIN_POS | \ 134 CY_PSOC6_PIN_FLAG(inst, i, drive_open_source) << \ 135 SOC_GPIO_OPENSOURCE_POS | \ 136 CY_PSOC6_PIN_FLAG(inst, i, drive_push_pull) << \ 137 SOC_GPIO_PUSHPULL_POS | \ 138 CY_PSOC6_PIN_FLAG(inst, i, input_enable) << \ 139 SOC_GPIO_INPUTENABLE_POS) 140 141 /* Construct a soc_pio_pin element for pin cfg */ 142 #define CY_PSOC6_DT_INST_PIN(inst, idx) \ 143 { \ 144 (GPIO_PRT_Type *)CY_PSOC6_PIN_TO_GPIO_REG_ADDR(inst, idx), \ 145 CY_PSOC6_PIN(inst, idx), \ 146 CY_PSOC6_PIN_HSIOM(inst, idx) << SOC_GPIO_FUNC_POS | \ 147 CY_PSOC6_PIN_FLAGS(inst, idx) \ 148 } 149 150 /* Get the number of pins for pinctrl-0 */ 151 #define CY_PSOC6_DT_INST_NUM_PINS(inst) DT_INST_NUM_PINCTRLS_BY_IDX(inst, 0) 152 153 /* internal macro to structure things for use with UTIL_LISTIFY */ 154 #define CY_PSOC6_PIN_ELEM(idx, inst) CY_PSOC6_DT_INST_PIN(inst, idx) 155 156 /* Construct an array initializer for soc_gpio_pin for a device instance */ 157 #define CY_PSOC6_DT_INST_PINS(inst) \ 158 { LISTIFY(CY_PSOC6_DT_INST_NUM_PINS(inst), \ 159 CY_PSOC6_PIN_ELEM, (,), inst) \ 160 } 161 162 #endif /* _CYPRESS_PSOC6_SOC_DT_H_ */ 163