brintos

brintos / linux-shallow public Read only

0
0
Text · 10.4 KiB · a31782e Raw
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