664927c86e
Fix the minor style issue and remove unnecessary cast Signed-off-by: chao an <anchao@xiaomi.com>
995 lines
27 KiB
C
995 lines
27 KiB
C
/****************************************************************************
|
|
* boards/arm/cxd56xx/drivers/sensors/bmp280_scu.c
|
|
*
|
|
* 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 <nuttx/config.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <fixedmath.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <debug.h>
|
|
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/fs/fs.h>
|
|
#include <nuttx/i2c/i2c_master.h>
|
|
#include <nuttx/sensors/bmp280.h>
|
|
#include <arch/chip/scu.h>
|
|
|
|
#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_BMP280_SCU)
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_SENSORS_BMI280_SCU_DECI_PRESS
|
|
# define PRESS_SEQ_TYPE SEQ_TYPE_DECI
|
|
#else
|
|
# define PRESS_SEQ_TYPE SEQ_TYPE_NORMAL
|
|
#endif
|
|
#ifdef CONFIG_SENSORS_BMI280_SCU_DECI_TEMP
|
|
# define TEMP_SEQ_TYPE SEQ_TYPE_DECI
|
|
#else
|
|
# define TEMP_SEQ_TYPE SEQ_TYPE_NORMAL
|
|
#endif
|
|
|
|
#define BMP280_ADDR 0x76
|
|
#define BMP280_FREQ 400000
|
|
#define DEVID 0x58
|
|
|
|
#define BMP280_DIG_T1_LSB 0x88
|
|
#define BMP280_DIG_T1_MSB 0x89
|
|
#define BMP280_DIG_T2_LSB 0x8a
|
|
#define BMP280_DIG_T2_MSB 0x8b
|
|
#define BMP280_DIG_T3_LSB 0x8c
|
|
#define BMP280_DIG_T3_MSB 0x8d
|
|
#define BMP280_DIG_P1_LSB 0x8e
|
|
#define BMP280_DIG_P1_MSB 0x8f
|
|
#define BMP280_DIG_P2_LSB 0x90
|
|
#define BMP280_DIG_P2_MSB 0x91
|
|
#define BMP280_DIG_P3_LSB 0x92
|
|
#define BMP280_DIG_P3_MSB 0x93
|
|
#define BMP280_DIG_P4_LSB 0x94
|
|
#define BMP280_DIG_P4_MSB 0x95
|
|
#define BMP280_DIG_P5_LSB 0x96
|
|
#define BMP280_DIG_P5_MSB 0x97
|
|
#define BMP280_DIG_P6_LSB 0x98
|
|
#define BMP280_DIG_P6_MSB 0x99
|
|
#define BMP280_DIG_P7_LSB 0x9a
|
|
#define BMP280_DIG_P7_MSB 0x9b
|
|
#define BMP280_DIG_P8_LSB 0x9c
|
|
#define BMP280_DIG_P8_MSB 0x9d
|
|
#define BMP280_DIG_P9_LSB 0x9e
|
|
#define BMP280_DIG_P9_MSB 0x9f
|
|
|
|
#define BMP280_DEVID 0xd0
|
|
#define BMP280_SOFT_RESET 0xe0
|
|
#define BMP280_STAT 0xf3
|
|
#define BMP280_CTRL_MEAS 0xf4
|
|
#define BMP280_CONFIG 0xf5
|
|
#define BMP280_PRESS_MSB 0xf7
|
|
#define BMP280_PRESS_LSB 0xf8
|
|
#define BMP280_PRESS_XLSB 0xf9
|
|
#define BMP280_TEMP_MSB 0xfa
|
|
#define BMP280_TEMP_LSB 0xfb
|
|
#define BMP280_TEMP_XLSB 0xfc
|
|
|
|
/* power mode */
|
|
|
|
#define BMP280_SLEEP_MODE 0x00
|
|
#define BMP280_FORCED_MODE 0x01
|
|
#define BMP280_NORMAL_MODE 0x03
|
|
|
|
/* oversampling */
|
|
|
|
#define BMP280_OVERSAMP_SKIPPED 0x00
|
|
#define BMP280_OVERSAMP_1X 0x01
|
|
#define BMP280_OVERSAMP_2X 0x02
|
|
#define BMP280_OVERSAMP_4X 0x03
|
|
#define BMP280_OVERSAMP_8X 0x04
|
|
#define BMP280_OVERSAMP_16X 0x05
|
|
|
|
/* BMP280 have press and temp, pressure respectively in 24 bits.
|
|
*/
|
|
|
|
#define BMP280PRESS_BYTESPERSAMPLE 3
|
|
#define BMP280PRESS_ELEMENTSIZE 3
|
|
#define BMP280TEMP_BYTESPERSAMPLE 3
|
|
#define BMP280TEMP_ELEMENTSIZE 3
|
|
|
|
#ifndef itemsof
|
|
# define itemsof(array) (sizeof(array)/sizeof(array[0]))
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Private Type Definitions
|
|
****************************************************************************/
|
|
|
|
struct bmp280_dev_s
|
|
{
|
|
struct i2c_master_s *i2c; /* I2C interface */
|
|
uint8_t addr; /* BMP280 I2C address */
|
|
int freq; /* BMP280 Frequency <= 3.4MHz */
|
|
int port; /* I2C port */
|
|
struct seq_s *seq; /* Sequencer */
|
|
int id; /* Sequencer id */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
static uint8_t bmp280_getreg8(struct bmp280_dev_s *priv,
|
|
uint8_t regaddr);
|
|
static void bmp280_putreg8(struct bmp280_dev_s *priv,
|
|
uint8_t regaddr,
|
|
uint8_t regval);
|
|
|
|
/* Character driver methods */
|
|
|
|
static int bmp280_open_press(struct file *filep);
|
|
static int bmp280_open_temp(struct file *filep);
|
|
static int bmp280_close_press(struct file *filep);
|
|
static int bmp280_close_temp(struct file *filep);
|
|
static ssize_t bmp280_read_press(struct file *filep, char *buffer,
|
|
size_t buflen);
|
|
static ssize_t bmp280_read_temp(struct file *filep, char *buffer,
|
|
size_t buflen);
|
|
static ssize_t bmp280_write(struct file *filep, const char *buffer,
|
|
size_t buflen);
|
|
static int bmp280_ioctl_press(struct file *filep, int cmd,
|
|
unsigned long arg);
|
|
static int bmp280_ioctl_temp(struct file *filep, int cmd,
|
|
unsigned long arg);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
/* This the vtable that supports the character driver interface */
|
|
|
|
static const struct file_operations g_bmp280pressfops =
|
|
{
|
|
bmp280_open_press, /* open */
|
|
bmp280_close_press, /* close */
|
|
bmp280_read_press, /* read */
|
|
bmp280_write, /* write */
|
|
NULL, /* seek */
|
|
bmp280_ioctl_press /* ioctl */
|
|
};
|
|
|
|
static const struct file_operations g_bmp280tempfops =
|
|
{
|
|
bmp280_open_temp, /* open */
|
|
bmp280_close_temp, /* close */
|
|
bmp280_read_temp, /* read */
|
|
bmp280_write, /* write */
|
|
NULL, /* seek */
|
|
bmp280_ioctl_temp /* ioctl */
|
|
};
|
|
|
|
/* SCU instructions for pick pressure sensing data. */
|
|
|
|
static const uint16_t g_bmp280pressinst[] =
|
|
{
|
|
SCU_INST_SEND(BMP280_PRESS_MSB),
|
|
SCU_INST_RECV(BMP280PRESS_BYTESPERSAMPLE) | SCU_INST_LAST,
|
|
};
|
|
|
|
/* SCU instructions for pick temperature sensing data. */
|
|
|
|
static const uint16_t g_bmp280tempinst[] =
|
|
{
|
|
SCU_INST_SEND(BMP280_TEMP_MSB),
|
|
SCU_INST_RECV(BMP280TEMP_BYTESPERSAMPLE) | SCU_INST_LAST,
|
|
};
|
|
|
|
/* driver reference counter */
|
|
|
|
static int g_refcnt_press = 0;
|
|
static int g_refcnt_temp = 0;
|
|
|
|
/* senser calibration parameters */
|
|
|
|
static struct bmp280_press_adj_s g_press_adj;
|
|
static struct bmp280_temp_adj_s g_temp_adj;
|
|
|
|
/* Sequencer instance */
|
|
|
|
static struct seq_s *g_seq_press = NULL;
|
|
static struct seq_s *g_seq_temp = NULL;
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_getreg8
|
|
*
|
|
* Description:
|
|
* Read from an 8-bit BMP280 register
|
|
*
|
|
****************************************************************************/
|
|
|
|
static uint8_t bmp280_getreg8(struct bmp280_dev_s *priv, uint8_t regaddr)
|
|
{
|
|
uint8_t regval = 0;
|
|
uint16_t inst[2];
|
|
|
|
/* Send register to read and get the next byte */
|
|
|
|
inst[0] = SCU_INST_SEND(regaddr);
|
|
inst[1] = SCU_INST_RECV(1) | SCU_INST_LAST;
|
|
|
|
scu_i2ctransfer(priv->port, priv->addr, inst, 2, ®val, 1);
|
|
|
|
return regval;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_putreg8
|
|
*
|
|
* Description:
|
|
* Write to an 8-bit BMP280 register
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void bmp280_putreg8(struct bmp280_dev_s *priv, uint8_t regaddr,
|
|
uint8_t regval)
|
|
{
|
|
uint16_t inst[2];
|
|
|
|
/* Send register address and set the value */
|
|
|
|
inst[0] = SCU_INST_SEND(regaddr);
|
|
inst[1] = SCU_INST_SEND(regval) | SCU_INST_LAST;
|
|
|
|
scu_i2ctransfer(priv->port, priv->addr, inst, 2, NULL, 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_checkid
|
|
*
|
|
* Description:
|
|
* Read and verify the BMP280 chip ID
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_checkid(struct bmp280_dev_s *priv)
|
|
{
|
|
uint8_t devid = 0;
|
|
|
|
/* Read device ID */
|
|
|
|
devid = bmp280_getreg8(priv, BMP280_DEVID);
|
|
sninfo("devid: 0x%02x\n", devid);
|
|
|
|
if (devid != (uint16_t)DEVID)
|
|
{
|
|
/* ID is not Correct */
|
|
|
|
snerr("Wrong Device ID! %02x\n", devid);
|
|
return -ENODEV;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_get_calib_param
|
|
*
|
|
* Description:
|
|
* Read Calibration Coefficient Data
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_get_calib_param_press(struct bmp280_dev_s *priv)
|
|
{
|
|
/* Read calibration values */
|
|
|
|
g_press_adj.dig_p1 =
|
|
((uint16_t)bmp280_getreg8(priv, BMP280_DIG_P1_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P1_LSB);
|
|
g_press_adj.dig_p2 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_P2_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P2_LSB);
|
|
g_press_adj.dig_p3 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_P3_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P3_LSB);
|
|
g_press_adj.dig_p4 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_P4_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P4_LSB);
|
|
g_press_adj.dig_p5 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_P5_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P5_LSB);
|
|
g_press_adj.dig_p6 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_P6_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P6_LSB);
|
|
g_press_adj.dig_p7 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_P7_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P7_LSB);
|
|
g_press_adj.dig_p8 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_P8_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P8_LSB);
|
|
g_press_adj.dig_p9 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_P9_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_P9_LSB);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_get_calib_param_temp
|
|
*
|
|
* Description:
|
|
* Read Calibration Coefficient Data
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_get_calib_param_temp(struct bmp280_dev_s *priv)
|
|
{
|
|
/* Read calibration values */
|
|
|
|
g_temp_adj.dig_t1 =
|
|
((uint16_t)bmp280_getreg8(priv, BMP280_DIG_T1_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_T1_LSB);
|
|
g_temp_adj.dig_t2 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_T2_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_T2_LSB);
|
|
g_temp_adj.dig_t3 =
|
|
((int16_t)bmp280_getreg8(priv, BMP280_DIG_T3_MSB) << 8) |
|
|
bmp280_getreg8(priv, BMP280_DIG_T3_LSB);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_set_power_mode
|
|
*
|
|
* Description:
|
|
* set power mode
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void bmp280_set_power_mode(struct bmp280_dev_s *priv,
|
|
uint8_t value)
|
|
{
|
|
uint8_t v_data_u8 = 0;
|
|
|
|
v_data_u8 = bmp280_getreg8(priv, BMP280_CTRL_MEAS);
|
|
v_data_u8 = ((v_data_u8 & ~0x03) | value);
|
|
bmp280_putreg8(priv, BMP280_CTRL_MEAS, v_data_u8);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_set_oversamp_press
|
|
*
|
|
* Description:
|
|
* set oversampling rate
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void bmp280_set_oversamp_press(struct bmp280_dev_s *priv,
|
|
uint8_t value)
|
|
{
|
|
uint8_t v_data_u8 = 0;
|
|
|
|
v_data_u8 = bmp280_getreg8(priv, BMP280_CTRL_MEAS);
|
|
v_data_u8 = ((v_data_u8 & ~(0x07 << 2)) | ((value << 2) & (0x07 << 2)));
|
|
bmp280_putreg8(priv, BMP280_CTRL_MEAS, v_data_u8);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_set_oversamp_temp
|
|
*
|
|
* Description:
|
|
* set oversampling rate
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void bmp280_set_oversamp_temp(struct bmp280_dev_s *priv,
|
|
uint8_t value)
|
|
{
|
|
uint8_t v_data_u8 = 0;
|
|
|
|
v_data_u8 = bmp280_getreg8(priv, BMP280_CTRL_MEAS);
|
|
v_data_u8 = ((v_data_u8 & ~(0x07 << 5)) | ((value << 5) & (0x07 << 5)));
|
|
bmp280_putreg8(priv, BMP280_CTRL_MEAS, v_data_u8);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_set_standby
|
|
*
|
|
* Description:
|
|
* set standby duration
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_set_standby(struct bmp280_dev_s *priv, uint8_t value)
|
|
{
|
|
uint8_t v_data_u8;
|
|
uint8_t v_sb_u8;
|
|
|
|
/* Set the standby duration value */
|
|
|
|
v_data_u8 = bmp280_getreg8(priv, BMP280_CONFIG);
|
|
v_data_u8 = (v_data_u8 & ~(0x07 << 5)) | (value << 5);
|
|
bmp280_putreg8(priv, BMP280_CONFIG, v_data_u8);
|
|
|
|
/* Check the standby duration value */
|
|
|
|
v_data_u8 = bmp280_getreg8(priv, BMP280_CONFIG);
|
|
v_sb_u8 = (v_data_u8 >> 5) & 0x07;
|
|
|
|
if (v_sb_u8 != value)
|
|
{
|
|
snerr("Failed to set value for standby time.");
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_initialize
|
|
*
|
|
* Description:
|
|
* Initialize BMP280 pressure sensor
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_initialize(struct bmp280_dev_s *priv)
|
|
{
|
|
int ret;
|
|
|
|
ret = bmp280_set_standby(priv, BMP280_STANDBY_05_MS);
|
|
|
|
if (ret != OK)
|
|
{
|
|
snerr("Failed to set value for standby time.");
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int bmp280_seqinit_press(struct bmp280_dev_s *priv)
|
|
{
|
|
DEBUGASSERT(!g_seq_press);
|
|
|
|
/* Open sequencer */
|
|
|
|
g_seq_press = seq_open(PRESS_SEQ_TYPE, SCU_BUS_I2C0);
|
|
if (!g_seq_press)
|
|
{
|
|
return -ENOENT;
|
|
}
|
|
|
|
priv->seq = g_seq_press;
|
|
|
|
seq_setaddress(priv->seq, priv->addr);
|
|
|
|
/* Set instruction and sample data information to sequencer */
|
|
|
|
seq_setinstruction(priv->seq, g_bmp280pressinst,
|
|
itemsof(g_bmp280pressinst));
|
|
seq_setsample(priv->seq, BMP280PRESS_BYTESPERSAMPLE, 0,
|
|
BMP280PRESS_ELEMENTSIZE, false);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int bmp280_seqinit_temp(struct bmp280_dev_s *priv)
|
|
{
|
|
DEBUGASSERT(!g_seq_temp);
|
|
|
|
/* Open sequencer */
|
|
|
|
g_seq_temp = seq_open(TEMP_SEQ_TYPE, SCU_BUS_I2C0);
|
|
if (!g_seq_temp)
|
|
{
|
|
return -ENOENT;
|
|
}
|
|
|
|
priv->seq = g_seq_temp;
|
|
|
|
seq_setaddress(priv->seq, priv->addr);
|
|
|
|
/* Set instruction and sample data information to sequencer */
|
|
|
|
seq_setinstruction(priv->seq, g_bmp280tempinst,
|
|
itemsof(g_bmp280tempinst));
|
|
seq_setsample(priv->seq, BMP280TEMP_BYTESPERSAMPLE, 0,
|
|
BMP280TEMP_ELEMENTSIZE, false);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_open_press
|
|
*
|
|
* Description:
|
|
* This function is called whenever the BMP280 device is opened.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_open_press(struct file *filep)
|
|
{
|
|
struct inode *inode = filep->f_inode;
|
|
struct bmp280_dev_s *priv = inode->i_private;
|
|
int ret;
|
|
|
|
/* first pressure device initialize */
|
|
|
|
if (g_refcnt_press == 0)
|
|
{
|
|
/* Open and set sequencer */
|
|
|
|
ret = bmp280_seqinit_press(priv);
|
|
if (ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
bmp280_get_calib_param_press(priv);
|
|
bmp280_set_oversamp_press(priv, BMP280_OVERSAMP_4X);
|
|
|
|
if (g_refcnt_temp == 0)
|
|
{
|
|
bmp280_set_power_mode(priv, BMP280_NORMAL_MODE);
|
|
bmp280_initialize(priv);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Set existing sequencer */
|
|
|
|
priv->seq = g_seq_press;
|
|
}
|
|
|
|
g_refcnt_press++;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_open_temp
|
|
*
|
|
* Description:
|
|
* This function is called whenever the BMP280 device is opened.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_open_temp(struct file *filep)
|
|
{
|
|
struct inode *inode = filep->f_inode;
|
|
struct bmp280_dev_s *priv = inode->i_private;
|
|
int ret;
|
|
|
|
/* first temperature device initialize */
|
|
|
|
if (g_refcnt_temp == 0)
|
|
{
|
|
/* Open and set sequencer */
|
|
|
|
ret = bmp280_seqinit_temp(priv);
|
|
if (ret)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
bmp280_get_calib_param_temp(priv);
|
|
bmp280_set_oversamp_temp(priv, BMP280_OVERSAMP_1X);
|
|
|
|
if (g_refcnt_press == 0)
|
|
{
|
|
bmp280_set_power_mode(priv, BMP280_NORMAL_MODE);
|
|
bmp280_initialize(priv);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Set existing sequencer */
|
|
|
|
priv->seq = g_seq_temp;
|
|
}
|
|
|
|
g_refcnt_temp++;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_close_press
|
|
*
|
|
* Description:
|
|
* This routine is called when the BMP280 device is closed.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_close_press(struct file *filep)
|
|
{
|
|
struct inode *inode = filep->f_inode;
|
|
struct bmp280_dev_s *priv = inode->i_private;
|
|
|
|
if (g_refcnt_press <= 1)
|
|
{
|
|
bmp280_set_oversamp_press(priv, BMP280_OVERSAMP_SKIPPED);
|
|
|
|
/* if close last BMP280 device, enter sleep mode */
|
|
|
|
if (g_refcnt_temp == 0)
|
|
{
|
|
bmp280_set_power_mode(priv, BMP280_SLEEP_MODE);
|
|
}
|
|
|
|
seq_close(g_seq_press);
|
|
g_seq_press = NULL;
|
|
}
|
|
else
|
|
{
|
|
seq_ioctl(priv->seq, priv->id, SCUIOC_FREEFIFO, 0);
|
|
}
|
|
|
|
g_refcnt_press--;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_close_temp
|
|
*
|
|
* Description:
|
|
* This routine is called when the BMP280 device is closed.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int bmp280_close_temp(struct file *filep)
|
|
{
|
|
struct inode *inode = filep->f_inode;
|
|
struct bmp280_dev_s *priv = inode->i_private;
|
|
|
|
if (g_refcnt_temp <= 1)
|
|
{
|
|
bmp280_set_oversamp_temp(priv, BMP280_OVERSAMP_SKIPPED);
|
|
|
|
/* if close last BMP280 device, enter sleep mode */
|
|
|
|
if (g_refcnt_press == 0)
|
|
{
|
|
bmp280_set_power_mode(priv, BMP280_SLEEP_MODE);
|
|
}
|
|
|
|
seq_close(g_seq_temp);
|
|
g_seq_temp = NULL;
|
|
}
|
|
else
|
|
{
|
|
seq_ioctl(priv->seq, priv->id, SCUIOC_FREEFIFO, 0);
|
|
}
|
|
|
|
g_refcnt_temp--;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_read_press
|
|
****************************************************************************/
|
|
|
|
static ssize_t bmp280_read_press(struct file *filep, char *buffer,
|
|
size_t buflen)
|
|
{
|
|
struct inode *inode = filep->f_inode;
|
|
struct bmp280_dev_s *priv = inode->i_private;
|
|
|
|
buflen = buflen / BMP280PRESS_BYTESPERSAMPLE * BMP280PRESS_BYTESPERSAMPLE;
|
|
buflen = seq_read(priv->seq, priv->id, buffer, buflen);
|
|
|
|
return buflen;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_read_temp
|
|
****************************************************************************/
|
|
|
|
static ssize_t bmp280_read_temp(struct file *filep, char *buffer,
|
|
size_t buflen)
|
|
{
|
|
struct inode *inode = filep->f_inode;
|
|
struct bmp280_dev_s *priv = inode->i_private;
|
|
|
|
buflen = buflen / BMP280TEMP_BYTESPERSAMPLE * BMP280TEMP_BYTESPERSAMPLE;
|
|
buflen = seq_read(priv->seq, priv->id, buffer, buflen);
|
|
|
|
return buflen;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bm p280_write
|
|
****************************************************************************/
|
|
|
|
static ssize_t bmp280_write(struct file *filep, const char *buffer,
|
|
size_t buflen)
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_ioctrl_press
|
|
****************************************************************************/
|
|
|
|
static int bmp280_ioctl_press(struct file *filep, int cmd,
|
|
unsigned long arg)
|
|
{
|
|
struct inode *inode = filep->f_inode;
|
|
struct bmp280_dev_s *priv = inode->i_private;
|
|
int ret = OK;
|
|
|
|
switch (cmd)
|
|
{
|
|
/* Get sensitivity adjustment value
|
|
* Arg: Pointer to struct bmp280_press_adj_s
|
|
*/
|
|
|
|
case SNIOC_GETADJ:
|
|
{
|
|
struct bmp280_press_adj_s *user = (struct bmp280_press_adj_s *)
|
|
(uintptr_t)arg;
|
|
|
|
user->dig_p1 = g_press_adj.dig_p1;
|
|
user->dig_p2 = g_press_adj.dig_p2;
|
|
user->dig_p3 = g_press_adj.dig_p3;
|
|
user->dig_p4 = g_press_adj.dig_p4;
|
|
user->dig_p5 = g_press_adj.dig_p5;
|
|
user->dig_p6 = g_press_adj.dig_p6;
|
|
user->dig_p7 = g_press_adj.dig_p7;
|
|
user->dig_p8 = g_press_adj.dig_p8;
|
|
user->dig_p9 = g_press_adj.dig_p9;
|
|
}
|
|
break;
|
|
|
|
case SNIOC_SETSTB:
|
|
{
|
|
ret = bmp280_set_standby(priv, arg);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
if (_SCUIOCVALID(cmd))
|
|
{
|
|
/* Redirect SCU commands */
|
|
|
|
ret = seq_ioctl(priv->seq, priv->id, cmd, arg);
|
|
}
|
|
else
|
|
{
|
|
snerr("Unrecognized cmd: %d\n", cmd);
|
|
ret = - ENOTTY;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_ioctrl_temp
|
|
****************************************************************************/
|
|
|
|
static int bmp280_ioctl_temp(struct file *filep, int cmd,
|
|
unsigned long arg)
|
|
{
|
|
struct inode *inode = filep->f_inode;
|
|
struct bmp280_dev_s *priv = inode->i_private;
|
|
int ret = OK;
|
|
|
|
switch (cmd)
|
|
{
|
|
/* Get sensitivity adjustment value
|
|
* Arg: Pointer to struct bmp280_temp_adj_s
|
|
*/
|
|
|
|
case SNIOC_GETADJ:
|
|
{
|
|
struct bmp280_temp_adj_s *user = (struct bmp280_temp_adj_s *)
|
|
(uintptr_t)arg;
|
|
|
|
user->dig_t1 = g_temp_adj.dig_t1;
|
|
user->dig_t2 = g_temp_adj.dig_t2;
|
|
user->dig_t3 = g_temp_adj.dig_t3;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
if (_SCUIOCVALID(cmd))
|
|
{
|
|
/* Redirect SCU commands */
|
|
|
|
ret = seq_ioctl(priv->seq, priv->id, cmd, arg);
|
|
}
|
|
else
|
|
{
|
|
snerr("Unrecognized cmd: %d\n", cmd);
|
|
ret = - ENOTTY;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280_init
|
|
*
|
|
* Description:
|
|
* Initialize the I2C interface to use to communicate with BMP280
|
|
*
|
|
* Input Parameters:
|
|
* i2c - An instance of the I2C interface to use to communicate with
|
|
* BMP280
|
|
* port - I2C port number
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int bmp280_init(struct i2c_master_s *i2c, int port)
|
|
{
|
|
struct bmp280_dev_s tmp;
|
|
struct bmp280_dev_s *priv = &tmp;
|
|
int ret;
|
|
|
|
/* Setup temporary device structure for initialization */
|
|
|
|
priv->i2c = i2c;
|
|
priv->addr = BMP280_ADDR;
|
|
priv->freq = BMP280_FREQ;
|
|
priv->port = port;
|
|
|
|
/* Check Device ID */
|
|
|
|
ret = bmp280_checkid(priv);
|
|
if (ret < 0)
|
|
{
|
|
snerr("Failed to register driver: %d\n", ret);
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280press_register
|
|
*
|
|
* Description:
|
|
* Register the BMP280 pressure sensor character device as 'devpath'
|
|
*
|
|
* Input Parameters:
|
|
* devpath - The base path to the driver to register. E.g., "/dev/press0"
|
|
* dev - An instance of the I2C interface to use to communicate with
|
|
* BMP280
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int bmp280press_register(const char *devpath, int minor,
|
|
struct i2c_master_s *i2c, int port)
|
|
{
|
|
struct bmp280_dev_s *priv;
|
|
char path[12];
|
|
int ret;
|
|
|
|
priv = kmm_malloc(sizeof(struct bmp280_dev_s));
|
|
if (!priv)
|
|
{
|
|
snerr("Failed to allocate instance\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
priv->i2c = i2c;
|
|
priv->seq = NULL;
|
|
priv->id = minor;
|
|
priv->addr = BMP280_ADDR;
|
|
priv->freq = BMP280_FREQ;
|
|
priv->port = port;
|
|
|
|
/* Register the character driver */
|
|
|
|
snprintf(path, sizeof(path), "%s%d", devpath, minor);
|
|
ret = register_driver(path, &g_bmp280pressfops, 0666, priv);
|
|
if (ret < 0)
|
|
{
|
|
snerr("Failed to register driver: %d\n", ret);
|
|
kmm_free(priv);
|
|
}
|
|
|
|
sninfo("BMP280 pressure driver loaded successfully!\n");
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: bmp280temp_register
|
|
*
|
|
* Description:
|
|
* Register the BMP280 temperature sensor character device as 'devpath'
|
|
*
|
|
* Input Parameters:
|
|
* devpath - The base path to the driver to register. E.g., "/dev/temp"
|
|
* dev - An instance of the I2C interface to use to communicate with
|
|
* BMP280
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int bmp280temp_register(const char *devpath, int minor,
|
|
struct i2c_master_s *i2c, int port)
|
|
{
|
|
struct bmp280_dev_s *priv;
|
|
char path[12];
|
|
int ret;
|
|
|
|
priv = kmm_malloc(sizeof(struct bmp280_dev_s));
|
|
if (!priv)
|
|
{
|
|
snerr("Failed to allocate instance\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
priv->i2c = i2c;
|
|
priv->seq = NULL;
|
|
priv->id = minor;
|
|
priv->addr = BMP280_ADDR;
|
|
priv->freq = BMP280_FREQ;
|
|
priv->port = port;
|
|
|
|
/* Register the character driver */
|
|
|
|
snprintf(path, sizeof(path), "%s%d", devpath, minor);
|
|
ret = register_driver(path, &g_bmp280tempfops, 0666, priv);
|
|
if (ret < 0)
|
|
{
|
|
snerr("Failed to register driver: %d\n", ret);
|
|
kmm_free(priv);
|
|
}
|
|
|
|
sninfo("BMP280 temperature driver loaded successfully!\n");
|
|
return ret;
|
|
}
|
|
|
|
#endif /* CONFIG_I2C && CONFIG_SENSORS_BMP280_SCU */
|