// SPDX-License-Identifier: GPL-2.0-or-later /* * w1-uart - UART 1-Wire bus driver * * Uses the UART interface (via Serial Device Bus) to create the 1-Wire * timing patterns. Implements the following 1-Wire master interface: * * - reset_bus: requests baud-rate 9600 * * - touch_bit: requests baud-rate 115200 * * Author: Christoph Winklhofer <[email protected]> */ #include <linux/completion.h> #include <linux/delay.h> #include <linux/jiffies.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/serdev.h> #include <linux/w1.h> /* UART packet contains start and stop bit */ #define W1_UART_BITS_PER_PACKET … /* Timeout to wait for completion of serdev-receive */ #define W1_UART_TIMEOUT … /** * struct w1_uart_config - configuration for 1-Wire operation * @baudrate: baud-rate returned from serdev * @delay_us: delay to complete a 1-Wire cycle (in us) * @tx_byte: byte to generate 1-Wire timing pattern */ struct w1_uart_config { … }; /** * struct w1_uart_device - 1-Wire UART device structure * @serdev: serial device * @bus: w1-bus master * @cfg_reset: config for 1-Wire reset * @cfg_touch_0: config for 1-Wire write-0 cycle * @cfg_touch_1: config for 1-Wire write-1 and read cycle * @rx_byte_received: completion for serdev receive * @rx_mutex: mutex to protect rx_err and rx_byte * @rx_err: indicates an error in serdev-receive * @rx_byte: result byte from serdev-receive */ struct w1_uart_device { … }; /** * struct w1_uart_limits - limits for 1-Wire operations * @baudrate: Requested baud-rate to create 1-Wire timing pattern * @bit_min_us: minimum time for a bit (in us) * @bit_max_us: maximum time for a bit (in us) * @sample_us: timespan to sample 1-Wire response * @cycle_us: duration of the 1-Wire cycle */ struct w1_uart_limits { … }; static inline unsigned int baud_to_bit_ns(unsigned int baud) { … } static inline unsigned int to_ns(unsigned int us) { … } /* * Set baud-rate, delay and tx-byte to create a 1-Wire pulse and adapt * the tx-byte according to the actual baud-rate. * * Reject when: * - time for a bit outside min/max range * - a 1-Wire response is not detectable for sent byte */ static int w1_uart_set_config(struct serdev_device *serdev, const struct w1_uart_limits *limits, struct w1_uart_config *w1cfg) { … } /* * Configuration for reset and presence detect * - bit_min_us is 480us, add margin and use 485us * - limits for sample time 60us-75us, use 65us */ static int w1_uart_set_config_reset(struct w1_uart_device *w1dev) { … } /* * Configuration for write-0 cycle (touch bit 0) * - bit_min_us is 60us, add margin and use 65us * - no sampling required, sample_us = 0 */ static int w1_uart_set_config_touch_0(struct w1_uart_device *w1dev) { … } /* * Configuration for write-1 and read cycle (touch bit 1) * - bit_min_us is 5us, add margin and use 6us * - limits for sample time 5us-15us, use 15us */ static int w1_uart_set_config_touch_1(struct w1_uart_device *w1dev) { … } /* * Configure and open the serial device */ static int w1_uart_serdev_open(struct w1_uart_device *w1dev) { … } /* * Send one byte (tx_byte) and read one byte (rx_byte) via serdev. */ static int w1_uart_serdev_tx_rx(struct w1_uart_device *w1dev, const struct w1_uart_config *w1cfg, u8 *rx_byte) { … } static size_t w1_uart_serdev_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t count) { … } static const struct serdev_device_ops w1_uart_serdev_ops = …; /* * 1-wire reset and presence detect: A present slave will manipulate * the received byte by pulling the 1-Wire low. */ static u8 w1_uart_reset_bus(void *data) { … } /* * 1-Wire read and write cycle: Only the read-0 manipulates the * received byte, all others left the line untouched. */ static u8 w1_uart_touch_bit(void *data, u8 bit) { … } static int w1_uart_probe(struct serdev_device *serdev) { … } static void w1_uart_remove(struct serdev_device *serdev) { … } static const struct of_device_id w1_uart_of_match[] = …; MODULE_DEVICE_TABLE(of, w1_uart_of_match); static struct serdev_device_driver w1_uart_driver = …; module_serdev_device_driver(…) …; MODULE_DESCRIPTION(…) …; MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …;