drivers/w1: driver for ds2485 1-Wire master
This commit introduces the 1-wire master driver for maxim ds2485. The ds2485 master has nearly the same (1-wire) feature set and i2c-interface as the ds2477. Therefore the common parts are extracted, but to avoid any nda troubles only the ds2485 specific part is included. Compared to older 1-wire masters, the ds2485 supports higher level commands, supporting multi byte operations, search next, automatic crc calculation. In this driver only basic read and write operations are supported, further hardware features are not yet utilized by the driver. Signed-off-by: Thomas Stranger <thomas.stranger@outlook.com>
This commit is contained in:
parent
f8d2226d58
commit
81bf4f98f7
9 changed files with 833 additions and 0 deletions
|
|
@ -8,6 +8,8 @@ zephyr_library_sources(w1_common.c)
|
|||
|
||||
# drivers implementing link functions (read, write, reset)
|
||||
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_TEST w1_test.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_W1_ZEPHYR_SERIAL w1_zephyr_serial.c)
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ config W1_SHELL_BUFFER_SIZE
|
|||
sure to also increase SHELL_ARGC_MAX accordingly.
|
||||
|
||||
rsource "Kconfig.ds2484"
|
||||
rsource "Kconfig.ds2477_85"
|
||||
rsource "Kconfig.ds2485"
|
||||
rsource "Kconfig.test"
|
||||
rsource "Kconfig.zephyr_serial"
|
||||
|
||||
|
|
|
|||
9
drivers/w1/Kconfig.ds2477_85
Normal file
9
drivers/w1/Kconfig.ds2477_85
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Common configuration options for DS2477 and DS2485 1-Wire master drivers
|
||||
|
||||
# Copyright (c) 2022 Thomas Stranger
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config W1_DS2477_85_COMMON
|
||||
bool
|
||||
help
|
||||
This enables support for the shared ds2477/85 1-Wire driver.
|
||||
13
drivers/w1/Kconfig.ds2485
Normal file
13
drivers/w1/Kconfig.ds2485
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Configuration options for the Zephyr DS2485 1-Wire master driver
|
||||
|
||||
# Copyright (c) 2022 Thomas Stranger
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config W1_DS2485
|
||||
bool "DS2485 1-wire master driver"
|
||||
select I2C
|
||||
depends on DT_HAS_MAXIM_DS2485_ENABLED
|
||||
select W1_DS2477_85_COMMON
|
||||
default y
|
||||
help
|
||||
Enable the ds2485 w1 master driver.
|
||||
309
drivers/w1/w1_ds2477_85_common.c
Normal file
309
drivers/w1/w1_ds2477_85_common.c
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* 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 <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/w1.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
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;
|
||||
}
|
||||
279
drivers/w1/w1_ds2477_85_common.h
Normal file
279
drivers/w1/w1_ds2477_85_common.h
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Thomas Stranger
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_W1_DS2477_DS2485_COMMON_H_
|
||||
#define ZEPHYR_DRIVERS_W1_DS2477_DS2485_COMMON_H_
|
||||
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/w1.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
/* memory specific commands */
|
||||
#define CMD_WR_MEM 0x96
|
||||
#define CMD_RD_MEM 0x44
|
||||
#define CMD_SET_PAGE_PROTECT 0xc3
|
||||
#define CMD_RD_STATUS 0xaa
|
||||
/* configuration specific commands */
|
||||
#define CMD_SET_I2C_ADDR 0x75
|
||||
#define CMD_RD_W1_PORT_CFG 0x52
|
||||
#define CMD_WR_W1_PORT_CFG 0x99
|
||||
#define CMD_MASTER_RESET 0x62
|
||||
/* 1-Wire specific commands */
|
||||
#define CMD_W1_SCRIPT 0x88
|
||||
#define CMD_W1_BLOCK 0xab
|
||||
#define CMD_RD_BLOCK 0x50
|
||||
#define CMD_WR_BLOCK 0x68
|
||||
#define CMD_SEARCH 0x11
|
||||
#define CMD_FULL_CMD_SEQ 0x57
|
||||
/* crc16 specific commands */
|
||||
#define CMD_COMPUTE_CRC 0xcc
|
||||
|
||||
/* i2c command overhead len */
|
||||
#define CMD_OVERHEAD_LEN 2U
|
||||
/* memory specific commands' data length */
|
||||
#define CMD_WR_MEM_LEN 33U
|
||||
#define CMD_RD_MEM_LEN 1U
|
||||
#define CMD_SET_PAGE_PROTECT_LEN 2U
|
||||
#define CMD_RD_STATUS_LEN 1U
|
||||
/* configuration specific commands */
|
||||
#define CMD_SET_I2C_ADDR_LEN 1U
|
||||
#define CMD_RD_W1_PORT_CFG_LEN 1U
|
||||
#define CMD_WR_W1_PORT_CFG_LEN 3U
|
||||
/* 1-Wire specific commands */
|
||||
#define CMD_W1_SCRIPT_LEN 1U
|
||||
#define CMD_W1_BLOCK_LEN 1U
|
||||
#define CMD_RD_BLOCK_LEN 1U
|
||||
#define CMD_WR_BLOCK_LEN 1U
|
||||
#define CMD_SEARCH_LEN 2U
|
||||
#define CMD_FULL_CMD_SEQ_LEN 9U
|
||||
/* crc16 specific commands */
|
||||
#define CMD_COMPUTE_CRC_LEN 1U
|
||||
|
||||
/* I2C communication result bytes */
|
||||
#define DS2477_88_RES_SUCCESS 0xaa
|
||||
#define DS2477_88_RES_INVALID_PARAM 0x77
|
||||
#define DS2477_88_RES_COMM_FAILURE 0x22
|
||||
#define DS2477_88_RES_RESET_FAILURE 0x22
|
||||
#define DS2477_88_RES_NO_PRESENCE 0x33
|
||||
#define DS2477_88_RES_WP_FAILURE 0x55
|
||||
|
||||
/* primitive commands, executable via the script command */
|
||||
#define SCRIPT_OW_RESET 0x00
|
||||
#define SCRIPT_OW_WRITE_BIT 0x01
|
||||
#define SCRIPT_OW_READ_BIT 0x02
|
||||
#define SCRIPT_OW_WRITE_BYTE 0x03
|
||||
#define SCRIPT_OW_READ_BYTE 0x04
|
||||
#define SCRIPT_OW_TRIPLET 0x05
|
||||
#define SCRIPT_OW_OV_SKIP 0x06
|
||||
#define SCRIPT_OW_SKIP 0x07
|
||||
#define SCRIPT_OW_READ_BLOCK 0x08
|
||||
#define SCRIPT_OW_WRITE_BLOCK 0x09
|
||||
#define SCRIPT_OW_DELAY 0x0a
|
||||
#define SCRIPT_OW_PRIME_SPU 0x0b
|
||||
#define SCRIPT_OW_SPU_OFF 0x0c
|
||||
#define SCRIPT_OW_SPEED 0x0d
|
||||
|
||||
/* port configuration register offsets */
|
||||
#define PORT_REG_MASTER_CONFIGURATION 0x00
|
||||
#define PORT_REG_STANDARD_SPEED_T_RSTL 0x01
|
||||
#define PORT_REG_STANDARD_SPEED_T_MSI 0x02
|
||||
#define PORT_REG_STANDARD_SPEED_T_MSP 0x03
|
||||
#define PORT_REG_STANDARD_SPEED_T_RSTH 0x04
|
||||
#define PORT_REG_STANDARD_SPEED_T_W0L 0x05
|
||||
#define PORT_REG_STANDARD_SPEED_T_W1L 0x06
|
||||
#define PORT_REG_STANDARD_SPEED_T_MSR 0x07
|
||||
#define PORT_REG_STANDARD_SPEED_T_REC 0x08
|
||||
#define PORT_REG_OVERDRIVE_SPEED_T_RSTL 0x09
|
||||
#define PORT_REG_OVERDRIVE_SPEED_T_MSI 0x0a
|
||||
#define PORT_REG_OVERDRIVE_SPEED_T_MSP 0x0b
|
||||
#define PORT_REG_OVERDRIVE_SPEED_T_RSTH 0x0c
|
||||
#define PORT_REG_OVERDRIVE_SPEED_T_W0L 0x0d
|
||||
#define PORT_REG_OVERDRIVE_SPEED_T_W1L 0x0e
|
||||
#define PORT_REG_OVERDRIVE_SPEED_T_MSR 0x0f
|
||||
#define PORT_REG_OVERDRIVE_SPEED_T_REC 0x10
|
||||
#define PORT_REG_RPUP_BUF 0x11
|
||||
#define PORT_REG_PDSLEW 0x12
|
||||
#define PORT_REG_COUNT 0x13
|
||||
|
||||
/* upper limit of 1-wire command length supported(in bytes) */
|
||||
#define MAX_BLOCK_LEN 126U
|
||||
/* limit of 1-wire command len is 126 bytes, but currently not used: */
|
||||
#define SCRIPT_WR_LEN 1U
|
||||
|
||||
/* variant independent timing */
|
||||
#define DS2477_85_T_RM_us 50000U
|
||||
#define DS2477_85_T_WM_us 100000U
|
||||
#define DS2477_85_T_WS_us 15000U
|
||||
|
||||
/* default 1-wire timing parameters (cfg. value==6) */
|
||||
#define DS2477_85_STD_SPD_T_RSTL_us 560U
|
||||
#define DS2477_85_STD_SPD_T_MSI_us 7U
|
||||
#define DS2477_85_STD_SPD_T_MSP_us 68U
|
||||
#define DS2477_85_STD_SPD_T_RSTH_us 560U
|
||||
#define DS2477_85_STD_SPD_T_W0L_us 68U
|
||||
#define DS2477_85_STD_SPD_T_W1L_us 8U
|
||||
#define DS2477_85_STD_SPD_T_MSR_us 12U
|
||||
#define DS2477_85_STD_SPD_T_REC_us 6U
|
||||
|
||||
#define DS2477_85_OVD_SPD_T_RSTL_us 56U
|
||||
#define DS2477_85_OVD_SPD_T_MSI_us 2U
|
||||
#define DS2477_85_OVD_SPD_T_MSP_us 8U
|
||||
#define DS2477_85_OVD_SPD_T_RSTH_us 56U
|
||||
#define DS2477_85_OVD_SPD_T_W0L_us 8U
|
||||
#define DS2477_85_OVD_SPD_T_W1L_us 1U
|
||||
#define DS2477_85_OVD_SPD_T_MSR_us 2U
|
||||
#define DS2477_85_OVD_SPD_T_REC_us 6U
|
||||
|
||||
#define DS2477_85_STD_SPD_T_SLOT_us \
|
||||
(DS2477_85_STD_SPD_T_W0L_us + DS2477_85_STD_SPD_T_REC_us)
|
||||
#define DS2477_85_STD_SPD_T_RESET_us \
|
||||
(DS2477_85_STD_SPD_T_RSTL_us + DS2477_85_STD_SPD_T_RSTH_us)
|
||||
|
||||
#define DS2477_85_OVD_SPD_T_SLOT_us \
|
||||
(DS2477_85_OVD_SPD_T_W0L_us + DS2477_85_OVD_SPD_T_REC_us)
|
||||
#define DS2477_85_OVD_SPD_T_RESET_us \
|
||||
(DS2477_85_OVD_SPD_T_RSTL_us + DS2477_85_OVD_SPD_T_RSTH_us)
|
||||
|
||||
/* defines for DTS switching-th, active-pull-th and weak-pullup enums */
|
||||
#define RPUP_BUF_CUSTOM BIT(15)
|
||||
|
||||
#define RPUP_BUF_SW_TH_Msk GENMASK(5, 4)
|
||||
#define RPUP_BUF_SW_TH_PREP(x) FIELD_PREP(RPUP_BUF_SW_TH_Msk, x)
|
||||
#define RPUP_BUF_SW_TH_LOW RPUP_BUF_SW_TH_PREP(0)
|
||||
#define RPUP_BUF_SW_TH_MEDIUM RPUP_BUF_SW_TH_PREP(1)
|
||||
#define RPUP_BUF_SW_TH_HIGH RPUP_BUF_SW_TH_PREP(2)
|
||||
#define RPUP_BUF_SW_TH_OFF RPUP_BUF_SW_TH_PREP(3)
|
||||
#define RPUP_BUF_APULL_TH_Msk GENMASK(3, 2)
|
||||
#define RPUP_BUF_APULL_TH_PREP(x) FIELD_PREP(RPUP_BUF_APULL_TH_Msk, x)
|
||||
#define RPUP_BUF_APULL_TH_LOW RPUP_BUF_APULL_TH_PREP(0)
|
||||
#define RPUP_BUF_APULL_TH_MEDIUM RPUP_BUF_APULL_TH_PREP(1)
|
||||
#define RPUP_BUF_APULL_TH_HIGH RPUP_BUF_APULL_TH_PREP(2)
|
||||
#define RPUP_BUF_APULL_TH_OFF RPUP_BUF_APULL_TH_PREP(3)
|
||||
#define RPUP_BUF_WPULL_Msk GENMASK(1, 0)
|
||||
#define RPUP_BUF_WPULL_PREP(x) FIELD_PREP(RPUP_BUF_WPULL_Msk, x)
|
||||
#define RPUP_BUF_WPULL_EXTERN RPUP_BUF_WPULL_PREP(0)
|
||||
#define RPUP_BUF_WPULL_500 RPUP_BUF_WPULL_PREP(1)
|
||||
#define RPUP_BUF_WPULL_1000 RPUP_BUF_WPULL_PREP(2)
|
||||
#define RPUP_BUF_WPULL_333 RPUP_BUF_WPULL_PREP(3)
|
||||
|
||||
/* defines for standard and overdrive slew enums */
|
||||
#define PDSLEW_CUSTOM BIT(15)
|
||||
#define PDSLEW_STD_Msk GENMASK(5, 3)
|
||||
#define PDSLEW_STD_PREP(x) FIELD_PREP(PDSLEW_STD_Msk, BIT(x))
|
||||
#define PDSLEW_STD_50 PDSLEW_STD_PREP(0)
|
||||
#define PDSLEW_STD_150 PDSLEW_STD_PREP(1)
|
||||
#define PDSLEW_STD_1300 PDSLEW_STD_PREP(2)
|
||||
#define PDSLEW_OVD_Msk GENMASK(2, 0)
|
||||
#define PDSLEW_OVD_PREP(x) FIELD_PREP(PDSLEW_OVD_Msk, BIT(x))
|
||||
#define PDSLEW_OVD_50 PDSLEW_OVD_PREP(0)
|
||||
#define PDSLEW_OVD_150 PDSLEW_OVD_PREP(1)
|
||||
|
||||
/* speed mode dependent timing parameters */
|
||||
struct mode_timing {
|
||||
uint16_t t_slot;
|
||||
uint16_t t_reset;
|
||||
};
|
||||
|
||||
union master_config_reg {
|
||||
struct {
|
||||
uint16_t res : 12;
|
||||
uint16_t apu : 1;
|
||||
uint16_t spu : 1;
|
||||
uint16_t pdn : 1;
|
||||
uint16_t od_active : 1;
|
||||
};
|
||||
uint16_t value;
|
||||
};
|
||||
|
||||
typedef int (*variant_w1_script_cmd_fn)(const struct device *dev,
|
||||
int w1_delay_us, uint8_t w1_cmd,
|
||||
const uint8_t *tx_buf,
|
||||
const uint8_t tx_len, uint8_t *rx_buf,
|
||||
uint8_t rx_len);
|
||||
|
||||
struct w1_ds2477_85_config {
|
||||
/** w1 master config, common to all drivers */
|
||||
struct w1_master_config master_config;
|
||||
/** I2C device */
|
||||
const struct i2c_dt_spec i2c_spec;
|
||||
/** config reg of weak pullup, active pullup, and switch threshold */
|
||||
uint16_t rpup_buf;
|
||||
/** config reg of standard and overdrive slew */
|
||||
uint16_t pdslew;
|
||||
/** mode dependent timing parameters (@0: standard, @1: overdrive) */
|
||||
struct mode_timing mode_timing[2];
|
||||
/** variant dependent time of 1 operation in us */
|
||||
uint16_t t_op_us;
|
||||
/** variant dependent time of 1 sequence in us */
|
||||
uint16_t t_seq_us;
|
||||
/** variant specific script command */
|
||||
variant_w1_script_cmd_fn w1_script_cmd;
|
||||
/** indicates enable active pull-up configuration */
|
||||
bool apu;
|
||||
};
|
||||
|
||||
struct w1_ds2477_85_data {
|
||||
/** w1 master data, common to all drivers */
|
||||
struct w1_master_data master_data;
|
||||
/** master specific runtime configuration */
|
||||
union master_config_reg master_reg;
|
||||
};
|
||||
|
||||
#define W1_DS2477_85_DT_CONFIG_GET(node_id, _t_op, _t_seq, _script_cmd) \
|
||||
{ \
|
||||
.i2c_spec = I2C_DT_SPEC_GET(node_id), \
|
||||
.master_config.slave_count = \
|
||||
W1_SLAVE_COUNT(node_id), \
|
||||
.rpup_buf = RPUP_BUF_CUSTOM | \
|
||||
RPUP_BUF_SW_TH_PREP(DT_ENUM_IDX(node_id, \
|
||||
switching_threshold)) | \
|
||||
RPUP_BUF_APULL_TH_PREP(DT_ENUM_IDX(node_id, \
|
||||
active_pull_threshold)) | \
|
||||
RPUP_BUF_WPULL_PREP(DT_ENUM_IDX(node_id, weak_pullup)),\
|
||||
.pdslew = PDSLEW_CUSTOM | \
|
||||
PDSLEW_STD_PREP(DT_ENUM_IDX(node_id, \
|
||||
standard_slew)) | \
|
||||
PDSLEW_OVD_PREP(DT_ENUM_IDX(node_id, \
|
||||
overdrive_slew)), \
|
||||
.apu = DT_PROP(node_id, active_pullup), \
|
||||
.mode_timing = { \
|
||||
{ \
|
||||
.t_slot = DS2477_85_STD_SPD_T_SLOT_us, \
|
||||
.t_reset = DS2477_85_STD_SPD_T_RESET_us, \
|
||||
}, \
|
||||
{ \
|
||||
.t_slot = DS2477_85_OVD_SPD_T_SLOT_us, \
|
||||
.t_reset = DS2477_85_OVD_SPD_T_RESET_us, \
|
||||
}, \
|
||||
}, \
|
||||
.t_op_us = _t_op, \
|
||||
.t_seq_us = _t_seq, \
|
||||
.w1_script_cmd = _script_cmd, \
|
||||
}
|
||||
|
||||
#define W1_DS2477_85_DT_CONFIG_INST_GET(inst, _t_op, _t_seq, _script_cmd) \
|
||||
W1_DS2477_85_DT_CONFIG_GET(DT_DRV_INST(inst), _t_op, _t_seq, \
|
||||
_script_cmd)
|
||||
|
||||
int w1_ds2477_85_init(const struct device *dev);
|
||||
int ds2477_85_write_port_config(const struct device *dev, uint8_t reg,
|
||||
uint16_t value);
|
||||
int ds2477_85_read_port_config(const struct device *dev, uint8_t reg,
|
||||
uint16_t *value);
|
||||
int ds2477_85_reset_master(const struct device *dev);
|
||||
int ds2477_85_reset_bus(const struct device *dev);
|
||||
int ds2477_85_read_bit(const struct device *dev);
|
||||
int ds2477_85_write_bit(const struct device *dev, const bool bit);
|
||||
int ds2477_85_read_byte(const struct device *dev);
|
||||
int ds2477_85_write_byte(const struct device *dev, const uint8_t tx_byte);
|
||||
int ds2477_85_write_block(const struct device *dev, const uint8_t *buffer,
|
||||
size_t tx_len);
|
||||
int ds2477_85_read_block(const struct device *dev, uint8_t *buffer,
|
||||
size_t rx_len);
|
||||
int ds2477_85_configure(const struct device *dev, enum w1_settings_type type,
|
||||
uint32_t value);
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_W1_DS2477_DS2485_COMMON_H_ */
|
||||
115
drivers/w1/w1_ds2485.c
Normal file
115
drivers/w1/w1_ds2485.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Thomas Stranger
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT maxim_ds2485
|
||||
|
||||
/**
|
||||
* @brief Driver for the Maxim ds2485 1-Wire Master
|
||||
*/
|
||||
|
||||
#include "w1_ds2477_85_common.h"
|
||||
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/w1.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(w1_ds2485, CONFIG_W1_LOG_LEVEL);
|
||||
|
||||
/* upper limits; guaranteed over operating temperature range */
|
||||
#define DS2485_T_OSCWUP_us 1000U
|
||||
#define DS2485_T_OP_us 400U
|
||||
#define DS2485_T_SEQ_us 10U
|
||||
|
||||
int ds2485_w1_script_cmd(const struct device *dev, int w1_delay_us, uint8_t w1_cmd,
|
||||
const uint8_t *tx_buf, const uint8_t tx_len,
|
||||
uint8_t *rx_buf, uint8_t rx_len)
|
||||
{
|
||||
const struct w1_ds2477_85_config *cfg = dev->config;
|
||||
uint8_t i2c_len = 3 + tx_len;
|
||||
uint8_t tx_bytes[3 + SCRIPT_WR_LEN] = {
|
||||
CMD_W1_SCRIPT, tx_len + CMD_W1_SCRIPT_LEN, w1_cmd
|
||||
};
|
||||
uint8_t rx_bytes[3];
|
||||
struct i2c_msg rx_msg[2] = {
|
||||
{
|
||||
.buf = rx_bytes,
|
||||
.len = (CMD_W1_SCRIPT_LEN + CMD_OVERHEAD_LEN),
|
||||
.flags = I2C_MSG_READ,
|
||||
},
|
||||
{
|
||||
.buf = rx_buf,
|
||||
.len = rx_len,
|
||||
.flags = (I2C_MSG_READ | I2C_MSG_STOP),
|
||||
},
|
||||
};
|
||||
int ret;
|
||||
|
||||
__ASSERT_NO_MSG(tx_len <= SCRIPT_WR_LEN);
|
||||
memcpy(&tx_bytes[3], tx_buf, tx_len);
|
||||
ret = i2c_write_dt(&cfg->i2c_spec, tx_bytes, i2c_len);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
k_usleep(DS2485_T_OP_us + DS2485_T_SEQ_us + w1_delay_us);
|
||||
|
||||
ret = i2c_transfer_dt(&cfg->i2c_spec, rx_msg, 2);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("scripts_cmd fail: ret: %x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((rx_bytes[0] != (rx_len + 2)) || (rx_bytes[2] != w1_cmd)) {
|
||||
LOG_ERR("scripts_cmd fail: response: %x,%x:",
|
||||
rx_bytes[0], rx_bytes[2]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return rx_bytes[1];
|
||||
}
|
||||
|
||||
static int w1_ds2485_init(const struct device *dev)
|
||||
{
|
||||
const struct w1_ds2477_85_config *cfg = dev->config;
|
||||
|
||||
if (!device_is_ready(cfg->i2c_spec.bus)) {
|
||||
LOG_ERR("%s is not ready", cfg->i2c_spec.bus->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (ds2477_85_reset_master(dev)) {
|
||||
return -EIO;
|
||||
}
|
||||
k_usleep(DS2485_T_OSCWUP_us);
|
||||
|
||||
return w1_ds2477_85_init(dev);
|
||||
}
|
||||
|
||||
static const struct w1_driver_api w1_ds2485_driver_api = {
|
||||
.reset_bus = ds2477_85_reset_bus,
|
||||
.read_bit = ds2477_85_read_bit,
|
||||
.write_bit = ds2477_85_write_bit,
|
||||
.read_byte = ds2477_85_read_byte,
|
||||
.write_byte = ds2477_85_write_byte,
|
||||
.read_block = ds2477_85_read_block,
|
||||
.write_block = ds2477_85_write_block,
|
||||
.configure = ds2477_85_configure,
|
||||
};
|
||||
|
||||
#define W1_DS2485_INIT(inst) \
|
||||
static const struct w1_ds2477_85_config w1_ds2477_85_cfg_##inst = \
|
||||
W1_DS2477_85_DT_CONFIG_INST_GET(inst, DS2485_T_OP_us, \
|
||||
DS2485_T_SEQ_us, \
|
||||
ds2485_w1_script_cmd); \
|
||||
\
|
||||
static struct w1_ds2477_85_data w1_ds2477_85_data_##inst = {}; \
|
||||
DEVICE_DT_INST_DEFINE(inst, &w1_ds2485_init, NULL, \
|
||||
&w1_ds2477_85_data_##inst, \
|
||||
&w1_ds2477_85_cfg_##inst, POST_KERNEL, \
|
||||
CONFIG_W1_INIT_PRIORITY, &w1_ds2485_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(W1_DS2485_INIT)
|
||||
93
dts/bindings/w1/maxim,ds2477_85_common.yaml
Normal file
93
dts/bindings/w1/maxim,ds2477_85_common.yaml
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# Copyright (c) 2022 Thomas Stranger
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Common Properties for the DS2477 and DS2485 I2C 1-Wire masters:
|
||||
|
||||
include: [w1-master.yaml, i2c-device.yaml]
|
||||
|
||||
properties:
|
||||
switching-threshold:
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- "low"
|
||||
- "medium"
|
||||
- "high"
|
||||
- "off"
|
||||
description: |
|
||||
Default Low-to-High Switching Threshold.
|
||||
|
||||
Only the following values are allowed:
|
||||
low: 0.25 x VCC, no hysteresis
|
||||
medium: 0.40 x VCC, no hysteresis (recommended for most configurations)
|
||||
high: 0.75 x VCC, with hysteresis
|
||||
off: off (chip reset value)
|
||||
|
||||
active-pull-threshold:
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- "low"
|
||||
- "medium"
|
||||
- "high"
|
||||
- "off"
|
||||
description: |
|
||||
Default Active Pullup on Threshold configuration.
|
||||
For configurations with a single slave a "low" active pull
|
||||
threshold is recommended.
|
||||
|
||||
Only the following values are allowed:
|
||||
low: 0.25 x VCC (recommended for most configurations)
|
||||
medium: 0.40 x VCC
|
||||
high: 0.75 x VCC
|
||||
off: off (chip reset value)
|
||||
|
||||
weak-pullup:
|
||||
type: string
|
||||
required: true
|
||||
enum:
|
||||
- "extern"
|
||||
- "500"
|
||||
- "1000"
|
||||
- "333"
|
||||
description: |
|
||||
Default 1-Wire Weak Pullup Resistance in ohms.
|
||||
For most configurations with a single slave "1000" ohms are recommended,
|
||||
but some devices and multidrop configurations might need a stronger pullup.
|
||||
|
||||
To enter floating condition, it is suggested to switch the weak-pull up
|
||||
to extern and disable the switching as well as the active-pull threshold.
|
||||
|
||||
Only the following values are allowed:
|
||||
"extern" (chip reset value)
|
||||
"500"
|
||||
"1000" (recommended for most configurations)
|
||||
"333"
|
||||
|
||||
standard-slew:
|
||||
type: int
|
||||
required: false
|
||||
default: 150
|
||||
enum:
|
||||
- 50
|
||||
- 150
|
||||
- 1300
|
||||
description: |
|
||||
Default slew for standard speed mode in ns. Only the following values are
|
||||
allowed:
|
||||
50
|
||||
150 (default; chip reset value)
|
||||
1300
|
||||
|
||||
overdrive-slew:
|
||||
type: int
|
||||
required: false
|
||||
default: 50
|
||||
enum:
|
||||
- 50
|
||||
- 150
|
||||
description: |
|
||||
Default slew for overdrive speed mode in ns. Only the following values are
|
||||
allowed:
|
||||
50 (default; chip reset value)
|
||||
150
|
||||
11
dts/bindings/w1/maxim,ds2485.yaml
Normal file
11
dts/bindings/w1/maxim,ds2485.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Copyright (c) 2022 Thomas Stranger
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Properties for the DS2485 I2C 1-Wire master with memory driver:
|
||||
|
||||
description: |
|
||||
This is a representation of the Maxim DS2485 I2C 1-Wire master w/ memory
|
||||
|
||||
compatible: "maxim,ds2485"
|
||||
|
||||
include: ["maxim,ds2477_85_common.yaml", "i2c-device.yaml"]
|
||||
Loading…
Reference in a new issue