1 /* 2 * Copyright (c) 2024, Ambiq Micro Inc. <www.ambiq.com> 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef ZEPHYR_INCLUDE_DRIVERS_MSPI_DEVICETREE_H_ 8 #define ZEPHYR_INCLUDE_DRIVERS_MSPI_DEVICETREE_H_ 9 10 /** 11 * @brief MSPI Devicetree related macros 12 * @defgroup mspi_devicetree MSPI Devicetree related macros 13 * @ingroup io_interfaces 14 * @{ 15 */ 16 17 #include <zephyr/drivers/gpio.h> 18 19 #ifdef __cplusplus 20 extern "C" { 21 #endif 22 23 /** 24 * @brief Structure initializer for <tt>struct mspi_dev_cfg</tt> from devicetree 25 * 26 * This helper macro expands to a static initializer for a <tt>struct 27 * mspi_dev_cfg</tt> by reading the relevant data from the devicetree. 28 * 29 * @param mspi_dev Devicetree node identifier for the MSPI device whose 30 * struct mspi_dev_cfg to create an initializer for 31 */ 32 #define MSPI_DEVICE_CONFIG_DT(mspi_dev) \ 33 { \ 34 .ce_num = DT_PROP_OR(mspi_dev, mspi_hardware_ce_num, 0), \ 35 .freq = DT_PROP(mspi_dev, mspi_max_frequency), \ 36 .io_mode = DT_ENUM_IDX_OR(mspi_dev, mspi_io_mode, \ 37 MSPI_IO_MODE_SINGLE), \ 38 .data_rate = DT_ENUM_IDX_OR(mspi_dev, mspi_data_rate, \ 39 MSPI_DATA_RATE_SINGLE), \ 40 .cpp = DT_ENUM_IDX_OR(mspi_dev, mspi_cpp_mode, MSPI_CPP_MODE_0), \ 41 .endian = DT_ENUM_IDX_OR(mspi_dev, mspi_endian, \ 42 MSPI_XFER_LITTLE_ENDIAN), \ 43 .ce_polarity = DT_ENUM_IDX_OR(mspi_dev, mspi_ce_polarity, \ 44 MSPI_CE_ACTIVE_LOW), \ 45 .dqs_enable = DT_PROP(mspi_dev, mspi_dqs_enable), \ 46 .rx_dummy = DT_PROP_OR(mspi_dev, rx_dummy, 0), \ 47 .tx_dummy = DT_PROP_OR(mspi_dev, tx_dummy, 0), \ 48 .read_cmd = DT_PROP_OR(mspi_dev, read_command, 0), \ 49 .write_cmd = DT_PROP_OR(mspi_dev, write_command, 0), \ 50 .cmd_length = DT_ENUM_IDX_OR(mspi_dev, command_length, 0), \ 51 .addr_length = DT_ENUM_IDX_OR(mspi_dev, address_length, 0), \ 52 .mem_boundary = COND_CODE_1(DT_NODE_HAS_PROP(mspi_dev, ce_break_config), \ 53 (DT_PROP_BY_IDX(mspi_dev, ce_break_config, 0)), \ 54 (0)), \ 55 .time_to_break = COND_CODE_1(DT_NODE_HAS_PROP(mspi_dev, ce_break_config), \ 56 (DT_PROP_BY_IDX(mspi_dev, ce_break_config, 1)), \ 57 (0)), \ 58 } 59 60 /** 61 * @brief Structure initializer for <tt>struct mspi_dev_cfg</tt> from devicetree instance 62 * 63 * This is equivalent to 64 * <tt>MSPI_DEVICE_CONFIG_DT(DT_DRV_INST(inst))</tt>. 65 * 66 * @param inst Devicetree instance number 67 */ 68 #define MSPI_DEVICE_CONFIG_DT_INST(inst) MSPI_DEVICE_CONFIG_DT(DT_DRV_INST(inst)) 69 70 /** 71 * @brief Structure initializer for <tt>struct mspi_xip_cfg</tt> from devicetree 72 * 73 * This helper macro expands to a static initializer for a <tt>struct 74 * mspi_xip_cfg</tt> by reading the relevant data from the devicetree. 75 * 76 * @param mspi_dev Devicetree node identifier for the MSPI device whose 77 * struct mspi_xip_cfg to create an initializer for 78 */ 79 #define MSPI_XIP_CONFIG_DT_NO_CHECK(mspi_dev) \ 80 { \ 81 .enable = DT_PROP_BY_IDX(mspi_dev, xip_config, 0), \ 82 .address_offset = DT_PROP_BY_IDX(mspi_dev, xip_config, 1), \ 83 .size = DT_PROP_BY_IDX(mspi_dev, xip_config, 2), \ 84 .permission = DT_PROP_BY_IDX(mspi_dev, xip_config, 3), \ 85 } 86 87 /** 88 * @brief Structure initializer for <tt>struct mspi_xip_cfg</tt> from devicetree 89 * 90 * This helper macro check whether <tt>xip_config</tt> binding exist first 91 * before calling <tt>MSPI_XIP_CONFIG_DT_NO_CHECK</tt>. 92 * 93 * @param mspi_dev Devicetree node identifier for the MSPI device whose 94 * struct mspi_xip_cfg to create an initializer for 95 */ 96 #define MSPI_XIP_CONFIG_DT(mspi_dev) \ 97 COND_CODE_1(DT_NODE_HAS_PROP(mspi_dev, xip_config), \ 98 (MSPI_XIP_CONFIG_DT_NO_CHECK(mspi_dev)), \ 99 ({})) 100 101 /** 102 * @brief Structure initializer for <tt>struct mspi_xip_cfg</tt> from devicetree instance 103 * 104 * This is equivalent to 105 * <tt>MSPI_XIP_CONFIG_DT(DT_DRV_INST(inst))</tt>. 106 * 107 * @param inst Devicetree instance number 108 */ 109 #define MSPI_XIP_CONFIG_DT_INST(inst) MSPI_XIP_CONFIG_DT(DT_DRV_INST(inst)) 110 111 /** 112 * @brief Structure initializer for <tt>struct mspi_scramble_cfg</tt> from devicetree 113 * 114 * This helper macro expands to a static initializer for a <tt>struct 115 * mspi_scramble_cfg</tt> by reading the relevant data from the devicetree. 116 * 117 * @param mspi_dev Devicetree node identifier for the MSPI device whose 118 * struct mspi_scramble_cfg to create an initializer for 119 */ 120 #define MSPI_SCRAMBLE_CONFIG_DT_NO_CHECK(mspi_dev) \ 121 { \ 122 .enable = DT_PROP_BY_IDX(mspi_dev, scramble_config, 0), \ 123 .address_offset = DT_PROP_BY_IDX(mspi_dev, scramble_config, 1), \ 124 .size = DT_PROP_BY_IDX(mspi_dev, scramble_config, 2), \ 125 } 126 127 /** 128 * @brief Structure initializer for <tt>struct mspi_scramble_cfg</tt> from devicetree 129 * 130 * This helper macro check whether <tt>scramble_config</tt> binding exist first 131 * before calling <tt>MSPI_SCRAMBLE_CONFIG_DT_NO_CHECK</tt>. 132 * 133 * @param mspi_dev Devicetree node identifier for the MSPI device whose 134 * struct mspi_scramble_cfg to create an initializer for 135 */ 136 #define MSPI_SCRAMBLE_CONFIG_DT(mspi_dev) \ 137 COND_CODE_1(DT_NODE_HAS_PROP(mspi_dev, scramble_config), \ 138 (MSPI_SCRAMBLE_CONFIG_DT_NO_CHECK(mspi_dev)), \ 139 ({})) 140 141 /** 142 * @brief Structure initializer for <tt>struct mspi_scramble_cfg</tt> from devicetree instance 143 * 144 * This is equivalent to 145 * <tt>MSPI_SCRAMBLE_CONFIG_DT(DT_DRV_INST(inst))</tt>. 146 * 147 * @param inst Devicetree instance number 148 */ 149 #define MSPI_SCRAMBLE_CONFIG_DT_INST(inst) MSPI_SCRAMBLE_CONFIG_DT(DT_DRV_INST(inst)) 150 151 /** 152 * @brief Structure initializer for <tt>struct mspi_dev_id</tt> from devicetree 153 * 154 * This helper macro expands to a static initializer for a <tt>struct 155 * mspi_dev_id</tt> by reading the relevant data from the devicetree. 156 * 157 * @param mspi_dev Devicetree node identifier for the MSPI device whose 158 * struct mspi_dev_id to create an initializer for 159 */ 160 #define MSPI_DEVICE_ID_DT(mspi_dev) \ 161 { \ 162 .ce = MSPI_DEV_CE_GPIOS_DT_SPEC_GET(mspi_dev), \ 163 .dev_idx = DT_REG_ADDR(mspi_dev), \ 164 } 165 166 /** 167 * @brief Structure initializer for <tt>struct mspi_dev_id</tt> from devicetree instance 168 * 169 * This is equivalent to 170 * <tt>MSPI_DEVICE_ID_DT(DT_DRV_INST(inst))</tt>. 171 * 172 * @param inst Devicetree instance number 173 */ 174 #define MSPI_DEVICE_ID_DT_INST(inst) MSPI_DEVICE_ID_DT(DT_DRV_INST(inst)) 175 176 177 /** 178 * @brief Get a <tt>struct gpio_dt_spec</tt> for a MSPI device's chip enable pin 179 * 180 * Example devicetree fragment: 181 * 182 * @code{.devicetree} 183 * gpio1: gpio@abcd0001 { ... }; 184 * 185 * gpio2: gpio@abcd0002 { ... }; 186 * 187 * mspi@abcd0003 { 188 * compatible = "ambiq,mspi"; 189 * ce-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>, 190 * <&gpio2 20 GPIO_ACTIVE_LOW>; 191 * 192 * a: mspi-dev-a@0 { 193 * reg = <0>; 194 * }; 195 * 196 * b: mspi-dev-b@1 { 197 * reg = <1>; 198 * }; 199 * }; 200 * @endcode 201 * 202 * Example usage: 203 * 204 * @code{.c} 205 * MSPI_DEV_CE_GPIOS_DT_SPEC_GET(DT_NODELABEL(a)) \ 206 * // { DEVICE_DT_GET(DT_NODELABEL(gpio1)), 10, GPIO_ACTIVE_LOW } 207 * MSPI_DEV_CE_GPIOS_DT_SPEC_GET(DT_NODELABEL(b)) \ 208 * // { DEVICE_DT_GET(DT_NODELABEL(gpio2)), 20, GPIO_ACTIVE_LOW } 209 * @endcode 210 * 211 * @param mspi_dev a MSPI device node identifier 212 * @return #gpio_dt_spec struct corresponding with mspi_dev's chip enable 213 */ 214 #define MSPI_DEV_CE_GPIOS_DT_SPEC_GET(mspi_dev) \ 215 GPIO_DT_SPEC_GET_BY_IDX_OR(DT_BUS(mspi_dev), ce_gpios, \ 216 DT_REG_ADDR_RAW(mspi_dev), {}) 217 218 /** 219 * @brief Get a <tt>struct gpio_dt_spec</tt> for a MSPI device's chip enable pin 220 * 221 * This is equivalent to 222 * <tt>MSPI_DEV_CE_GPIOS_DT_SPEC_GET(DT_DRV_INST(inst))</tt>. 223 * 224 * @param inst Devicetree instance number 225 * @return #gpio_dt_spec struct corresponding with mspi_dev's chip enable 226 */ 227 #define MSPI_DEV_CE_GPIOS_DT_SPEC_INST_GET(inst) \ 228 MSPI_DEV_CE_GPIOS_DT_SPEC_GET(DT_DRV_INST(inst)) 229 230 231 /** 232 * @brief Get an array of <tt>struct gpio_dt_spec</tt> from devicetree for a MSPI controller 233 * 234 * This helper macro check whether <tt>ce_gpios</tt> binding exist first 235 * before calling <tt>GPIO_DT_SPEC_GET_BY_IDX</tt> and expand to an array of 236 * gpio_dt_spec. 237 * 238 * @param node_id Devicetree node identifier for the MSPI controller 239 * @return an array of gpio_dt_spec struct corresponding with mspi_dev's chip enables 240 */ 241 #define MSPI_CE_GPIOS_DT_SPEC_GET(node_id) \ 242 { \ 243 COND_CODE_1(DT_NODE_HAS_PROP(node_id, ce_gpios), \ 244 (DT_FOREACH_PROP_ELEM_SEP(node_id, ce_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,))), \ 245 ()) \ 246 } 247 248 /** 249 * @brief Get an array of <tt>struct gpio_dt_spec</tt> for a MSPI controller 250 * 251 * This is equivalent to 252 * <tt>MSPI_CE_GPIOS_DT_SPEC_GET(DT_DRV_INST(inst))</tt>. 253 * 254 * @param inst Devicetree instance number 255 * @return an array of gpio_dt_spec struct corresponding with mspi_dev's chip enables 256 */ 257 #define MSPI_CE_GPIOS_DT_SPEC_INST_GET(inst) \ 258 MSPI_CE_GPIOS_DT_SPEC_GET(DT_DRV_INST(inst)) 259 260 /** 261 * @brief Initialize and get a pointer to a @p mspi_ce_control from a 262 * devicetree node identifier 263 * 264 * This helper is useful for initializing a device on a MSPI bus. It 265 * initializes a struct mspi_ce_control and returns a pointer to it. 266 * Here, @p node_id is a node identifier for a MSPI device, not a MSPI 267 * controller. 268 * 269 * Example devicetree fragment: 270 * 271 * @code{.devicetree} 272 * mspi@abcd0001 { 273 * ce-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; 274 * mspidev: mspi-device@0 { ... }; 275 * }; 276 * @endcode 277 * 278 * Example usage: 279 * 280 * @code{.c} 281 * struct mspi_ce_control ctrl = 282 * MSPI_CE_CONTROL_INIT(DT_NODELABEL(mspidev), 2); 283 * @endcode 284 * 285 * This example is equivalent to: 286 * 287 * @code{.c} 288 * struct mspi_ce_control ctrl = { 289 * .gpio = MSPI_DEV_CE_GPIOS_DT_SPEC_GET(DT_NODELABEL(mspidev)), 290 * .delay = 2, 291 * }; 292 * @endcode 293 * 294 * @param node_id Devicetree node identifier for a device on a MSPI bus 295 * @param delay_ The @p delay field to set in the @p mspi_ce_control 296 * @return a pointer to the @p mspi_ce_control structure 297 */ 298 #define MSPI_CE_CONTROL_INIT(node_id, delay_) \ 299 { \ 300 .gpio = MSPI_DEV_CE_GPIOS_DT_SPEC_GET(node_id), .delay = (delay_), \ 301 } 302 303 /** 304 * @brief Get a pointer to a @p mspi_ce_control from a devicetree node 305 * 306 * This is equivalent to 307 * <tt>MSPI_CE_CONTROL_INIT(DT_DRV_INST(inst), delay)</tt>. 308 * 309 * Therefore, @p DT_DRV_COMPAT must already be defined before using 310 * this macro. 311 * 312 * @param inst Devicetree node instance number 313 * @param delay_ The @p delay field to set in the @p mspi_ce_control 314 * @return a pointer to the @p mspi_ce_control structure 315 */ 316 #define MSPI_CE_CONTROL_INIT_INST(inst, delay_) MSPI_CE_CONTROL_INIT(DT_DRV_INST(inst), delay_) 317 318 #ifdef __cplusplus 319 } 320 #endif 321 322 /** 323 * @} 324 */ 325 326 #endif /* ZEPHYR_INCLUDE_DRIVERS_MSPI_DEVICETREE_H_ */ 327