From 3c4f819c0281351d69aace862a3deb5e8b746f1a Mon Sep 17 00:00:00 2001 From: Sadik Ozer Date: Thu, 30 Nov 2023 13:48:26 +0300 Subject: [PATCH] drivers: w1: Add MAX32xxx 1-Wire driver Added 1-Wire master driver for MAX32xxx MCUs Signed-off-by: Sadik Ozer --- drivers/w1/CMakeLists.txt | 1 + drivers/w1/Kconfig | 1 + drivers/w1/Kconfig.max32 | 10 ++ drivers/w1/w1_max32.c | 207 ++++++++++++++++++++++++++++++ dts/bindings/w1/adi,max32-w1.yaml | 61 +++++++++ 5 files changed, 280 insertions(+) create mode 100644 drivers/w1/Kconfig.max32 create mode 100644 drivers/w1/w1_max32.c create mode 100644 dts/bindings/w1/adi,max32-w1.yaml diff --git a/drivers/w1/CMakeLists.txt b/drivers/w1/CMakeLists.txt index 58fa21ab84a..9a9b3133069 100644 --- a/drivers/w1/CMakeLists.txt +++ b/drivers/w1/CMakeLists.txt @@ -13,6 +13,7 @@ zephyr_library_sources_ifdef(CONFIG_W1_DS2482_800 w1_ds2482-800.c w1_ds248 zephyr_library_sources_ifdef(CONFIG_W1_DS2484 w1_ds2484.c) zephyr_library_sources_ifdef(CONFIG_W1_DS2485 w1_ds2485.c) zephyr_library_sources_ifdef(CONFIG_W1_DS2477_85_COMMON w1_ds2477_85_common.c) +zephyr_library_sources_ifdef(CONFIG_W1_MAX32 w1_max32.c) zephyr_library_sources_ifdef(CONFIG_W1_TEST w1_test.c) zephyr_library_sources_ifdef(CONFIG_W1_ZEPHYR_GPIO w1_zephyr_gpio.c) zephyr_library_sources_ifdef(CONFIG_W1_ZEPHYR_SERIAL w1_zephyr_serial.c) diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index d33503c2684..a55fd3e46e8 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -43,6 +43,7 @@ rsource "Kconfig.ds2482-800" rsource "Kconfig.ds2484" rsource "Kconfig.ds2477_85" rsource "Kconfig.ds2485" +rsource "Kconfig.max32" rsource "Kconfig.test" rsource "Kconfig.zephyr_gpio" rsource "Kconfig.zephyr_serial" diff --git a/drivers/w1/Kconfig.max32 b/drivers/w1/Kconfig.max32 new file mode 100644 index 00000000000..7f36b89c433 --- /dev/null +++ b/drivers/w1/Kconfig.max32 @@ -0,0 +1,10 @@ +# Copyright (c) 2023-2024 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config W1_MAX32 + bool "MAX32xxx MCUs 1-Wire master driver" + default y + depends on DT_HAS_ADI_MAX32_W1_ENABLED + select PINCTRL + help + This option enables the 1-Wire master driver for MAX32xxx MCUs diff --git a/drivers/w1/w1_max32.c b/drivers/w1/w1_max32.c new file mode 100644 index 00000000000..99651cc0393 --- /dev/null +++ b/drivers/w1/w1_max32.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2023-2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include + +#define DT_DRV_COMPAT adi_max32_w1 + +LOG_MODULE_REGISTER(w1_max32, CONFIG_W1_LOG_LEVEL); + +struct max32_w1_config { + struct w1_master_config w1_config; + mxc_owm_regs_t *regs; + const struct pinctrl_dev_config *pctrl; + const struct device *clock; + struct max32_perclk perclk; + uint8_t internal_pullup; + uint8_t external_pullup; + uint8_t long_line_mode; +}; + +struct max32_w1_data { + struct w1_master_data w1_data; + uint8_t reg_device_config; +}; + +static int api_reset_bus(const struct device *dev) +{ + int ret; + const struct max32_w1_config *const cfg = dev->config; + mxc_owm_regs_t *regs = cfg->regs; + + /* 0 if no 1-wire devices responded during the presence pulse, 1 otherwise */ + ret = MXC_OWM_Reset(); + if (ret > 0) { + /* Check OW pin input state due to presence detect pin seems not work well */ + if (regs->ctrl_stat & MXC_F_OWM_CTRL_STAT_OW_INPUT) { + ret = 1; /* At least 1 device on the line */ + } else { + ret = 0; /* no device on the line */ + } + } + + return ret; +} + +static int api_read_bit(const struct device *dev) +{ + int ret; + + ret = MXC_OWM_ReadBit(); + if (ret < 0) { + if (MXC_OWM_GetPresenceDetect() == 0) { + /* if no slave connected to the bus, read bits shall be logical ones */ + ret = 1; + } else { + return -EIO; + } + } + + return ret; +} + +static int api_write_bit(const struct device *dev, bool bit) +{ + int ret; + + ret = MXC_OWM_WriteBit(bit); + if (ret < 0) { + if (MXC_OWM_GetPresenceDetect() == 0) { + /* if no slave connected to the bus, write shall success */ + ret = 0; + } else { + return -EIO; + } + } + + return ret; +} + +static int api_read_byte(const struct device *dev) +{ + int ret; + + ret = MXC_OWM_ReadByte(); + if (ret < 0) { + if (MXC_OWM_GetPresenceDetect() == 0) { + /* if no slave connected to the bus, read bits shall be logical ones */ + ret = 0xff; + } else { + return -EIO; + } + } + + return ret; +} + +static int api_write_byte(const struct device *dev, uint8_t byte) +{ + int ret; + + ret = MXC_OWM_WriteByte(byte); + if (ret < 0) { + if (MXC_OWM_GetPresenceDetect() == 0) { + /* if no slave connected to the bus, write shall success */ + ret = 0; + } else { + return -EIO; + } + } + + return ret; +} + +static int api_configure(const struct device *dev, enum w1_settings_type type, uint32_t value) +{ + int ret = 0; + + switch (type) { + case W1_SETTING_SPEED: + MXC_OWM_SetOverdrive(value); + break; + case W1_SETTING_STRONG_PULLUP: + const struct max32_w1_config *const dev_config = dev->config; + mxc_owm_regs_t *regs = dev_config->regs; + + if (value == 1) { + regs->cfg |= MXC_F_OWM_CFG_EXT_PULLUP_MODE; + } else { + regs->cfg &= ~MXC_F_OWM_CFG_EXT_PULLUP_MODE; + } + break; + default: + return -EINVAL; + } + + return ret; +} + +static int w1_max32_init(const struct device *dev) +{ + int ret; + const struct max32_w1_config *const cfg = dev->config; + mxc_owm_cfg_t mxc_owm_cfg; + + if (!device_is_ready(cfg->clock)) { + LOG_ERR("clock control device not ready"); + return -ENODEV; + } + + MXC_OWM_Shutdown(); + + ret = clock_control_on(cfg->clock, (clock_control_subsys_t)&cfg->perclk); + if (ret != 0) { + LOG_ERR("cannot enable OWM clock"); + return ret; + } + + ret = pinctrl_apply_state(cfg->pctrl, PINCTRL_STATE_DEFAULT); + if (ret) { + return ret; + } + + mxc_owm_cfg.int_pu_en = cfg->internal_pullup; + mxc_owm_cfg.ext_pu_mode = cfg->external_pullup; + mxc_owm_cfg.long_line_mode = cfg->long_line_mode; + + ret = Wrap_MXC_OWM_Init(&mxc_owm_cfg); + + return ret; +} + +static const struct w1_driver_api w1_max32_driver_api = { + .reset_bus = api_reset_bus, + .read_bit = api_read_bit, + .write_bit = api_write_bit, + .read_byte = api_read_byte, + .write_byte = api_write_byte, + .configure = api_configure, +}; + +#define MAX32_W1_INIT(_num) \ + PINCTRL_DT_INST_DEFINE(_num); \ + static const struct max32_w1_config max32_w1_config_##_num = { \ + .w1_config.slave_count = W1_INST_SLAVE_COUNT(_num), \ + .regs = (mxc_owm_regs_t *)DT_INST_REG_ADDR(_num), \ + .pctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(_num), \ + .clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(_num)), \ + .perclk.bus = DT_INST_CLOCKS_CELL(_num, offset), \ + .perclk.bit = DT_INST_CLOCKS_CELL(_num, bit), \ + .internal_pullup = DT_INST_PROP(_num, internal_pullup), \ + .external_pullup = DT_INST_PROP_OR(_num, external_pullup, 0), \ + .long_line_mode = DT_INST_PROP(_num, long_line_mode), \ + }; \ + static struct max32_w1_data max32_owm_data##_num; \ + DEVICE_DT_INST_DEFINE(_num, w1_max32_init, NULL, &max32_owm_data##_num, \ + &max32_w1_config_##_num, POST_KERNEL, CONFIG_W1_INIT_PRIORITY, \ + &w1_max32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MAX32_W1_INIT) diff --git a/dts/bindings/w1/adi,max32-w1.yaml b/dts/bindings/w1/adi,max32-w1.yaml new file mode 100644 index 00000000000..77fb82822e1 --- /dev/null +++ b/dts/bindings/w1/adi,max32-w1.yaml @@ -0,0 +1,61 @@ +# Copyright (c) 2023-2024 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: ADI MAX32xxx MCUs 1-Wire Master + +include: [w1-master.yaml, pinctrl-device.yaml] + +compatible: "adi,max32-w1" + +properties: + reg: + required: true + + clocks: + required: true + + interrupts: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + internal-pullup: + required: true + type: int + enum: [0, 1] + description: | + Set this field to enable the internal pullup resistor. + 0 - Internal pullup disabled. + 1 - Internal pullup enabled. + + external-pullup: + type: int + enum: [0, 1, 2] + description: | + Set this field to enable the external pullup. + 0 - Pullup pin is active high when enabled. + 1 - Pullup pin is active low when enabled. + 2 - Pullup pin is not used for an external pullup. + + long-line-mode: + type: boolean + description: | + Long Line Mode Enable + Selects alternate timings for 1-Wire communication. + The recommended setting depends on the length of the wire. + For lines less than 40 meters, 0 should be used. + + Setting this bit to 0 leaves the write one release, + the data sampling, and the time-slot recovery times at + approximately 5us (micro second), 15us, and 7us, respectively. + + Setting this bit to 1 enables long line mode timings during standard mode communications. + This mode moves the write one release, the data sampling, + and the time-slot recovery times out to approximately 8us, 22us, and 14us, respectively. + + 0 - Standard operation for lines less than 40 meters. + 1 - Long Line mode enabled.