brintos

brintos / linux-shallow public Read only

0
0
Text · 15.5 KiB · da7873b Raw
561 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Serial line interface for Bosh BNO055 IMU (via serdev).4 * This file implements serial communication up to the register read/write5 * level.6 *7 * Copyright (C) 2021-2022 Istituto Italiano di Tecnologia8 * Electronic Design Laboratory9 * Written by Andrea Merello <andrea.merello@iit.it>10 *11 * This driver is based on12 *	Plantower PMS7003 particulate matter sensor driver13 *	Which is14 *	Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>15 */16 17#include <linux/completion.h>18#include <linux/device.h>19#include <linux/errno.h>20#include <linux/jiffies.h>21#include <linux/kernel.h>22#include <linux/mod_devicetable.h>23#include <linux/module.h>24#include <linux/mutex.h>25#include <linux/regmap.h>26#include <linux/serdev.h>27 28#include "bno055_ser_trace.h"29#include "bno055.h"30 31/*32 * Register writes cmd have the following format33 * +------+------+-----+-----+----- ... ----+34 * | 0xAA | 0xOO | REG | LEN | payload[LEN] |35 * +------+------+-----+-----+----- ... ----+36 *37 * Register write responses have the following format38 * +------+----------+39 * | 0xEE | ERROCODE |40 * +------+----------+41 *42 * .. except when writing the SYS_RST bit (i.e. triggering a system reset); in43 * case the IMU accepts the command, then it resets without responding. We don't44 * handle this (yet) here (so we inform the common bno055 code not to perform45 * sw resets - bno055 on serial bus basically requires the hw reset pin).46 *47 * Register read have the following format48 * +------+------+-----+-----+49 * | 0xAA | 0xO1 | REG | LEN |50 * +------+------+-----+-----+51 *52 * Successful register read response have the following format53 * +------+-----+----- ... ----+54 * | 0xBB | LEN | payload[LEN] |55 * +------+-----+----- ... ----+56 *57 * Failed register read response have the following format58 * +------+--------+59 * | 0xEE | ERRCODE|  (ERRCODE always > 1)60 * +------+--------+61 *62 * Error codes are63 * 01: OK64 * 02: read/write FAIL65 * 04: invalid address66 * 05: write on RO67 * 06: wrong start byte68 * 07: bus overrun69 * 08: len too high70 * 09: len too low71 * 10: bus RX byte timeout (timeout is 30mS)72 *73 *74 * **WORKAROUND ALERT**75 *76 * Serial communication seems very fragile: the BNO055 buffer seems to overflow77 * very easy; BNO055 seems able to sink few bytes, then it needs a brief pause.78 * On the other hand, it is also picky on timeout: if there is a pause > 30mS in79 * between two bytes then the transaction fails (IMU internal RX FSM resets).80 *81 * BNO055 has been seen also failing to process commands in case we send them82 * too close each other (or if it is somehow busy?)83 *84 * In particular I saw these scenarios:85 * 1) If we send 2 bytes per time, then the IMU never(?) overflows.86 * 2) If we send 4 bytes per time (i.e. the full header), then the IMU could87 *    overflow, but it seem to sink all 4 bytes, then it returns error.88 * 3) If we send more than 4 bytes, the IMU could overflow, and I saw it sending89 *    error after 4 bytes are sent; we have troubles in synchronizing again,90 *    because we are still sending data, and the IMU interprets it as the 1st91 *    byte of a new command.92 *93 * While we must avoid case 3, we could send 4 bytes per time and eventually94 * retry in case of failure; this seemed convenient for reads (which requires95 * TXing exactly 4 bytes), however it has been seen that, depending by the IMU96 * settings (e.g. LPF), failures became less or more frequent; in certain IMU97 * configurations they are very rare, but in certain others we keeps failing98 * even after like 30 retries.99 *100 * So, we just split TXes in [2-bytes + delay] steps, and still keep an eye on101 * the IMU response; in case it overflows (which is now unlikely), we retry.102 */103 104/*105 * Read operation overhead:106 *  4 bytes req + 2byte resp hdr.107 *  6 bytes = 60 bit (considering 1start + 1stop bits).108 *  60/115200 = ~520uS + about 2500mS delay -> ~3mS109 * In 3mS we could read back about 34 bytes that means 17 samples, this means110 * that in case of scattered reads in which the gap is 17 samples or less it is111 * still convenient to go for a burst.112 * We have to take into account also IMU response time - IMU seems to be often113 * reasonably quick to respond, but sometimes it seems to be in some "critical114 * section" in which it delays handling of serial protocol. Because of this we115 * round-up to 22, which is the max number of samples, always bursting indeed.116 */117#define BNO055_SER_XFER_BURST_BREAK_THRESHOLD 22118 119struct bno055_ser_priv {120	enum {121		CMD_NONE,122		CMD_READ,123		CMD_WRITE,124	} expect_response;125	int expected_data_len;126	u8 *response_buf;127 128	/**129	 * enum cmd_status - represent the status of a command sent to the HW.130	 * @STATUS_CRIT: The command failed: the serial communication failed.131	 * @STATUS_OK:   The command executed successfully.132	 * @STATUS_FAIL: The command failed: HW responded with an error.133	 */134	enum {135		STATUS_CRIT = -1,136		STATUS_OK = 0,137		STATUS_FAIL = 1,138	} cmd_status;139 140	/*141	 * Protects all the above fields, which are accessed in behalf of both142	 * the serdev RX callback and the regmap side143	 */144	struct mutex lock;145 146	/* Only accessed in serdev RX callback context*/147	struct {148		enum {149			RX_IDLE,150			RX_START,151			RX_DATA,152		} state;153		int databuf_count;154		int expected_len;155		int type;156	} rx;157 158	/* Never accessed in behalf of serdev RX callback context */159	bool cmd_stale;160 161	struct completion cmd_complete;162	struct serdev_device *serdev;163};164 165static int bno055_ser_send_chunk(struct bno055_ser_priv *priv, const u8 *data, int len)166{167	int ret;168 169	trace_send_chunk(len, data);170	ret = serdev_device_write(priv->serdev, data, len, msecs_to_jiffies(25));171	if (ret < 0)172		return ret;173 174	if (ret < len)175		return -EIO;176 177	return 0;178}179 180/*181 * Send a read or write command.182 * 'data' can be NULL (used in read case). 'len' parameter is always valid; in183 * case 'data' is non-NULL then it must match 'data' size.184 */185static int bno055_ser_do_send_cmd(struct bno055_ser_priv *priv,186				  bool read, int addr, int len, const u8 *data)187{188	u8 hdr[] = {0xAA, read, addr, len};189	int chunk_len;190	int ret;191 192	ret = bno055_ser_send_chunk(priv, hdr, 2);193	if (ret)194		goto fail;195	usleep_range(2000, 3000);196	ret = bno055_ser_send_chunk(priv, hdr + 2, 2);197	if (ret)198		goto fail;199 200	if (read)201		return 0;202 203	while (len) {204		chunk_len = min(len, 2);205		usleep_range(2000, 3000);206		ret = bno055_ser_send_chunk(priv, data, chunk_len);207		if (ret)208			goto fail;209		data += chunk_len;210		len -= chunk_len;211	}212 213	return 0;214fail:215	/* waiting more than 30mS should clear the BNO055 internal state */216	usleep_range(40000, 50000);217	return ret;218}219 220static int bno055_ser_send_cmd(struct bno055_ser_priv *priv,221			       bool read, int addr, int len, const u8 *data)222{223	const int retry_max = 5;224	int retry = retry_max;225	int ret = 0;226 227	/*228	 * In case previous command was interrupted we still need to wait it to229	 * complete before we can issue new commands230	 */231	if (priv->cmd_stale) {232		ret = wait_for_completion_interruptible_timeout(&priv->cmd_complete,233								msecs_to_jiffies(100));234		if (ret == -ERESTARTSYS)235			return -ERESTARTSYS;236 237		priv->cmd_stale = false;238		/* if serial protocol broke, bail out */239		if (priv->cmd_status == STATUS_CRIT)240			return -EIO;241	}242 243	/*244	 * Try to convince the IMU to cooperate.. as explained in the comments245	 * at the top of this file, the IMU could also refuse the command (i.e.246	 * it is not ready yet); retry in this case.247	 */248	do {249		mutex_lock(&priv->lock);250		priv->expect_response = read ? CMD_READ : CMD_WRITE;251		reinit_completion(&priv->cmd_complete);252		mutex_unlock(&priv->lock);253 254		if (retry != retry_max)255			trace_cmd_retry(read, addr, retry_max - retry);256		ret = bno055_ser_do_send_cmd(priv, read, addr, len, data);257		if (ret)258			continue;259 260		ret = wait_for_completion_interruptible_timeout(&priv->cmd_complete,261								msecs_to_jiffies(100));262		if (ret == -ERESTARTSYS) {263			priv->cmd_stale = true;264			return -ERESTARTSYS;265		}266 267		if (!ret)268			return -ETIMEDOUT;269 270		if (priv->cmd_status == STATUS_OK)271			return 0;272		if (priv->cmd_status == STATUS_CRIT)273			return -EIO;274 275		/* loop in case priv->cmd_status == STATUS_FAIL */276	} while (--retry);277 278	if (ret < 0)279		return ret;280	if (priv->cmd_status == STATUS_FAIL)281		return -EINVAL;282	return 0;283}284 285static int bno055_ser_write_reg(void *context, const void *_data, size_t count)286{287	const u8 *data = _data;288	struct bno055_ser_priv *priv = context;289 290	if (count < 2) {291		dev_err(&priv->serdev->dev, "Invalid write count %zu", count);292		return -EINVAL;293	}294 295	trace_write_reg(data[0], data[1]);296	return bno055_ser_send_cmd(priv, 0, data[0], count - 1, data + 1);297}298 299static int bno055_ser_read_reg(void *context,300			       const void *_reg, size_t reg_size,301			       void *val, size_t val_size)302{303	int ret;304	int reg_addr;305	const u8 *reg = _reg;306	struct bno055_ser_priv *priv = context;307 308	if (val_size > 128) {309		dev_err(&priv->serdev->dev, "Invalid read valsize %zu", val_size);310		return -EINVAL;311	}312 313	reg_addr = *reg;314	trace_read_reg(reg_addr, val_size);315	mutex_lock(&priv->lock);316	priv->expected_data_len = val_size;317	priv->response_buf = val;318	mutex_unlock(&priv->lock);319 320	ret = bno055_ser_send_cmd(priv, 1, reg_addr, val_size, NULL);321 322	mutex_lock(&priv->lock);323	priv->response_buf = NULL;324	mutex_unlock(&priv->lock);325 326	return ret;327}328 329/*330 * Handler for received data; this is called from the receiver callback whenever331 * it got some packet from the serial bus. The status tells us whether the332 * packet is valid (i.e. header ok && received payload len consistent wrt the333 * header). It's now our responsibility to check whether this is what we334 * expected, of whether we got some unexpected, yet valid, packet.335 */336static void bno055_ser_handle_rx(struct bno055_ser_priv *priv, int status)337{338	mutex_lock(&priv->lock);339	switch (priv->expect_response) {340	case CMD_NONE:341		dev_warn(&priv->serdev->dev, "received unexpected, yet valid, data from sensor");342		mutex_unlock(&priv->lock);343		return;344 345	case CMD_READ:346		priv->cmd_status = status;347		if (status == STATUS_OK &&348		    priv->rx.databuf_count != priv->expected_data_len) {349			/*350			 * If we got here, then the lower layer serial protocol351			 * seems consistent with itself; if we got an unexpected352			 * amount of data then signal it as a non critical error353			 */354			priv->cmd_status = STATUS_FAIL;355			dev_warn(&priv->serdev->dev,356				 "received an unexpected amount of, yet valid, data from sensor");357		}358		break;359 360	case CMD_WRITE:361		priv->cmd_status = status;362		break;363	}364 365	priv->expect_response = CMD_NONE;366	mutex_unlock(&priv->lock);367	complete(&priv->cmd_complete);368}369 370/*371 * Serdev receiver FSM. This tracks the serial communication and parse the372 * header. It pushes packets to bno055_ser_handle_rx(), eventually communicating373 * failures (i.e. malformed packets).374 * Ideally it doesn't know anything about upper layer (i.e. if this is the375 * packet we were really expecting), but since we copies the payload into the376 * receiver buffer (that is not valid when i.e. we don't expect data), we377 * snoop a bit in the upper layer..378 * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything379 * unless we require to AND we don't queue more than one request per time).380 */381static size_t bno055_ser_receive_buf(struct serdev_device *serdev,382				     const u8 *buf, size_t size)383{384	int status;385	struct bno055_ser_priv *priv = serdev_device_get_drvdata(serdev);386	size_t remaining = size;387 388	if (size == 0)389		return 0;390 391	trace_recv(size, buf);392	switch (priv->rx.state) {393	case RX_IDLE:394		/*395		 * New packet.396		 * Check for its 1st byte that identifies the pkt type.397		 */398		if (buf[0] != 0xEE && buf[0] != 0xBB) {399			dev_err(&priv->serdev->dev,400				"Invalid packet start %x", buf[0]);401			bno055_ser_handle_rx(priv, STATUS_CRIT);402			break;403		}404		priv->rx.type = buf[0];405		priv->rx.state = RX_START;406		remaining--;407		buf++;408		priv->rx.databuf_count = 0;409		fallthrough;410 411	case RX_START:412		/*413		 * Packet RX in progress, we expect either 1-byte len or 1-byte414		 * status depending by the packet type.415		 */416		if (remaining == 0)417			break;418 419		if (priv->rx.type == 0xEE) {420			if (remaining > 1) {421				dev_err(&priv->serdev->dev, "EE pkt. Extra data received");422				status = STATUS_CRIT;423			} else {424				status = (buf[0] == 1) ? STATUS_OK : STATUS_FAIL;425			}426			bno055_ser_handle_rx(priv, status);427			priv->rx.state = RX_IDLE;428			break;429 430		} else {431			/*priv->rx.type == 0xBB */432			priv->rx.state = RX_DATA;433			priv->rx.expected_len = buf[0];434			remaining--;435			buf++;436		}437		fallthrough;438 439	case RX_DATA:440		/* Header parsed; now receiving packet data payload */441		if (remaining == 0)442			break;443 444		if (priv->rx.databuf_count + remaining > priv->rx.expected_len) {445			/*446			 * This is an inconsistency in serial protocol, we lost447			 * sync and we don't know how to handle further data448			 */449			dev_err(&priv->serdev->dev, "BB pkt. Extra data received");450			bno055_ser_handle_rx(priv, STATUS_CRIT);451			priv->rx.state = RX_IDLE;452			break;453		}454 455		mutex_lock(&priv->lock);456		/*457		 * NULL e.g. when read cmd is stale or when no read cmd is458		 * actually pending.459		 */460		if (priv->response_buf &&461		    /*462		     * Snoop on the upper layer protocol stuff to make sure not463		     * to write to an invalid memory. Apart for this, let's the464		     * upper layer manage any inconsistency wrt expected data465		     * len (as long as the serial protocol is consistent wrt466		     * itself (i.e. response header is consistent with received467		     * response len.468		     */469		    (priv->rx.databuf_count + remaining <= priv->expected_data_len))470			memcpy(priv->response_buf + priv->rx.databuf_count,471			       buf, remaining);472		mutex_unlock(&priv->lock);473 474		priv->rx.databuf_count += remaining;475 476		/*477		 * Reached expected len advertised by the IMU for the current478		 * packet. Pass it to the upper layer (for us it is just valid).479		 */480		if (priv->rx.databuf_count == priv->rx.expected_len) {481			bno055_ser_handle_rx(priv, STATUS_OK);482			priv->rx.state = RX_IDLE;483		}484		break;485	}486 487	return size;488}489 490static const struct serdev_device_ops bno055_ser_serdev_ops = {491	.receive_buf = bno055_ser_receive_buf,492	.write_wakeup = serdev_device_write_wakeup,493};494 495static const struct regmap_bus bno055_ser_regmap_bus = {496	.write = bno055_ser_write_reg,497	.read = bno055_ser_read_reg,498};499 500static int bno055_ser_probe(struct serdev_device *serdev)501{502	struct bno055_ser_priv *priv;503	struct regmap *regmap;504	int ret;505 506	priv = devm_kzalloc(&serdev->dev, sizeof(*priv), GFP_KERNEL);507	if (!priv)508		return -ENOMEM;509 510	serdev_device_set_drvdata(serdev, priv);511	priv->serdev = serdev;512	mutex_init(&priv->lock);513	init_completion(&priv->cmd_complete);514 515	serdev_device_set_client_ops(serdev, &bno055_ser_serdev_ops);516	ret = devm_serdev_device_open(&serdev->dev, serdev);517	if (ret)518		return ret;519 520	if (serdev_device_set_baudrate(serdev, 115200) != 115200) {521		dev_err(&serdev->dev, "Cannot set required baud rate");522		return -EIO;523	}524 525	ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);526	if (ret) {527		dev_err(&serdev->dev, "Cannot set required parity setting");528		return ret;529	}530	serdev_device_set_flow_control(serdev, false);531 532	regmap = devm_regmap_init(&serdev->dev, &bno055_ser_regmap_bus,533				  priv, &bno055_regmap_config);534	if (IS_ERR(regmap))535		return dev_err_probe(&serdev->dev, PTR_ERR(regmap),536				     "Unable to init register map");537 538	return bno055_probe(&serdev->dev, regmap,539			    BNO055_SER_XFER_BURST_BREAK_THRESHOLD, false);540}541 542static const struct of_device_id bno055_ser_of_match[] = {543	{ .compatible = "bosch,bno055" },544	{ }545};546MODULE_DEVICE_TABLE(of, bno055_ser_of_match);547 548static struct serdev_device_driver bno055_ser_driver = {549	.driver = {550		.name = "bno055-ser",551		.of_match_table = bno055_ser_of_match,552	},553	.probe = bno055_ser_probe,554};555module_serdev_device_driver(bno055_ser_driver);556 557MODULE_AUTHOR("Andrea Merello <andrea.merello@iit.it>");558MODULE_DESCRIPTION("Bosch BNO055 serdev interface");559MODULE_IMPORT_NS(IIO_BNO055);560MODULE_LICENSE("GPL");561