/* * Copyright (c) 2025 Analog Devices, Inc. * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include LOG_MODULE_REGISTER(memc_max32_hpb, CONFIG_MEMC_LOG_LEVEL); #include #include #define DT_DRV_COMPAT adi_max32_hpb struct memc_max32_hpb_config { const struct device *clock; const struct pinctrl_dev_config *pcfg; }; struct memc_max32_hpb_mem_config { uint8_t reg; mxc_hpb_mem_config_t config; }; /* clang-format off */ #define MEM_CONFIG(n) \ { \ .reg = DT_REG_ADDR(n), \ .config = {.device_type = DT_PROP(n, device_type), \ .base_addr = DT_PROP(n, base_address), \ .latency_cycle = DT_PROP_OR(n, latency_cycles, 1), \ .write_cs_high = DT_PROP_OR(n, write_cs_high, 0), \ .read_cs_high = DT_PROP_OR(n, read_cs_high, 0), \ .write_cs_hold = DT_PROP_OR(n, write_cs_hold, 0), \ .read_cs_hold = DT_PROP_OR(n, read_cs_hold, 0), \ .write_cs_setup = DT_PROP_OR(n, write_cs_setup, 0), \ .read_cs_setup = DT_PROP_OR(n, read_cs_setup, 0), \ .fixed_latency = DT_PROP_OR(n, fixed_read_latency, 0), \ COND_CODE_1(DT_NODE_HAS_PROP(n, config_regs), \ (.cfg_reg_val = config_regs_##n, \ .cfg_reg_val_len = ARRAY_SIZE(config_regs_##n)), ()) }, \ } /* clang-format on */ #define CR_ENTRY(idx, n) \ { \ .addr = DT_PROP_BY_IDX(n, config_regs, idx), \ .val = DT_PROP_BY_IDX(n, config_reg_vals, idx), \ } #define MEM_CR_ENTRIES(n) \ COND_CODE_1(DT_NODE_HAS_PROP(n, config_regs), ( \ BUILD_ASSERT(DT_PROP_LEN(n, config_regs) == DT_PROP_LEN(n, config_reg_vals), \ "The config-regs and config-reg-vals properties of adi,max32-hpb memory device" \ " child nodes must be the same length"); \ static const mxc_hpb_cfg_reg_val_t config_regs_##n[] = \ { LISTIFY(DT_PROP_LEN(n, config_regs), CR_ENTRY, (,), n) }; \ ), ()) /** memory device configuration(s). */ DT_INST_FOREACH_CHILD(0, MEM_CR_ENTRIES) /* clang-format off */ static const struct memc_max32_hpb_mem_config mem_configs[] = { DT_INST_FOREACH_CHILD_SEP(0, MEM_CONFIG, (,))}; #define CLOCK_CFG(node_id, prop, idx) \ {.bus = DT_CLOCKS_CELL_BY_IDX(node_id, idx, offset), \ .bit = DT_CLOCKS_CELL_BY_IDX(node_id, idx, bit)} static const struct max32_perclk perclks[] = { DT_INST_FOREACH_PROP_ELEM_SEP(0, clocks, CLOCK_CFG, (,))}; /* clang-format on */ static int memc_max32_hpb_init(const struct device *dev) { const struct memc_max32_hpb_config *config = dev->config; int r; const mxc_hpb_mem_config_t *mem0 = NULL, *mem1 = NULL; if (!device_is_ready(config->clock)) { LOG_ERR("clock control device not ready"); return -ENODEV; } for (size_t i = 0; i < ARRAY_SIZE(perclks); i++) { r = clock_control_on(config->clock, (clock_control_subsys_t)&perclks[i]); if (r < 0) { LOG_ERR("Could not initialize HPB clock (%d)", r); return r; } } for (size_t i = 0; i < ARRAY_SIZE(mem_configs); i++) { if (mem_configs[i].reg == 0) { mem0 = &mem_configs[i].config; } else if (mem_configs[i].reg == 1) { mem1 = &mem_configs[i].config; } } /* configure pinmux */ r = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); if (r < 0) { LOG_ERR("HPB pinctrl setup failed (%d)", r); return r; } r = MXC_HPB_Init(mem0, mem1); if (r < 0) { LOG_ERR("HPB init failed (%d)", r); return r; } COND_CODE_1(DT_INST_PROP(0, enable_emcc), (MXC_EMCC_Enable()), (MXC_EMCC_Disable())); return 0; } PINCTRL_DT_INST_DEFINE(0); static const struct memc_max32_hpb_config config = { .clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)), .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), }; DEVICE_DT_INST_DEFINE(0, memc_max32_hpb_init, NULL, NULL, &config, POST_KERNEL, CONFIG_MEMC_INIT_PRIORITY, NULL);