// SPDX-License-Identifier: GPL-2.0 /* * Serial line interface for Bosh BNO055 IMU (via serdev). * This file implements serial communication up to the register read/write * level. * * Copyright (C) 2021-2022 Istituto Italiano di Tecnologia * Electronic Design Laboratory * Written by Andrea Merello <[email protected]> * * This driver is based on * Plantower PMS7003 particulate matter sensor driver * Which is * Copyright (c) Tomasz Duszynski <[email protected]> */ #include <linux/completion.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/regmap.h> #include <linux/serdev.h> #include "bno055_ser_trace.h" #include "bno055.h" /* * Register writes cmd have the following format * +------+------+-----+-----+----- ... ----+ * | 0xAA | 0xOO | REG | LEN | payload[LEN] | * +------+------+-----+-----+----- ... ----+ * * Register write responses have the following format * +------+----------+ * | 0xEE | ERROCODE | * +------+----------+ * * .. except when writing the SYS_RST bit (i.e. triggering a system reset); in * case the IMU accepts the command, then it resets without responding. We don't * handle this (yet) here (so we inform the common bno055 code not to perform * sw resets - bno055 on serial bus basically requires the hw reset pin). * * Register read have the following format * +------+------+-----+-----+ * | 0xAA | 0xO1 | REG | LEN | * +------+------+-----+-----+ * * Successful register read response have the following format * +------+-----+----- ... ----+ * | 0xBB | LEN | payload[LEN] | * +------+-----+----- ... ----+ * * Failed register read response have the following format * +------+--------+ * | 0xEE | ERRCODE| (ERRCODE always > 1) * +------+--------+ * * Error codes are * 01: OK * 02: read/write FAIL * 04: invalid address * 05: write on RO * 06: wrong start byte * 07: bus overrun * 08: len too high * 09: len too low * 10: bus RX byte timeout (timeout is 30mS) * * * **WORKAROUND ALERT** * * Serial communication seems very fragile: the BNO055 buffer seems to overflow * very easy; BNO055 seems able to sink few bytes, then it needs a brief pause. * On the other hand, it is also picky on timeout: if there is a pause > 30mS in * between two bytes then the transaction fails (IMU internal RX FSM resets). * * BNO055 has been seen also failing to process commands in case we send them * too close each other (or if it is somehow busy?) * * In particular I saw these scenarios: * 1) If we send 2 bytes per time, then the IMU never(?) overflows. * 2) If we send 4 bytes per time (i.e. the full header), then the IMU could * overflow, but it seem to sink all 4 bytes, then it returns error. * 3) If we send more than 4 bytes, the IMU could overflow, and I saw it sending * error after 4 bytes are sent; we have troubles in synchronizing again, * because we are still sending data, and the IMU interprets it as the 1st * byte of a new command. * * While we must avoid case 3, we could send 4 bytes per time and eventually * retry in case of failure; this seemed convenient for reads (which requires * TXing exactly 4 bytes), however it has been seen that, depending by the IMU * settings (e.g. LPF), failures became less or more frequent; in certain IMU * configurations they are very rare, but in certain others we keeps failing * even after like 30 retries. * * So, we just split TXes in [2-bytes + delay] steps, and still keep an eye on * the IMU response; in case it overflows (which is now unlikely), we retry. */ /* * Read operation overhead: * 4 bytes req + 2byte resp hdr. * 6 bytes = 60 bit (considering 1start + 1stop bits). * 60/115200 = ~520uS + about 2500mS delay -> ~3mS * In 3mS we could read back about 34 bytes that means 17 samples, this means * that in case of scattered reads in which the gap is 17 samples or less it is * still convenient to go for a burst. * We have to take into account also IMU response time - IMU seems to be often * reasonably quick to respond, but sometimes it seems to be in some "critical * section" in which it delays handling of serial protocol. Because of this we * round-up to 22, which is the max number of samples, always bursting indeed. */ #define BNO055_SER_XFER_BURST_BREAK_THRESHOLD … struct bno055_ser_priv { … }; static int bno055_ser_send_chunk(struct bno055_ser_priv *priv, const u8 *data, int len) { … } /* * Send a read or write command. * 'data' can be NULL (used in read case). 'len' parameter is always valid; in * case 'data' is non-NULL then it must match 'data' size. */ static int bno055_ser_do_send_cmd(struct bno055_ser_priv *priv, bool read, int addr, int len, const u8 *data) { … } static int bno055_ser_send_cmd(struct bno055_ser_priv *priv, bool read, int addr, int len, const u8 *data) { … } static int bno055_ser_write_reg(void *context, const void *_data, size_t count) { … } static int bno055_ser_read_reg(void *context, const void *_reg, size_t reg_size, void *val, size_t val_size) { … } /* * Handler for received data; this is called from the receiver callback whenever * it got some packet from the serial bus. The status tells us whether the * packet is valid (i.e. header ok && received payload len consistent wrt the * header). It's now our responsibility to check whether this is what we * expected, of whether we got some unexpected, yet valid, packet. */ static void bno055_ser_handle_rx(struct bno055_ser_priv *priv, int status) { … } /* * Serdev receiver FSM. This tracks the serial communication and parse the * header. It pushes packets to bno055_ser_handle_rx(), eventually communicating * failures (i.e. malformed packets). * Ideally it doesn't know anything about upper layer (i.e. if this is the * packet we were really expecting), but since we copies the payload into the * receiver buffer (that is not valid when i.e. we don't expect data), we * snoop a bit in the upper layer.. * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything * unless we require to AND we don't queue more than one request per time). */ static size_t bno055_ser_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t size) { … } static const struct serdev_device_ops bno055_ser_serdev_ops = …; static struct regmap_bus bno055_ser_regmap_bus = …; static int bno055_ser_probe(struct serdev_device *serdev) { … } static const struct of_device_id bno055_ser_of_match[] = …; MODULE_DEVICE_TABLE(of, bno055_ser_of_match); static struct serdev_device_driver bno055_ser_driver = …; module_serdev_device_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_IMPORT_NS(…); MODULE_LICENSE(…) …;