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