416 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * w1-uart - UART 1-Wire bus driver4 *5 * Uses the UART interface (via Serial Device Bus) to create the 1-Wire6 * timing patterns. Implements the following 1-Wire master interface:7 *8 * - reset_bus: requests baud-rate 96009 *10 * - touch_bit: requests baud-rate 11520011 *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 operation32 * @baudrate: baud-rate returned from serdev33 * @delay_us: delay to complete a 1-Wire cycle (in us)34 * @tx_byte: byte to generate 1-Wire timing pattern35 */36struct 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 structure44 * @serdev: serial device45 * @bus: w1-bus master46 * @cfg_reset: config for 1-Wire reset47 * @cfg_touch_0: config for 1-Wire write-0 cycle48 * @cfg_touch_1: config for 1-Wire write-1 and read cycle49 * @rx_byte_received: completion for serdev receive50 * @rx_mutex: mutex to protect rx_err and rx_byte51 * @rx_err: indicates an error in serdev-receive52 * @rx_byte: result byte from serdev-receive53 */54struct 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 in65 * 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 operations74 * @baudrate: Requested baud-rate to create 1-Wire timing pattern75 * @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 response78 * @cycle_us: duration of the 1-Wire cycle79 */80struct 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 88static inline unsigned int baud_to_bit_ns(unsigned int baud)89{90 return NSEC_PER_SEC / baud;91}92 93static 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 adapt100 * the tx-byte according to the actual baud-rate.101 *102 * Reject when:103 * - time for a bit outside min/max range104 * - a 1-Wire response is not detectable for sent byte105 */106static 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 detect151 * - bit_min_us is 480us, add margin and use 485us152 * - limits for sample time 60us-75us, use 65us153 */154static 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 65us173 * - no sampling required, sample_us = 0174 */175static 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 6us194 * - limits for sample time 5us-15us, use 15us195 */196static 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 device214 */215static 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 */257static 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 292static 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 313static 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 manipulate320 * the received byte by pulling the 1-Wire low.321 */322static 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 the339 * received byte, all others left the line untouched.340 */341static 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 358static 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 384static 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 closed390 * and its device data released automatically by devres (waits391 * until serdev-receive is finished).392 */393 w1_remove_master_device(&w1dev->bus);394}395 396static const struct of_device_id w1_uart_of_match[] = {397 { .compatible = "w1-uart" },398 {},399};400MODULE_DEVICE_TABLE(of, w1_uart_of_match);401 402static 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 411module_serdev_device_driver(w1_uart_driver);412 413MODULE_DESCRIPTION("UART w1 bus driver");414MODULE_AUTHOR("Christoph Winklhofer <cj.winklhofer@gmail.com>");415MODULE_LICENSE("GPL");416