1 /*
2  * Copyright (c) 2022 Thomas Stranger
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT maxim_ds2485
8 
9 /**
10  * @brief Driver for the Analog Devices DS2485 1-Wire Master
11  */
12 
13 #include "w1_ds2477_85_common.h"
14 
15 #include <zephyr/drivers/i2c.h>
16 #include <zephyr/drivers/w1.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/logging/log.h>
19 
20 LOG_MODULE_REGISTER(w1_ds2485, CONFIG_W1_LOG_LEVEL);
21 
22 /* upper limits; guaranteed over operating temperature range */
23 #define DS2485_T_OSCWUP_us 1000U
24 #define DS2485_T_OP_us	   400U
25 #define DS2485_T_SEQ_us	   10U
26 
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)27 int ds2485_w1_script_cmd(const struct device *dev, int w1_delay_us, uint8_t w1_cmd,
28 			 const uint8_t *tx_buf, const uint8_t tx_len,
29 			 uint8_t *rx_buf, uint8_t rx_len)
30 {
31 	const struct w1_ds2477_85_config *cfg = dev->config;
32 	uint8_t i2c_len = 3 + tx_len;
33 	uint8_t tx_bytes[3 + SCRIPT_WR_LEN] = {
34 		CMD_W1_SCRIPT, tx_len + CMD_W1_SCRIPT_LEN, w1_cmd
35 	};
36 	uint8_t rx_bytes[3];
37 	struct i2c_msg rx_msg[2] = {
38 		{
39 			.buf = rx_bytes,
40 			.len = (CMD_W1_SCRIPT_LEN + CMD_OVERHEAD_LEN),
41 			.flags = I2C_MSG_READ,
42 		},
43 		{
44 			.buf = rx_buf,
45 			.len = rx_len,
46 			.flags = (I2C_MSG_READ | I2C_MSG_STOP),
47 		},
48 	};
49 	int ret;
50 
51 	__ASSERT_NO_MSG(tx_len <= SCRIPT_WR_LEN);
52 	memcpy(&tx_bytes[3], tx_buf, tx_len);
53 	ret = i2c_write_dt(&cfg->i2c_spec, tx_bytes, i2c_len);
54 	if (ret < 0) {
55 		return ret;
56 	}
57 
58 	k_usleep(DS2485_T_OP_us + DS2485_T_SEQ_us + w1_delay_us);
59 
60 	ret = i2c_transfer_dt(&cfg->i2c_spec, rx_msg, 2);
61 	if (ret < 0) {
62 		LOG_ERR("scripts_cmd fail: ret: %x", ret);
63 		return ret;
64 	}
65 
66 	if ((rx_bytes[0] != (rx_len + 2)) || (rx_bytes[2] != w1_cmd)) {
67 		LOG_ERR("scripts_cmd fail: response: %x,%x:",
68 			rx_bytes[0], rx_bytes[2]);
69 		return -EIO;
70 	}
71 
72 	return rx_bytes[1];
73 }
74 
w1_ds2485_init(const struct device * dev)75 static int w1_ds2485_init(const struct device *dev)
76 {
77 	const struct w1_ds2477_85_config *cfg = dev->config;
78 
79 	if (!device_is_ready(cfg->i2c_spec.bus)) {
80 		LOG_ERR("%s is not ready", cfg->i2c_spec.bus->name);
81 		return -ENODEV;
82 	}
83 
84 	if (ds2477_85_reset_master(dev)) {
85 		return -EIO;
86 	}
87 	k_usleep(DS2485_T_OSCWUP_us);
88 
89 	return w1_ds2477_85_init(dev);
90 }
91 
92 static DEVICE_API(w1, w1_ds2485_driver_api) = {
93 	.reset_bus = ds2477_85_reset_bus,
94 	.read_bit = ds2477_85_read_bit,
95 	.write_bit = ds2477_85_write_bit,
96 	.read_byte = ds2477_85_read_byte,
97 	.write_byte = ds2477_85_write_byte,
98 	.read_block = ds2477_85_read_block,
99 	.write_block = ds2477_85_write_block,
100 	.configure = ds2477_85_configure,
101 };
102 
103 #define W1_DS2485_INIT(inst)                                                   \
104 	static const struct w1_ds2477_85_config w1_ds2477_85_cfg_##inst =      \
105 		W1_DS2477_85_DT_CONFIG_INST_GET(inst, DS2485_T_OP_us,          \
106 						DS2485_T_SEQ_us,               \
107 						ds2485_w1_script_cmd);         \
108 	                                                                       \
109 	static struct w1_ds2477_85_data w1_ds2477_85_data_##inst = {};         \
110 	DEVICE_DT_INST_DEFINE(inst, &w1_ds2485_init, NULL,                     \
111 			      &w1_ds2477_85_data_##inst,                       \
112 			      &w1_ds2477_85_cfg_##inst, POST_KERNEL,           \
113 			      CONFIG_W1_INIT_PRIORITY, &w1_ds2485_driver_api);
114 
115 DT_INST_FOREACH_STATUS_OKAY(W1_DS2485_INIT)
116