/* * Copyright (c) 2022 Thomas Stranger * * SPDX-License-Identifier: Apache-2.0 */ /** * @brief Common functions for Maxim DS2477,DS2485 1-Wire Masters */ #include "w1_ds2477_85_common.h" #include #include #include #include LOG_MODULE_REGISTER(w1_ds2477_85, CONFIG_W1_LOG_LEVEL); int ds2477_85_write_port_config(const struct device *dev, uint8_t reg, uint16_t value) { const struct w1_ds2477_85_config *cfg = dev->config; uint8_t buf[5] = {CMD_WR_W1_PORT_CFG, CMD_WR_W1_PORT_CFG_LEN, reg}; int ret; __ASSERT_NO_MSG(reg <= PORT_REG_COUNT); sys_put_le16(value, &buf[3]); ret = i2c_write_dt(&cfg->i2c_spec, buf, (CMD_WR_W1_PORT_CFG_LEN + CMD_OVERHEAD_LEN)); if (ret < 0) { return ret; } k_usleep(cfg->t_op_us); ret = i2c_read_dt(&cfg->i2c_spec, buf, 2); if (ret < 0) { return ret; } if ((buf[0] != 1) || (buf[1] != DS2477_88_RES_SUCCESS)) { return -EIO; } return 0; } int ds2477_85_read_port_config(const struct device *dev, uint8_t reg, uint16_t *value) { const struct w1_ds2477_85_config *cfg = dev->config; uint8_t buf[4] = {CMD_RD_W1_PORT_CFG, CMD_RD_W1_PORT_CFG_LEN, reg}; int ret; __ASSERT_NO_MSG(value != NULL && reg <= PORT_REG_COUNT); ret = i2c_write_dt(&cfg->i2c_spec, buf, (CMD_RD_W1_PORT_CFG_LEN + CMD_OVERHEAD_LEN)); if (ret < 0) { return ret; } k_usleep(cfg->t_op_us); ret = i2c_read_dt(&cfg->i2c_spec, buf, 4); if (ret < 0) { return ret; } if ((buf[0] != 3) || (buf[1] != DS2477_88_RES_SUCCESS)) { return -EIO; } *value = sys_get_le16(&buf[2]); return 0; } int ds2477_85_reset_master(const struct device *dev) { const struct w1_ds2477_85_config *cfg = dev->config; uint8_t buf[2] = {CMD_MASTER_RESET}; int ret; ret = i2c_write_dt(&cfg->i2c_spec, buf, 1); if (ret < 0) { LOG_ERR("initiate reset failed"); return ret; } k_usleep(cfg->t_op_us); ret = i2c_read_dt(&cfg->i2c_spec, buf, 2); if (ret < 0) { return ret; } if ((buf[0] != 1) || (buf[1] != DS2477_88_RES_SUCCESS)) { return -EIO; } return 0; } int ds2477_85_reset_bus(const struct device *dev) { const struct w1_ds2477_85_config *cfg = dev->config; struct w1_ds2477_85_data *data = dev->data; uint16_t delay_us = cfg->mode_timing[data->master_reg.od_active].t_reset; uint8_t tx_data; uint8_t rx_data; int ret; tx_data = data->master_reg.od_active ? BIT(3) : BIT(7); ret = cfg->w1_script_cmd(dev, delay_us, SCRIPT_OW_RESET, &tx_data, 1, &rx_data, 1); switch (ret) { case DS2477_88_RES_COMM_FAILURE: /* presence not detected */ return 0; case DS2477_88_RES_SUCCESS: /* at least 1 device present */ return 1; default: return -EIO; } } int ds2477_85_read_bit(const struct device *dev) { const struct w1_ds2477_85_config *cfg = dev->config; struct w1_ds2477_85_data *data = dev->data; uint16_t delay_us = cfg->mode_timing[data->master_reg.od_active].t_slot; uint8_t rx_data; int ret; ret = cfg->w1_script_cmd(dev, delay_us, SCRIPT_OW_READ_BIT, NULL, 0, &rx_data, 1); if (ret != DS2477_88_RES_SUCCESS) { return -EIO; } return (rx_data & BIT(5)) ? 1 : 0; } int ds2477_85_write_bit(const struct device *dev, const bool bit) { const struct w1_ds2477_85_config *cfg = dev->config; struct w1_ds2477_85_data *data = dev->data; uint16_t delay_us = cfg->mode_timing[data->master_reg.od_active].t_slot; uint8_t tx_data = (uint8_t)bit; uint8_t rx_data; int ret; ret = cfg->w1_script_cmd(dev, delay_us, SCRIPT_OW_WRITE_BIT, &tx_data, 1, &rx_data, 1); if (ret != DS2477_88_RES_SUCCESS) { return -EIO; } return 0; } int ds2477_85_read_byte(const struct device *dev) { const struct w1_ds2477_85_config *cfg = dev->config; struct w1_ds2477_85_data *data = dev->data; uint16_t delay_us = cfg->mode_timing[data->master_reg.od_active].t_slot * 8; uint8_t rx_data; int ret; ret = cfg->w1_script_cmd(dev, delay_us, SCRIPT_OW_READ_BYTE, NULL, 0, &rx_data, 1); if (ret != DS2477_88_RES_SUCCESS) { return -EIO; } return rx_data; } int ds2477_85_write_byte(const struct device *dev, const uint8_t tx_byte) { const struct w1_ds2477_85_config *cfg = dev->config; struct w1_ds2477_85_data *data = dev->data; uint16_t delay_us = cfg->mode_timing[data->master_reg.od_active].t_slot * 8; uint8_t rx_data; int ret; ret = cfg->w1_script_cmd(dev, delay_us, SCRIPT_OW_WRITE_BYTE, &tx_byte, 1, &rx_data, 1); if (ret != DS2477_88_RES_SUCCESS) { return -EIO; } return 0; } int ds2477_85_write_block(const struct device *dev, const uint8_t *buffer, size_t tx_len) { const struct w1_ds2477_85_config *cfg = dev->config; struct w1_ds2477_85_data *data = dev->data; int w1_timing = cfg->mode_timing[data->master_reg.od_active].t_slot * 8 * tx_len; uint8_t buf[3] = {CMD_WR_BLOCK, (tx_len + CMD_WR_BLOCK_LEN), 0}; struct i2c_msg tx_msg[2] = { {.buf = buf, .len = (CMD_WR_BLOCK_LEN + CMD_OVERHEAD_LEN), .flags = I2C_MSG_WRITE}, {.buf = (uint8_t *)buffer, .len = tx_len, .flags = (I2C_MSG_WRITE | I2C_MSG_STOP)}, }; int ret; __ASSERT_NO_MSG(tx_len <= MAX_BLOCK_LEN); if (tx_len == 0) { return 0; } ret = i2c_transfer_dt(&cfg->i2c_spec, tx_msg, 2); if (ret < 0) { LOG_ERR("write block fail: %x", ret); return ret; } k_usleep(cfg->t_op_us + (cfg->t_seq_us * tx_len) + w1_timing); ret = i2c_read_dt(&cfg->i2c_spec, buf, 2); if (ret < 0) { return ret; } if ((buf[0] != 1) || (buf[1] != DS2477_88_RES_SUCCESS)) { return -EIO; } return 0; } int ds2477_85_read_block(const struct device *dev, uint8_t *buffer, size_t rx_len) { const struct w1_ds2477_85_config *cfg = dev->config; struct w1_ds2477_85_data *data = dev->data; int w1_timing = cfg->mode_timing[data->master_reg.od_active].t_slot * 8 * rx_len; uint8_t buf[3] = {CMD_RD_BLOCK, CMD_RD_BLOCK_LEN, rx_len}; struct i2c_msg rx_msg[2] = { {.buf = buf, .len = 2, .flags = I2C_MSG_READ}, {.buf = buffer, .len = rx_len, .flags = (I2C_MSG_READ | I2C_MSG_STOP)} }; int ret; __ASSERT_NO_MSG(rx_len <= MAX_BLOCK_LEN); if (rx_len == 0) { return 0; } ret = i2c_write_dt(&cfg->i2c_spec, buf, (CMD_RD_BLOCK_LEN + CMD_OVERHEAD_LEN)); if (ret < 0) { LOG_ERR("read block fail: %x", ret); return ret; } k_usleep(cfg->t_op_us + (cfg->t_seq_us * rx_len) + w1_timing); ret = i2c_transfer_dt(&cfg->i2c_spec, rx_msg, 2); if (ret < 0) { return ret; } if (buf[1] != DS2477_88_RES_SUCCESS) { return -EIO; } return 0; } int ds2477_85_configure(const struct device *dev, enum w1_settings_type type, uint32_t value) { struct w1_ds2477_85_data *data = dev->data; switch (type) { case W1_SETTING_SPEED: __ASSERT_NO_MSG(value <= 1); data->master_reg.od_active = value; break; default: return -EINVAL; } return ds2477_85_write_port_config(dev, PORT_REG_MASTER_CONFIGURATION, data->master_reg.value); } int w1_ds2477_85_init(const struct device *dev) { const struct w1_ds2477_85_config *cfg = dev->config; struct w1_ds2477_85_data *data = dev->data; data->master_reg.apu = cfg->apu; if (ds2477_85_write_port_config(dev, PORT_REG_MASTER_CONFIGURATION, data->master_reg.value) < 0) { return -EIO; } if (ds2477_85_write_port_config(dev, PORT_REG_RPUP_BUF, cfg->rpup_buf) < 0) { return -EIO; } if (ds2477_85_write_port_config(dev, PORT_REG_PDSLEW, cfg->pdslew) < 0) { return -EIO; } LOG_DBG("cfg: rpup_buf=%02x, pdslew:%02x", cfg->rpup_buf, cfg->pdslew); /* RPUP/BUF configuration is applied after a bus reset */ (void)ds2477_85_reset_bus(dev); LOG_DBG("w1-ds2477/85 init; %d slave devices", cfg->master_config.slave_count); return 0; }