Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

w1: add UART w1 bus driver

Add a UART 1-Wire bus driver. The driver utilizes the UART interface via
the Serial Device Bus to create the 1-Wire timing patterns. The driver
was tested on a "Raspberry Pi 3B" with a DS18B20 and on a "Variscite
DART-6UL" with a DS18S20 temperature sensor.

The 1-Wire timing pattern and the corresponding UART baud-rate with the
interpretation of the transferred bytes are described in the document:

Link: https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html

In short, the UART peripheral must support full-duplex and operate in
open-drain mode. The timing patterns are generated by a specific
combination of baud-rate and transmitted byte, which corresponds to a
1-Wire read bit, write bit or reset.

Signed-off-by: Christoph Winklhofer <cj.winklhofer@gmail.com>
Link: https://lore.kernel.org/r/20240214-w1-uart-v7-3-6e21fa24e066@gmail.com
[krzysztof: w1_uart_serdev_receive_buf() return type fixup]
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

authored by

Christoph Winklhofer and committed by
Krzysztof Kozlowski
a3c08804 23b33337

+481
+1
Documentation/w1/masters/index.rst
··· 12 12 mxc-w1 13 13 omap-hdq 14 14 w1-gpio 15 + w1-uart
+54
Documentation/w1/masters/w1-uart.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + ===================== 4 + Kernel driver w1-uart 5 + ===================== 6 + 7 + Author: Christoph Winklhofer <cj.winklhofer@gmail.com> 8 + 9 + 10 + Description 11 + ----------- 12 + 13 + UART 1-Wire bus driver. The driver utilizes the UART interface via the 14 + Serial Device Bus to create the 1-Wire timing patterns as described in 15 + the document `"Using a UART to Implement a 1-Wire Bus Master"`_. 16 + 17 + .. _"Using a UART to Implement a 1-Wire Bus Master": https://www.analog.com/en/technical-articles/using-a-uart-to-implement-a-1wire-bus-master.html 18 + 19 + In short, the UART peripheral must support full-duplex and operate in 20 + open-drain mode. The timing patterns are generated by a specific 21 + combination of baud-rate and transmitted byte, which corresponds to a 22 + 1-Wire read bit, write bit or reset pulse. 23 + 24 + For instance the timing pattern for a 1-Wire reset and presence detect uses 25 + the baud-rate 9600, i.e. 104.2 us per bit. The transmitted byte 0xf0 over 26 + UART (least significant bit first, start-bit low) sets the reset low time 27 + for 1-Wire to 521 us. A present 1-Wire device changes the received byte by 28 + pulling the line low, which is used by the driver to evaluate the result of 29 + the 1-Wire operation. 30 + 31 + Similar for a 1-Wire read bit or write bit, which uses the baud-rate 32 + 115200, i.e. 8.7 us per bit. The transmitted byte 0x80 is used for a 33 + Write-0 operation (low time 69.6us) and the byte 0xff for Read-0, Read-1 34 + and Write-1 (low time 8.7us). 35 + 36 + The default baud-rate for reset and presence detection is 9600 and for 37 + a 1-Wire read or write operation 115200. In case the actual baud-rate 38 + is different from the requested one, the transmitted byte is adapted 39 + to generate the 1-Wire timing patterns. 40 + 41 + 42 + Usage 43 + ----- 44 + 45 + Specify the UART 1-wire bus in the device tree by adding the single child 46 + onewire to the serial node (e.g. uart0). For example: 47 + :: 48 + 49 + @uart0 { 50 + ... 51 + onewire { 52 + compatible = "w1-uart"; 53 + }; 54 + };
+10
drivers/w1/masters/Kconfig
··· 78 78 This support is also available as a module. If so, the module 79 79 will be called sgi_w1. 80 80 81 + config W1_MASTER_UART 82 + tristate "UART 1-wire driver" 83 + depends on SERIAL_DEV_BUS 84 + help 85 + Say Y here if you want to communicate with your 1-wire devices using 86 + UART interface. 87 + 88 + This support is also available as a module. If so, the module 89 + will be called w1-uart. 90 + 81 91 endmenu 82 92
+1
drivers/w1/masters/Makefile
··· 12 12 obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o 13 13 obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o 14 14 obj-$(CONFIG_W1_MASTER_SGI) += sgi_w1.o 15 + obj-$(CONFIG_W1_MASTER_UART) += w1-uart.o
+415
drivers/w1/masters/w1-uart.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * w1-uart - UART 1-Wire bus driver 4 + * 5 + * Uses the UART interface (via Serial Device Bus) to create the 1-Wire 6 + * timing patterns. Implements the following 1-Wire master interface: 7 + * 8 + * - reset_bus: requests baud-rate 9600 9 + * 10 + * - touch_bit: requests baud-rate 115200 11 + * 12 + * Author: Christoph Winklhofer <cj.winklhofer@gmail.com> 13 + */ 14 + 15 + #include <linux/completion.h> 16 + #include <linux/delay.h> 17 + #include <linux/jiffies.h> 18 + #include <linux/module.h> 19 + #include <linux/mutex.h> 20 + #include <linux/of.h> 21 + #include <linux/serdev.h> 22 + #include <linux/w1.h> 23 + 24 + /* UART packet contains start and stop bit */ 25 + #define W1_UART_BITS_PER_PACKET (BITS_PER_BYTE + 2) 26 + 27 + /* Timeout to wait for completion of serdev-receive */ 28 + #define W1_UART_TIMEOUT msecs_to_jiffies(500) 29 + 30 + /** 31 + * struct w1_uart_config - configuration for 1-Wire operation 32 + * @baudrate: baud-rate returned from serdev 33 + * @delay_us: delay to complete a 1-Wire cycle (in us) 34 + * @tx_byte: byte to generate 1-Wire timing pattern 35 + */ 36 + struct w1_uart_config { 37 + unsigned int baudrate; 38 + unsigned int delay_us; 39 + u8 tx_byte; 40 + }; 41 + 42 + /** 43 + * struct w1_uart_device - 1-Wire UART device structure 44 + * @serdev: serial device 45 + * @bus: w1-bus master 46 + * @cfg_reset: config for 1-Wire reset 47 + * @cfg_touch_0: config for 1-Wire write-0 cycle 48 + * @cfg_touch_1: config for 1-Wire write-1 and read cycle 49 + * @rx_byte_received: completion for serdev receive 50 + * @rx_mutex: mutex to protect rx_err and rx_byte 51 + * @rx_err: indicates an error in serdev-receive 52 + * @rx_byte: result byte from serdev-receive 53 + */ 54 + struct w1_uart_device { 55 + struct serdev_device *serdev; 56 + struct w1_bus_master bus; 57 + 58 + struct w1_uart_config cfg_reset; 59 + struct w1_uart_config cfg_touch_0; 60 + struct w1_uart_config cfg_touch_1; 61 + 62 + struct completion rx_byte_received; 63 + /* 64 + * protect rx_err and rx_byte from concurrent access in 65 + * w1-callbacks and serdev-receive. 66 + */ 67 + struct mutex rx_mutex; 68 + int rx_err; 69 + u8 rx_byte; 70 + }; 71 + 72 + /** 73 + * struct w1_uart_limits - limits for 1-Wire operations 74 + * @baudrate: Requested baud-rate to create 1-Wire timing pattern 75 + * @bit_min_us: minimum time for a bit (in us) 76 + * @bit_max_us: maximum time for a bit (in us) 77 + * @sample_us: timespan to sample 1-Wire response 78 + * @cycle_us: duration of the 1-Wire cycle 79 + */ 80 + struct w1_uart_limits { 81 + unsigned int baudrate; 82 + unsigned int bit_min_us; 83 + unsigned int bit_max_us; 84 + unsigned int sample_us; 85 + unsigned int cycle_us; 86 + }; 87 + 88 + static inline unsigned int baud_to_bit_ns(unsigned int baud) 89 + { 90 + return NSEC_PER_SEC / baud; 91 + } 92 + 93 + static inline unsigned int to_ns(unsigned int us) 94 + { 95 + return us * NSEC_PER_USEC; 96 + } 97 + 98 + /* 99 + * Set baud-rate, delay and tx-byte to create a 1-Wire pulse and adapt 100 + * the tx-byte according to the actual baud-rate. 101 + * 102 + * Reject when: 103 + * - time for a bit outside min/max range 104 + * - a 1-Wire response is not detectable for sent byte 105 + */ 106 + static int w1_uart_set_config(struct serdev_device *serdev, 107 + const struct w1_uart_limits *limits, 108 + struct w1_uart_config *w1cfg) 109 + { 110 + unsigned int packet_ns; 111 + unsigned int bits_low; 112 + unsigned int bit_ns; 113 + unsigned int low_ns; 114 + 115 + w1cfg->baudrate = serdev_device_set_baudrate(serdev, limits->baudrate); 116 + if (w1cfg->baudrate == 0) 117 + return -EINVAL; 118 + 119 + /* Compute in nanoseconds for accuracy */ 120 + bit_ns = baud_to_bit_ns(w1cfg->baudrate); 121 + bits_low = to_ns(limits->bit_min_us) / bit_ns; 122 + /* start bit is always low */ 123 + low_ns = bit_ns * (bits_low + 1); 124 + 125 + if (low_ns < to_ns(limits->bit_min_us)) 126 + return -EINVAL; 127 + 128 + if (low_ns > to_ns(limits->bit_max_us)) 129 + return -EINVAL; 130 + 131 + /* 1-Wire response detectable for sent byte */ 132 + if (limits->sample_us > 0 && 133 + bit_ns * BITS_PER_BYTE < low_ns + to_ns(limits->sample_us)) 134 + return -EINVAL; 135 + 136 + /* delay: 1-Wire cycle takes longer than the UART packet */ 137 + packet_ns = bit_ns * W1_UART_BITS_PER_PACKET; 138 + w1cfg->delay_us = 0; 139 + if (to_ns(limits->cycle_us) > packet_ns) 140 + w1cfg->delay_us = 141 + (to_ns(limits->cycle_us) - packet_ns) / NSEC_PER_USEC; 142 + 143 + /* byte to create 1-Wire pulse */ 144 + w1cfg->tx_byte = 0xff << bits_low; 145 + 146 + return 0; 147 + } 148 + 149 + /* 150 + * Configuration for reset and presence detect 151 + * - bit_min_us is 480us, add margin and use 485us 152 + * - limits for sample time 60us-75us, use 65us 153 + */ 154 + static int w1_uart_set_config_reset(struct w1_uart_device *w1dev) 155 + { 156 + struct serdev_device *serdev = w1dev->serdev; 157 + struct device_node *np = serdev->dev.of_node; 158 + 159 + struct w1_uart_limits limits = { .baudrate = 9600, 160 + .bit_min_us = 485, 161 + .bit_max_us = 640, 162 + .sample_us = 65, 163 + .cycle_us = 960 }; 164 + 165 + of_property_read_u32(np, "reset-bps", &limits.baudrate); 166 + 167 + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_reset); 168 + } 169 + 170 + /* 171 + * Configuration for write-0 cycle (touch bit 0) 172 + * - bit_min_us is 60us, add margin and use 65us 173 + * - no sampling required, sample_us = 0 174 + */ 175 + static int w1_uart_set_config_touch_0(struct w1_uart_device *w1dev) 176 + { 177 + struct serdev_device *serdev = w1dev->serdev; 178 + struct device_node *np = serdev->dev.of_node; 179 + 180 + struct w1_uart_limits limits = { .baudrate = 115200, 181 + .bit_min_us = 65, 182 + .bit_max_us = 120, 183 + .sample_us = 0, 184 + .cycle_us = 70 }; 185 + 186 + of_property_read_u32(np, "write-0-bps", &limits.baudrate); 187 + 188 + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_touch_0); 189 + } 190 + 191 + /* 192 + * Configuration for write-1 and read cycle (touch bit 1) 193 + * - bit_min_us is 5us, add margin and use 6us 194 + * - limits for sample time 5us-15us, use 15us 195 + */ 196 + static int w1_uart_set_config_touch_1(struct w1_uart_device *w1dev) 197 + { 198 + struct serdev_device *serdev = w1dev->serdev; 199 + struct device_node *np = serdev->dev.of_node; 200 + 201 + struct w1_uart_limits limits = { .baudrate = 115200, 202 + .bit_min_us = 6, 203 + .bit_max_us = 15, 204 + .sample_us = 15, 205 + .cycle_us = 70 }; 206 + 207 + of_property_read_u32(np, "write-1-bps", &limits.baudrate); 208 + 209 + return w1_uart_set_config(serdev, &limits, &w1dev->cfg_touch_1); 210 + } 211 + 212 + /* 213 + * Configure and open the serial device 214 + */ 215 + static int w1_uart_serdev_open(struct w1_uart_device *w1dev) 216 + { 217 + struct serdev_device *serdev = w1dev->serdev; 218 + struct device *dev = &serdev->dev; 219 + int ret; 220 + 221 + ret = devm_serdev_device_open(dev, serdev); 222 + if (ret < 0) 223 + return ret; 224 + 225 + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); 226 + if (ret < 0) { 227 + dev_err(dev, "set parity failed\n"); 228 + return ret; 229 + } 230 + 231 + ret = w1_uart_set_config_reset(w1dev); 232 + if (ret < 0) { 233 + dev_err(dev, "config for reset failed\n"); 234 + return ret; 235 + } 236 + 237 + ret = w1_uart_set_config_touch_0(w1dev); 238 + if (ret < 0) { 239 + dev_err(dev, "config for touch-0 failed\n"); 240 + return ret; 241 + } 242 + 243 + ret = w1_uart_set_config_touch_1(w1dev); 244 + if (ret < 0) { 245 + dev_err(dev, "config for touch-1 failed\n"); 246 + return ret; 247 + } 248 + 249 + serdev_device_set_flow_control(serdev, false); 250 + 251 + return 0; 252 + } 253 + 254 + /* 255 + * Send one byte (tx_byte) and read one byte (rx_byte) via serdev. 256 + */ 257 + static int w1_uart_serdev_tx_rx(struct w1_uart_device *w1dev, 258 + const struct w1_uart_config *w1cfg, u8 *rx_byte) 259 + { 260 + struct serdev_device *serdev = w1dev->serdev; 261 + int ret; 262 + 263 + serdev_device_write_flush(serdev); 264 + serdev_device_set_baudrate(serdev, w1cfg->baudrate); 265 + 266 + /* write and immediately read one byte */ 267 + reinit_completion(&w1dev->rx_byte_received); 268 + ret = serdev_device_write_buf(serdev, &w1cfg->tx_byte, 1); 269 + if (ret != 1) 270 + return -EIO; 271 + ret = wait_for_completion_interruptible_timeout( 272 + &w1dev->rx_byte_received, W1_UART_TIMEOUT); 273 + if (ret <= 0) 274 + return -EIO; 275 + 276 + /* locking could fail when serdev is unexpectedly receiving. */ 277 + if (!mutex_trylock(&w1dev->rx_mutex)) 278 + return -EIO; 279 + 280 + ret = w1dev->rx_err; 281 + if (ret == 0) 282 + *rx_byte = w1dev->rx_byte; 283 + 284 + mutex_unlock(&w1dev->rx_mutex); 285 + 286 + if (w1cfg->delay_us > 0) 287 + fsleep(w1cfg->delay_us); 288 + 289 + return ret; 290 + } 291 + 292 + static size_t w1_uart_serdev_receive_buf(struct serdev_device *serdev, 293 + const u8 *buf, size_t count) 294 + { 295 + struct w1_uart_device *w1dev = serdev_device_get_drvdata(serdev); 296 + 297 + mutex_lock(&w1dev->rx_mutex); 298 + 299 + /* sent a single byte and receive one single byte */ 300 + if (count == 1) { 301 + w1dev->rx_byte = buf[0]; 302 + w1dev->rx_err = 0; 303 + } else { 304 + w1dev->rx_err = -EIO; 305 + } 306 + 307 + mutex_unlock(&w1dev->rx_mutex); 308 + complete(&w1dev->rx_byte_received); 309 + 310 + return count; 311 + } 312 + 313 + static const struct serdev_device_ops w1_uart_serdev_ops = { 314 + .receive_buf = w1_uart_serdev_receive_buf, 315 + .write_wakeup = serdev_device_write_wakeup, 316 + }; 317 + 318 + /* 319 + * 1-wire reset and presence detect: A present slave will manipulate 320 + * the received byte by pulling the 1-Wire low. 321 + */ 322 + static u8 w1_uart_reset_bus(void *data) 323 + { 324 + struct w1_uart_device *w1dev = data; 325 + const struct w1_uart_config *w1cfg = &w1dev->cfg_reset; 326 + int ret; 327 + u8 val; 328 + 329 + ret = w1_uart_serdev_tx_rx(w1dev, w1cfg, &val); 330 + if (ret < 0) 331 + return -1; 332 + 333 + /* Device present (0) or no device (1) */ 334 + return val != w1cfg->tx_byte ? 0 : 1; 335 + } 336 + 337 + /* 338 + * 1-Wire read and write cycle: Only the read-0 manipulates the 339 + * received byte, all others left the line untouched. 340 + */ 341 + static u8 w1_uart_touch_bit(void *data, u8 bit) 342 + { 343 + struct w1_uart_device *w1dev = data; 344 + const struct w1_uart_config *w1cfg = bit ? &w1dev->cfg_touch_1 : 345 + &w1dev->cfg_touch_0; 346 + int ret; 347 + u8 val; 348 + 349 + ret = w1_uart_serdev_tx_rx(w1dev, w1cfg, &val); 350 + 351 + /* return inactive bus state on error */ 352 + if (ret < 0) 353 + return 1; 354 + 355 + return val == w1cfg->tx_byte ? 1 : 0; 356 + } 357 + 358 + static int w1_uart_probe(struct serdev_device *serdev) 359 + { 360 + struct device *dev = &serdev->dev; 361 + struct w1_uart_device *w1dev; 362 + int ret; 363 + 364 + w1dev = devm_kzalloc(dev, sizeof(*w1dev), GFP_KERNEL); 365 + if (!w1dev) 366 + return -ENOMEM; 367 + w1dev->bus.data = w1dev; 368 + w1dev->bus.reset_bus = w1_uart_reset_bus; 369 + w1dev->bus.touch_bit = w1_uart_touch_bit; 370 + w1dev->serdev = serdev; 371 + 372 + init_completion(&w1dev->rx_byte_received); 373 + mutex_init(&w1dev->rx_mutex); 374 + 375 + ret = w1_uart_serdev_open(w1dev); 376 + if (ret < 0) 377 + return ret; 378 + serdev_device_set_drvdata(serdev, w1dev); 379 + serdev_device_set_client_ops(serdev, &w1_uart_serdev_ops); 380 + 381 + return w1_add_master_device(&w1dev->bus); 382 + } 383 + 384 + static void w1_uart_remove(struct serdev_device *serdev) 385 + { 386 + struct w1_uart_device *w1dev = serdev_device_get_drvdata(serdev); 387 + 388 + /* 389 + * Waits until w1-uart callbacks are finished, serdev is closed 390 + * and its device data released automatically by devres (waits 391 + * until serdev-receive is finished). 392 + */ 393 + w1_remove_master_device(&w1dev->bus); 394 + } 395 + 396 + static const struct of_device_id w1_uart_of_match[] = { 397 + { .compatible = "w1-uart" }, 398 + {}, 399 + }; 400 + MODULE_DEVICE_TABLE(of, w1_uart_of_match); 401 + 402 + static struct serdev_device_driver w1_uart_driver = { 403 + .driver = { 404 + .name = "w1-uart", 405 + .of_match_table = w1_uart_of_match, 406 + }, 407 + .probe = w1_uart_probe, 408 + .remove = w1_uart_remove, 409 + }; 410 + 411 + module_serdev_device_driver(w1_uart_driver); 412 + 413 + MODULE_DESCRIPTION("UART w1 bus driver"); 414 + MODULE_AUTHOR("Christoph Winklhofer <cj.winklhofer@gmail.com>"); 415 + MODULE_LICENSE("GPL");