diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index a560a19c6c9..f9bad127504 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -131,6 +131,13 @@ config SENSORS_DHTXX ---help--- Enable driver support for the DHTxx humidity/temperature sensor. +config SENSORS_FXOS8700CQ + bool "NXP FXOS8700CQ Motion Sensor support" + default n + select I2C + ---help--- + Enable driver support for the NXP FXOS8700CQ Motion sensor + config SENSORS_HCSR04 bool "HC-SR04 Distance Measurement Sensor" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index 530d20a1be5..53d2132a1bb 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -69,6 +69,10 @@ ifeq ($(CONFIG_SENSORS_AS726X),y) CSRCS += as726x.c endif +ifeq ($(CONFIG_SENSORS_FXOS8700CQ),y) + CSRCS += fxos8700cq.c +endif + ifeq ($(CONFIG_SENSORS_KXTJ9),y) CSRCS += kxtj9.c endif diff --git a/drivers/sensors/fxos8700cq.c b/drivers/sensors/fxos8700cq.c new file mode 100644 index 00000000000..34e2289396f --- /dev/null +++ b/drivers/sensors/fxos8700cq.c @@ -0,0 +1,450 @@ +/**************************************************************************** + * 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 + +#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, + fxos8700cq_close, + fxos8700cq_read, + 0, /* write */ + 0, /* seek */ + 0, /* ioctl */ +}; + +/**************************************************************************** + * 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, 0666, 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 */ diff --git a/include/nuttx/sensors/fxos8700cq.h b/include/nuttx/sensors/fxos8700cq.h new file mode 100644 index 00000000000..a6f0dc67f7d --- /dev/null +++ b/include/nuttx/sensors/fxos8700cq.h @@ -0,0 +1,120 @@ +/**************************************************************************** + * include/nuttx/sensors/fxos8700cq.h + * FXOS8700CQ Driver declaration + * + * 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. + * + ****************************************************************************/ +#ifndef __INCLUDE_NUTTX_SENSORS_FXOS8700CQ_H +#define __INCLUDE_NUTTX_SENSORS_FXOS8700CQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#if defined(CONFIG_SENSORS_FXOS8700CQ) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Power mode */ + +#define FXOS8700CQ_PM_SUSPEND (0x00) +#define FXOS8700CQ_PM_NORMAL (0x01) +#define FXOS8700CQ_PM_LOWPOWER (0x02) +#define FXOS8700CQ_PM_FASTSTARTUP (0x03) + +/* IOCTL Commands ***********************************************************/ + +#define SNIOC_ENABLESC _SNIOC(0x0001) /* Arg: uint8_t value */ +#define SNIOC_READSC _SNIOC(0x0002) /* Arg: int16_t* pointer */ +#define SNIOC_SETACCPM _SNIOC(0x0003) /* Arg: uint8_t value */ +#define SNIOC_SETACCODR _SNIOC(0x0004) /* Arg: uint8_t value */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef struct +{ + int16_t x; + int16_t y; + int16_t z; +} v3int16_t; + +typedef struct +{ + v3int16_t accel; + v3int16_t magn; +} fxos8700cq_data; + +struct i2c_master_s; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * 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. + * + ****************************************************************************/ + +#ifndef CONFIG_SENSORS_FXOS8700CQ_SCU + +int fxos8700cq_register(FAR const char *devpath, + FAR struct i2c_master_s *dev); + +#else /* CONFIG_SENSORS_FXOS8700CQ_SCU */ + +int fxos8700cq_init(FAR struct i2c_master_s *dev, int port); +int fxos8700cqgyro_register(FAR const char *devpath, int minor, + FAR struct i2c_master_s *dev, int port); +int fxos8700cqaccel_register(FAR const char *devpath, int minor, + FAR struct i2c_master_s *dev, int port); + +#endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_SENSORS_FXOS8700CQ */ +#endif /* __INCLUDE_NUTTX_SENSORS_FXOS8700CQ_H */