/**************************************************************************** * drivers/sensors/fxos8700cq.c * Driver for Motion Sensor FXOS8700CQ (NXP) * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #if defined(CONFIG_SENSORS_FXOS8700CQ) /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define FXOS8700CQ_I2C_ADDR 0x1d #define FXOS8700CQ_I2C_FREQ 400000 /* I2C Regs */ #define FXOS8700CQ_STATUS 0x00 #define FXOS8700CQ_WHOAMI 0x0D #define FXOS8700CQ_XYZ_DATA_CFG 0x0E #define FXOS8700CQ_CTRL_REG1 0x2A #define FXOS8700CQ_CTRL_REG2 0x2B #define FXOS8700CQ_CTRL_REG3 0x2C #define FXOS8700CQ_CTRL_REG4 0x2D #define FXOS8700CQ_CTRL_REG5 0x2E #define FXOS8700CQ_M_CTRL_REG1 0x5B #define FXOS8700CQ_M_CTRL_REG2 0x5C #define FXOS8700CQ_PULSE_CFG (0x21) #define FXOS8700CQ_PULSE_SRC (0x22) #define FXOS8700CQ_PULSE_THSX (0x23) /* Values */ #define FXOS8700CQ_WHOAMI_VAL 0xC7 /** status byte + x,y,z for accelerometer and magnetometer */ #define FXOS8700CQ_READ_LEN ((8 + (16 * 3 + 16 * 3)) / 8) /**************************************************************************** * Private Types ****************************************************************************/ struct fxos8700cq_dev_s { FAR struct i2c_master_s *i2c; uint8_t addr; int freq; }; /**************************************************************************** * Private Functions ****************************************************************************/ static uint8_t fxos8700cq_getreg8(FAR struct fxos8700cq_dev_s *priv, uint8_t regaddr); static int fxos8700cq_putreg8(FAR struct fxos8700cq_dev_s *priv, uint8_t regaddr, uint8_t regval); static int fxos8700cq_getregs(FAR struct fxos8700cq_dev_s *priv, uint8_t regaddr, uint8_t *regval, int len); /* Character driver methods */ static int fxos8700cq_open(FAR struct file *filep); static int fxos8700cq_close(FAR struct file *filep); static ssize_t fxos8700cq_read(FAR struct file *filep, FAR char *buffer, size_t len); static int fxos8700cq_checkid(FAR struct fxos8700cq_dev_s *priv); /**************************************************************************** * Private Data ****************************************************************************/ /** vtable that supports the character driver interface */ static const struct file_operations g_fxos8700cqfops = { fxos8700cq_open, /* open */ fxos8700cq_close, /* close */ fxos8700cq_read, /* read */ }; /**************************************************************************** * Name: fxos8700cq_getreg8 * * Description: * Read from an 8-bit FXOS8700CQ register * ****************************************************************************/ static uint8_t fxos8700cq_getreg8(FAR struct fxos8700cq_dev_s *priv, uint8_t regaddr) { uint8_t regval = 0; struct i2c_msg_s msg[2]; int ret; msg[0].frequency = priv->freq; msg[0].addr = priv->addr; msg[0].flags = 0; msg[0].buffer = ®addr; msg[0].length = 1; msg[1].frequency = priv->freq; msg[1].addr = priv->addr; msg[1].flags = I2C_M_READ; msg[1].buffer = ®val; msg[1].length = 1; ret = I2C_TRANSFER(priv->i2c, msg, 2); if (ret < 0) { snerr("I2C_TRANSFER failed: %d\n", ret); } return regval; } /**************************************************************************** * Name: fxos8700cq_putreg8 * * Description: * Write a value to an 8-bit FXOS8700CQ register * ****************************************************************************/ static int fxos8700cq_putreg8(FAR struct fxos8700cq_dev_s *priv, uint8_t regaddr, uint8_t regval) { struct i2c_msg_s msg[2]; int ret; uint8_t txbuffer[2]; txbuffer[0] = regaddr; txbuffer[1] = regval; msg[0].frequency = priv->freq; msg[0].addr = priv->addr; msg[0].flags = 0; msg[0].buffer = txbuffer; msg[0].length = 2; ret = I2C_TRANSFER(priv->i2c, msg, 1); if (ret < 0) { snerr("I2C_TRANSFER failed: %d\n", ret); } return ret; } /**************************************************************************** * Name: fxos8700cq_getregs * * Description: * Read cnt bytes from specified dev_addr and reg_addr * ****************************************************************************/ static int fxos8700cq_getregs(FAR struct fxos8700cq_dev_s *priv, uint8_t regaddr, uint8_t *regval, int len) { struct i2c_msg_s msg[2]; int ret; msg[0].frequency = priv->freq; msg[0].addr = priv->addr; msg[0].flags = 0; msg[0].buffer = ®addr; msg[0].length = 1; msg[1].frequency = priv->freq; msg[1].addr = priv->addr; msg[1].flags = I2C_M_READ; msg[1].buffer = regval; msg[1].length = len; ret = I2C_TRANSFER(priv->i2c, msg, 2); if (ret < 0) { snerr("I2C_TRANSFER failed: %d\n", ret); } return ret; } /**************************************************************************** * Name: fxos8700cq_open * * Description: * Standard character driver open method. * ****************************************************************************/ static int fxos8700cq_open(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct fxos8700cq_dev_s *priv = inode->i_private; uint8_t regval; int ret = 0; ret = fxos8700cq_getreg8(priv, FXOS8700CQ_WHOAMI); if (ret != FXOS8700CQ_WHOAMI_VAL) { snerr("ERROR: Invalid device identification %02x\n", regval); return -ENODEV; } regval = 0x00; /* active: standbye */ ret = fxos8700cq_putreg8(priv, FXOS8700CQ_CTRL_REG1, regval); if (ret < 0) { snerr("ERROR: %02x\n", regval); return (ret); } /* m_hms[1:0]: Hybrid mode, both accelerometer and magnetometer * m_os[2:0]: Oversample ratio (OSR) for magnetometer data * m_ost: One-shot triggered magnetic measurement mode * m_rst: One-shot magnetic reset degauss control bit * m_acal: Magnetic hard-iron offset auto-calibration enable */ regval = 0 | (0b11 << 0) | (0b11 << 3) | (0b1 << 5) | (0b0 << 6) | (0b0 << 7) ; ret = fxos8700cq_putreg8(priv, FXOS8700CQ_M_CTRL_REG1, regval); if (ret < 0) { return (ret); } /* hyb_autoinc_mode */ regval = 0b1 << 5; ret = fxos8700cq_putreg8(priv, FXOS8700CQ_M_CTRL_REG2, regval); if (ret < 0) { return (ret); } /* fs[1:0]: Accelerometer full-scale range : 4G */ regval = 0b01; ret = fxos8700cq_putreg8(priv, FXOS8700CQ_XYZ_DATA_CFG, regval); if (ret < 0) { return (ret); } /* active , lnoise , dr[2:0] */ regval = 0b1 | (0b1 < 2) | (0b001 < 5) ; ret = fxos8700cq_putreg8(priv, FXOS8700CQ_CTRL_REG1, regval); if (ret < 0) { return (ret); } return OK; } /**************************************************************************** * Name: fxos8700cq_close * * Description: * Standard character driver close method. * ****************************************************************************/ static int fxos8700cq_close(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct fxos8700cq_dev_s *priv = inode->i_private; uint8_t regval = 0b0; /* active */ int ret = fxos8700cq_putreg8(priv, FXOS8700CQ_CTRL_REG1, regval); if (ret < 0) { return (ret); } return OK; } /**************************************************************************** * Name: fxos8700cq_read * * Description: * Standard character driver read method. * ****************************************************************************/ static ssize_t fxos8700cq_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode = filep->f_inode; FAR struct fxos8700cq_dev_s *priv = inode->i_private; FAR fxos8700cq_data * p = (FAR fxos8700cq_data *) buffer; if (len < sizeof(fxos8700cq_data)) { snerr("Expected buffer size is %d\n", sizeof(fxos8700cq_data)); return 0; } uint8_t data[FXOS8700CQ_READ_LEN]; int status = fxos8700cq_getregs(priv, FXOS8700CQ_STATUS, (FAR uint8_t *)data, FXOS8700CQ_READ_LEN); if (status < 0) { snerr("Error: read status=%d", status); return 0; } /* Copy the 14 bit accelerometer byte data into 16 bit words */ p->accel.x = (int16_t)(((data[1] << 8) | data[2])) >> 2; p->accel.y = (int16_t)(((data[3] << 8) | data[4])) >> 2; p->accel.z = (int16_t)(((data[5] << 8) | data[6])) >> 2; /* Copy the magnetometer byte data into 16 bit words */ p->magn.x = (int16_t)(((data[7] << 8) | data[8])); p->magn.y = (int16_t)(((data[9] << 8) | data[10])); p->magn.z = (int16_t)(((data[11] << 8) | data[12])); return len; } /**************************************************************************** * Name: fxos8700cq_checkid * * Description: * Read and verify the FXOS8700CQ chip ID * ****************************************************************************/ static int fxos8700cq_checkid(FAR struct fxos8700cq_dev_s *priv) { uint8_t devid = 0; devid = fxos8700cq_getreg8(priv, FXOS8700CQ_WHOAMI); sninfo("devid: %04x\n", devid); if (devid != (uint16_t) FXOS8700CQ_WHOAMI_VAL) { return -ENODEV; } return OK; } /**************************************************************************** * Name: fxos8700cq_register * * Description: * Register the FXOS8700CQ character device as 'devpath' * * Input Parameters: * devpath - The full path to the driver to register. E.g., "/dev/accel0" * dev - An instance of the I2C interface to communicate with device * * * Returned Value: * Zero (OK) on success; a negated errno value on failure. * ****************************************************************************/ int fxos8700cq_register(FAR const char *devpath, FAR struct i2c_master_s *dev) { FAR struct fxos8700cq_dev_s *priv; int ret; priv = (FAR struct fxos8700cq_dev_s *) kmm_malloc(sizeof(struct fxos8700cq_dev_s)); if (!priv) { snerr("Failed to allocate instance\n"); return -ENOMEM; } priv->i2c = dev; priv->addr = FXOS8700CQ_I2C_ADDR; priv->freq = FXOS8700CQ_I2C_FREQ; ret = fxos8700cq_checkid(priv); if (ret < 0) { snerr("Wrong Device ID!\n"); kmm_free(priv); return ret; } ret = register_driver(devpath, &g_fxos8700cqfops, 0444, priv); if (ret < 0) { snerr("Failed to register driver: %d\n", ret); kmm_free(priv); } sninfo("FXOS8700CQ driver loaded successfully!\n"); return OK; } #endif /* CONFIG_SENSORS_FXOS8700CQ */