mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
Permissions (Part 2) Description: In kernel builds, any unprivileged process running on the NuttX device can open /dev/efuse and attempt to read/write fuse content. Reading the fuses may provide valuable information to an attacker controlling the user process. The write operation, in extreme cases where the fuse blocks are not locked, may brick the device. DISCLAIMER: I tried to be strict with the settings, better to relax them later if it's needed. This is part of https://github.com/apache/nuttx/issues/19410 See https://github.com/apache/nuttx/issues/19410 Compiles ok. Signed-off-by: Catalin Visinescu <catalin_visinescu@yahoo.com>
789 lines
19 KiB
C
789 lines
19 KiB
C
/****************************************************************************
|
|
* drivers/sensors/lps25h.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/* WARNING for developers:
|
|
*
|
|
* This driver uses the legacy style of writing sensor drivers for NuttX. The
|
|
* project has since decided to adopt a new sensor framework in order to
|
|
* have a consistent API and feature-set.
|
|
*
|
|
* Sensors which use the uORB framework are typically suffixed "_uorb". You
|
|
* can also visit the documentation about the new sensor framework to learn
|
|
* more.
|
|
*/
|
|
|
|
#warning "This is a deprecated legacy sensor driver."
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/i2c/i2c_master.h>
|
|
#include <sys/types.h>
|
|
#include <assert.h>
|
|
#include <nuttx/debug.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/mutex.h>
|
|
#include <nuttx/random.h>
|
|
|
|
#include <nuttx/sensors/lps25h.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-Processor Definitions
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_DEBUG_LPS25H
|
|
# define lps25h_dbg(x, ...) _info(x, ##__VA_ARGS__)
|
|
#else
|
|
# define lps25h_dbg(x, ...) sninfo(x, ##__VA_ARGS__)
|
|
#endif
|
|
|
|
#define LPS25H_PRESSURE_INTERNAL_DIVIDER 4096
|
|
|
|
/* 'AN4450 - Hardware and software guidelines for use of LPS25H pressure
|
|
* sensors' - '6.2 One-shot mode conversion time estimation' gives estimates
|
|
* for conversion times:
|
|
*
|
|
* Typical conversion time ≈ 62*(Pavg+Tavg) + 975 μs
|
|
* ex: Tavg = 64; Pavg = 512; Typ. conversation time ≈ 36.7 ms
|
|
* (compatible with ODT=25 Hz)
|
|
* ex: Tavg = 32; Pavg = 128; Typ. conversation time ≈ 10.9 ms
|
|
* The formula is accurate within +/- 3% at room temperature
|
|
*
|
|
* Set timeout to 2 * max.conversation time (2*36.7*1.03 = 76 ms).
|
|
*/
|
|
|
|
#define LPS25H_RETRY_TIMEOUT_MSECS 76
|
|
#define LPS25H_MAX_RETRIES 5
|
|
|
|
#define LPS25H_I2C_RETRIES 10
|
|
|
|
/* Registers */
|
|
|
|
#define LPS25H_REF_P_XL 0x08
|
|
#define LPS25H_REF_P_L 0x09
|
|
#define LPS25H_REF_P_H 0x0a
|
|
#define LPS25H_WHO_AM_I 0x0f
|
|
#define LPS25H_RES_CONF 0x10
|
|
#define LPS25H_CTRL_REG1 0x20
|
|
#define LPS25H_CTRL_REG2 0x21
|
|
#define LPS25H_CTRL_REG3 0x22
|
|
#define LPS25H_CTRL_REG4 0x23
|
|
#define LPS25H_INT_CFG 0x24
|
|
#define LPS25H_INT_SOURCE 0x25
|
|
#define LPS25H_STATUS_REG 0x27
|
|
#define LPS25H_PRESS_POUT_XL 0x28
|
|
#define LPS25H_PRESS_OUT_L 0x29
|
|
#define LPS25H_PRESS_OUT_H 0x2a
|
|
#define LPS25H_TEMP_OUT_L 0x2b
|
|
#define LPS25H_TEMP_OUT_H 0x2c
|
|
#define LPS25H_FIFO_CTRL 0x2e
|
|
#define LPS25H_FIFO_STATUS 0x2f
|
|
#define LPS25H_THS_P_L 0x30
|
|
#define LPS25H_THS_P_H 0x31
|
|
#define LPS25H_RPDS_L 0x39
|
|
#define LPS25H_RPDS_H 0x3a
|
|
|
|
/* Bits in registers */
|
|
|
|
#define LPS25H_AUTO_ZERO (1 << 2)
|
|
#define LPS25H_BDU (1 << 2)
|
|
#define LPS25H_DIFF_EN (1 << 3)
|
|
#define LPS25H_FIFO_EN (1 << 6)
|
|
#define LPS25H_WTM_EN (1 << 5)
|
|
#define LPS25H_FIFO_MEAN_DEC (1 << 4)
|
|
#define LPS25H_PD (1 << 7)
|
|
#define LPS25H_ONE_SHOT (1 << 0)
|
|
#define LPS25H_INT_H_L (1 << 7)
|
|
#define LPS25H_PP_OD (1 << 6)
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
struct lps25h_dev_s
|
|
{
|
|
FAR struct i2c_master_s *i2c;
|
|
uint8_t addr;
|
|
bool irqenabled;
|
|
volatile bool int_pending;
|
|
mutex_t devlock;
|
|
sem_t waitsem;
|
|
FAR lps25h_config_t *config;
|
|
};
|
|
|
|
enum LPS25H_RES_CONF_AVG_PRES
|
|
{
|
|
PRES_AVG_8 = 0,
|
|
PRES_AVG_32,
|
|
PRES_AVG_128,
|
|
PRES_AVG_512
|
|
};
|
|
|
|
enum LPS25H_RES_CONF_AVG_TEMP
|
|
{
|
|
TEMP_AVG_8 = 0,
|
|
TEMP_AVG_16,
|
|
TEMP_AVG_32,
|
|
TEMP_AVG_64
|
|
};
|
|
|
|
enum LPS25H_CTRL_REG1_ODR
|
|
{
|
|
CTRL_REG1_ODR_ONE_SHOT = 0,
|
|
CTRL_REG1_ODR_1HZ,
|
|
CTRL_REG1_ODR_7HZ,
|
|
CTRL_REG1_ODR_12_5HZ,
|
|
CTRL_REG1_ODR_25HZ
|
|
};
|
|
|
|
enum LPS25H_CTRL_REG4_P1
|
|
{
|
|
P1_DRDY = 0x1,
|
|
P1_OVERRUN = 0x02,
|
|
P1_WTM = 0x04,
|
|
P1_EMPTY = 0x08
|
|
};
|
|
|
|
enum LPS25H_FIFO_CTRL_MODE
|
|
{
|
|
BYPASS_MODE = 0x0,
|
|
FIFO_STOP_WHEN_FULL,
|
|
STREAM_NEWEST_IN_FIFO,
|
|
STREAM_DEASSERTED,
|
|
BYPASS_DEASSERTED_STREAM,
|
|
FIFO_MEAN = 0x06,
|
|
BYPASS_DEASSERTED_FIFO
|
|
};
|
|
|
|
enum LPS25H_FIFO_CTRL_WTM
|
|
{
|
|
SAMPLE_2 = 0x01,
|
|
SAMPLE_4 = 0x03,
|
|
SAMPLE_8 = 0x07,
|
|
SAMPLE_16 = 0x0f,
|
|
SAMPLE_32 = 0x1f
|
|
};
|
|
|
|
enum LPS25H_INT_CFG_OP
|
|
{
|
|
PH_E = 0x1,
|
|
PL_E = 0x2,
|
|
LIR = 0x4
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static int lps25h_open(FAR struct file *filep);
|
|
static int lps25h_close(FAR struct file *filep);
|
|
static ssize_t lps25h_read(FAR struct file *filep, FAR char *buffer,
|
|
size_t buflen);
|
|
static ssize_t lps25h_write(FAR struct file *filep, FAR const char *buffer,
|
|
size_t buflen);
|
|
static int lps25h_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
|
|
|
static int lps25h_configure_dev(FAR struct lps25h_dev_s *dev);
|
|
static int lps25h_read_pressure(FAR struct lps25h_dev_s *dev,
|
|
FAR lps25h_pressure_data_t *pres);
|
|
static int lps25h_read_temper(FAR struct lps25h_dev_s *dev,
|
|
FAR lps25h_temper_data_t *temper);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static const struct file_operations g_lps25hops =
|
|
{
|
|
lps25h_open, /* open */
|
|
lps25h_close, /* close */
|
|
lps25h_read, /* read */
|
|
lps25h_write, /* write */
|
|
NULL, /* seek */
|
|
lps25h_ioctl, /* ioctl */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
static int lps25h_do_transfer(FAR struct lps25h_dev_s *dev,
|
|
FAR struct i2c_msg_s *msgv,
|
|
size_t nmsg)
|
|
{
|
|
int ret = -EIO;
|
|
int retries;
|
|
|
|
for (retries = 0; retries < LPS25H_I2C_RETRIES; retries++)
|
|
{
|
|
ret = I2C_TRANSFER(dev->i2c, msgv, nmsg);
|
|
if (ret >= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
/* Some error. Try to reset I2C bus and keep trying. */
|
|
|
|
#ifdef CONFIG_I2C_RESET
|
|
if (retries == LPS25H_I2C_RETRIES - 1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ret = I2C_RESET(dev->i2c);
|
|
if (ret < 0)
|
|
{
|
|
lps25h_dbg("I2C_RESET failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
lps25h_dbg("xfer failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static int lps25h_write_reg8(FAR struct lps25h_dev_s *dev, uint8_t reg_addr,
|
|
const uint8_t value)
|
|
{
|
|
struct i2c_msg_s msgv[2] =
|
|
{
|
|
{
|
|
.frequency = CONFIG_LPS25H_I2C_FREQUENCY,
|
|
.addr = dev->addr,
|
|
.flags = 0,
|
|
.buffer = ®_addr,
|
|
.length = 1
|
|
},
|
|
{
|
|
.frequency = CONFIG_LPS25H_I2C_FREQUENCY,
|
|
.addr = dev->addr,
|
|
.flags = I2C_M_NOSTART,
|
|
.buffer = (FAR void *)&value,
|
|
.length = 1
|
|
}
|
|
};
|
|
|
|
return lps25h_do_transfer(dev, msgv, 2);
|
|
}
|
|
|
|
static int lps25h_read_reg8(FAR struct lps25h_dev_s *dev,
|
|
FAR uint8_t *reg_addr,
|
|
FAR uint8_t *value)
|
|
{
|
|
struct i2c_msg_s msgv[2] =
|
|
{
|
|
{
|
|
.frequency = CONFIG_LPS25H_I2C_FREQUENCY,
|
|
.addr = dev->addr,
|
|
.flags = 0,
|
|
.buffer = reg_addr,
|
|
.length = 1
|
|
},
|
|
{
|
|
.frequency = CONFIG_LPS25H_I2C_FREQUENCY,
|
|
.addr = dev->addr,
|
|
.flags = I2C_M_READ,
|
|
.buffer = value,
|
|
.length = 1
|
|
}
|
|
};
|
|
|
|
return lps25h_do_transfer(dev, msgv, 2);
|
|
}
|
|
|
|
static int lps25h_power_on_off(FAR struct lps25h_dev_s *dev, bool on)
|
|
{
|
|
int ret;
|
|
uint8_t value;
|
|
|
|
value = on ? LPS25H_PD : 0;
|
|
ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG1, value);
|
|
return ret;
|
|
}
|
|
|
|
static int lps25h_open(FAR struct file *filep)
|
|
{
|
|
FAR struct inode *inode = filep->f_inode;
|
|
FAR struct lps25h_dev_s *dev = inode->i_private;
|
|
uint8_t value = 0;
|
|
uint8_t addr = LPS25H_WHO_AM_I;
|
|
int32_t ret;
|
|
|
|
/* Get exclusive access */
|
|
|
|
ret = nxmutex_lock(&dev->devlock);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
dev->config->set_power(dev->config, true);
|
|
ret = lps25h_read_reg8(dev, &addr, &value);
|
|
if (ret < 0)
|
|
{
|
|
lps25h_dbg("Cannot read device's ID\n");
|
|
dev->config->set_power(dev->config, false);
|
|
goto out;
|
|
}
|
|
|
|
lps25h_dbg("WHO_AM_I: 0x%2x\n", value);
|
|
|
|
dev->config->irq_enable(dev->config, true);
|
|
dev->irqenabled = true;
|
|
|
|
out:
|
|
nxmutex_unlock(&dev->devlock);
|
|
return ret;
|
|
}
|
|
|
|
static int lps25h_close(FAR struct file *filep)
|
|
{
|
|
FAR struct inode *inode = filep->f_inode;
|
|
FAR struct lps25h_dev_s *dev = inode->i_private;
|
|
int ret;
|
|
|
|
/* Get exclusive access */
|
|
|
|
ret = nxmutex_lock(&dev->devlock);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
dev->config->irq_enable(dev->config, false);
|
|
dev->irqenabled = false;
|
|
ret = lps25h_power_on_off(dev, false);
|
|
dev->config->set_power(dev->config, false);
|
|
lps25h_dbg("CLOSED\n");
|
|
|
|
nxmutex_unlock(&dev->devlock);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t lps25h_read(FAR struct file *filep, FAR char *buffer,
|
|
size_t buflen)
|
|
{
|
|
FAR struct inode *inode = filep->f_inode;
|
|
FAR struct lps25h_dev_s *dev = inode->i_private;
|
|
lps25h_pressure_data_t data;
|
|
ssize_t length = 0;
|
|
int ret;
|
|
|
|
/* Get exclusive access */
|
|
|
|
ret = nxmutex_lock(&dev->devlock);
|
|
if (ret < 0)
|
|
{
|
|
return (ssize_t)ret;
|
|
}
|
|
|
|
ret = lps25h_configure_dev(dev);
|
|
if (ret < 0)
|
|
{
|
|
lps25h_dbg("cannot configure sensor: %d\n", ret);
|
|
goto out;
|
|
}
|
|
|
|
ret = lps25h_read_pressure(dev, &data);
|
|
if (ret < 0)
|
|
{
|
|
lps25h_dbg("cannot read data: %d\n", ret);
|
|
}
|
|
else
|
|
{
|
|
/* This interface is mainly intended for easy debugging in nsh. */
|
|
|
|
length = snprintf(buffer, buflen, "%u\n", data.pressure_pa);
|
|
if (length > buflen)
|
|
{
|
|
length = buflen;
|
|
}
|
|
}
|
|
|
|
out:
|
|
nxmutex_unlock(&dev->devlock);
|
|
return length;
|
|
}
|
|
|
|
static ssize_t lps25h_write(FAR struct file *filep, FAR const char *buffer,
|
|
size_t buflen)
|
|
{
|
|
ssize_t length = 0;
|
|
|
|
return length;
|
|
}
|
|
|
|
static void lps25h_notify(FAR struct lps25h_dev_s *dev)
|
|
{
|
|
DEBUGASSERT(dev != NULL);
|
|
|
|
dev->int_pending = true;
|
|
nxsem_post(&dev->waitsem);
|
|
}
|
|
|
|
static int lps25h_int_handler(int irq, FAR void *context, FAR void *arg)
|
|
{
|
|
FAR struct lps25h_dev_s *dev = (FAR struct lps25h_dev_s *)arg;
|
|
|
|
DEBUGASSERT(dev != NULL);
|
|
|
|
lps25h_notify(dev);
|
|
lps25h_dbg("lps25h interrupt\n");
|
|
return OK;
|
|
}
|
|
|
|
static int lps25h_configure_dev(FAR struct lps25h_dev_s *dev)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = lps25h_power_on_off(dev, false);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* Enable FIFO */
|
|
|
|
ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG2, LPS25H_FIFO_EN);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = lps25h_write_reg8(dev, LPS25H_FIFO_CTRL, (BYPASS_MODE << 5));
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG4, P1_DRDY);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* Write CTRL_REG1 to turn device on */
|
|
|
|
ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG1,
|
|
LPS25H_PD | (CTRL_REG1_ODR_1HZ << 4));
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int lps25h_one_shot(FAR struct lps25h_dev_s *dev)
|
|
{
|
|
int ret = ERROR;
|
|
int retries;
|
|
irqstate_t flags;
|
|
|
|
if (!dev->irqenabled)
|
|
{
|
|
lps25h_dbg("IRQ disabled!\n");
|
|
}
|
|
|
|
/* Retry one-shot measurement multiple times. */
|
|
|
|
for (retries = 0; retries < LPS25H_MAX_RETRIES; retries++)
|
|
{
|
|
/* Power off so we start from a known state. */
|
|
|
|
ret = lps25h_power_on_off(dev, false);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* Initiate a one shot mode measurement */
|
|
|
|
ret = lps25h_write_reg8(dev, LPS25H_CTRL_REG2, LPS25H_ONE_SHOT);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
/* Power on to start measurement. */
|
|
|
|
ret = lps25h_power_on_off(dev, true);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = nxsem_tickwait_uninterruptible(&dev->waitsem,
|
|
MSEC2TICK(LPS25H_RETRY_TIMEOUT_MSECS));
|
|
if (ret == OK)
|
|
{
|
|
break;
|
|
}
|
|
else if (ret == -ETIMEDOUT)
|
|
{
|
|
uint8_t reg = LPS25H_CTRL_REG2;
|
|
uint8_t value;
|
|
|
|
/* In 'AN4450 - Hardware and software guidelines for use of
|
|
* LPS25H pressure sensors' - '4.3 One-shot mode measurement
|
|
* sequence', one-shot mode example is given where interrupt line
|
|
* is not used, but CTRL_REG2 is polled until ONE_SHOT bit is
|
|
* unset (as it is self-clearing). Check ONE_SHOT bit status here
|
|
* to see if we just missed interrupt.
|
|
*/
|
|
|
|
ret = lps25h_read_reg8(dev, ®, &value);
|
|
if (ret == OK && (value & LPS25H_ONE_SHOT) == 0)
|
|
{
|
|
/* One-shot completed. */
|
|
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Some unknown mystery error */
|
|
|
|
DEBUGASSERT(ret == -ECANCELED);
|
|
return ret;
|
|
}
|
|
|
|
lps25h_dbg("Retrying one-shot measurement: retries=%d\n", retries);
|
|
}
|
|
|
|
if (ret != OK)
|
|
{
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
flags = enter_critical_section();
|
|
dev->int_pending = false;
|
|
leave_critical_section(flags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int lps25h_read_pressure(FAR struct lps25h_dev_s *dev,
|
|
FAR lps25h_pressure_data_t *pres)
|
|
{
|
|
int ret;
|
|
uint8_t pres_addr_h = LPS25H_PRESS_OUT_H;
|
|
uint8_t pres_addr_l = LPS25H_PRESS_OUT_L;
|
|
uint8_t pres_addr_xl = LPS25H_PRESS_POUT_XL;
|
|
uint8_t pres_value_h = 0;
|
|
uint8_t pres_value_l = 0;
|
|
uint8_t pres_value_xl = 0;
|
|
int32_t pres_res = 0;
|
|
|
|
ret = lps25h_one_shot(dev);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = lps25h_read_reg8(dev, &pres_addr_h, &pres_value_h);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = lps25h_read_reg8(dev, &pres_addr_l, &pres_value_l);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = lps25h_read_reg8(dev, &pres_addr_xl, &pres_value_xl);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
pres_res = ((int32_t) pres_value_h << 16) |
|
|
((int16_t) pres_value_l << 8) |
|
|
pres_value_xl;
|
|
|
|
/* Add to entropy pool. */
|
|
|
|
add_sensor_randomness(pres_res);
|
|
|
|
/* Convert to more usable format. */
|
|
|
|
pres->pressure_int_hp =
|
|
pres_res / LPS25H_PRESSURE_INTERNAL_DIVIDER;
|
|
pres->pressure_pa = (uint64_t)
|
|
pres_res * 100000 / LPS25H_PRESSURE_INTERNAL_DIVIDER;
|
|
pres->raw_data = pres_res;
|
|
|
|
lps25h_dbg("Pressure: %u Pa\n", pres->pressure_pa);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int lps25h_read_temper(FAR struct lps25h_dev_s *dev,
|
|
FAR lps25h_temper_data_t *temper)
|
|
{
|
|
int ret;
|
|
uint8_t temper_addr_h = LPS25H_TEMP_OUT_H;
|
|
uint8_t temper_addr_l = LPS25H_TEMP_OUT_L;
|
|
uint8_t temper_value_h = 0;
|
|
uint8_t temper_value_l = 0;
|
|
int32_t temper_res;
|
|
int16_t raw_data;
|
|
|
|
ret = lps25h_read_reg8(dev, &temper_addr_h, &temper_value_h);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
ret = lps25h_read_reg8(dev, &temper_addr_l, &temper_value_l);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
raw_data = (temper_value_h << 8) | temper_value_l;
|
|
|
|
/* Add to entropy pool. */
|
|
|
|
add_sensor_randomness(raw_data);
|
|
|
|
/* T(⁰C) = 42.5 + (raw / 480)
|
|
* =>
|
|
* T(⁰C) * scale = (425 * 48 + raw) * scale / 480;
|
|
*/
|
|
|
|
temper_res = (425 * 48 + raw_data);
|
|
temper_res *= LPS25H_TEMPER_DIVIDER;
|
|
temper_res /= 480;
|
|
|
|
temper->int_temper = temper_res;
|
|
temper->raw_data = raw_data;
|
|
lps25h_dbg("Temperature: %d\n", temper_res);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int lps25h_who_am_i(FAR struct lps25h_dev_s *dev,
|
|
lps25h_who_am_i_data * who_am_i_data)
|
|
{
|
|
uint8_t who_addr = LPS25H_WHO_AM_I;
|
|
return lps25h_read_reg8(dev, &who_addr, &who_am_i_data->who_am_i);
|
|
}
|
|
|
|
static int lps25h_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|
{
|
|
FAR struct inode *inode = filep->f_inode;
|
|
FAR struct lps25h_dev_s *dev = inode->i_private;
|
|
int ret;
|
|
|
|
/* Get exclusive access */
|
|
|
|
ret = nxmutex_lock(&dev->devlock);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
switch (cmd)
|
|
{
|
|
case SNIOC_CFGR:
|
|
ret = lps25h_configure_dev(dev);
|
|
break;
|
|
|
|
case SNIOC_PRESSURE_OUT:
|
|
ret = lps25h_read_pressure(dev, (FAR lps25h_pressure_data_t *)arg);
|
|
break;
|
|
|
|
case SNIOC_TEMPERATURE_OUT:
|
|
/* NOTE: call SNIOC_PRESSURE_OUT before this one,
|
|
* or results are bogus.
|
|
*/
|
|
|
|
ret = lps25h_read_temper(dev, (FAR lps25h_temper_data_t *)arg);
|
|
break;
|
|
|
|
case SNIOC_SENSOR_OFF:
|
|
ret = lps25h_power_on_off(dev, false);
|
|
break;
|
|
|
|
case SNIOC_GET_DEV_ID:
|
|
ret = lps25h_who_am_i(dev, (FAR lps25h_who_am_i_data *)arg);
|
|
break;
|
|
|
|
default:
|
|
ret = -ENOTTY;
|
|
break;
|
|
}
|
|
|
|
nxmutex_unlock(&dev->devlock);
|
|
return ret;
|
|
}
|
|
|
|
int lps25h_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
|
|
uint8_t addr, FAR lps25h_config_t *config)
|
|
{
|
|
int ret = 0;
|
|
FAR struct lps25h_dev_s *dev;
|
|
|
|
dev = kmm_zalloc(sizeof(struct lps25h_dev_s));
|
|
if (!dev)
|
|
{
|
|
lps25h_dbg("Memory cannot be allocated for LPS25H sensor\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
nxmutex_init(&dev->devlock);
|
|
nxsem_init(&dev->waitsem, 0, 0);
|
|
|
|
dev->addr = addr;
|
|
dev->i2c = i2c;
|
|
dev->config = config;
|
|
|
|
if (dev->config->irq_clear)
|
|
{
|
|
dev->config->irq_clear(dev->config);
|
|
}
|
|
|
|
ret = register_driver(devpath, &g_lps25hops, 0600, dev);
|
|
|
|
lps25h_dbg("Registered with %d\n", ret);
|
|
|
|
if (ret < 0)
|
|
{
|
|
nxmutex_destroy(&dev->devlock);
|
|
nxsem_destroy(&dev->waitsem);
|
|
kmm_free(dev);
|
|
lps25h_dbg("Error occurred during the driver registering\n");
|
|
return ret;
|
|
}
|
|
|
|
dev->config->irq_attach(config, lps25h_int_handler, dev);
|
|
dev->config->irq_enable(config, false);
|
|
dev->irqenabled = false;
|
|
return OK;
|
|
}
|