Split the BMP280 / BME280 driver into common code and create I2C and

SPI attachments.
This commit is contained in:
brad 2022-12-03 01:04:42 +00:00
parent 86e4c4a8e3
commit 50bb9ed19f
17 changed files with 576 additions and 196 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: module.mi,v 1.22 2022/11/21 21:24:01 brad Exp $
# $NetBSD: module.mi,v 1.23 2022/12/03 01:04:43 brad Exp $
./usr/libdata/debug/@MODULEDIR@ modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/accf_dataready modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/accf_dataready/accf_dataready.kmod.debug modules-base-kernel kmod,debug
@ -24,6 +24,8 @@
./usr/libdata/debug/@MODULEDIR@/blowfish/blowfish.kmod.debug modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/bmx280thp modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/bmx280thp/bmx280thp.kmod.debug modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/bmx280thpi2c modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/bmx280thpi2c/bmx280thpi2c.kmod.debug modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/bpf modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/bpf/bpf.kmod.debug modules-base-kernel kmod,debug
./usr/libdata/debug/@MODULEDIR@/bpf_filter modules-base-kernel kmod,debug

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.156 2022/11/21 21:24:01 brad Exp $
# $NetBSD: mi,v 1.157 2022/12/03 01:04:43 brad Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -33,6 +33,8 @@
./@MODULEDIR@/blowfish/blowfish.kmod modules-base-kernel kmod
./@MODULEDIR@/bmx280thp modules-base-kernel kmod
./@MODULEDIR@/bmx280thp/bmx280thp.kmod modules-base-kernel kmod
./@MODULEDIR@/bmx280thpi2c modules-base-kernel kmod
./@MODULEDIR@/bmx280thpi2c/bmx280thpi2c.kmod modules-base-kernel kmod
./@MODULEDIR@/bpf modules-base-kernel kmod
./@MODULEDIR@/bpf/bpf.kmod modules-base-kernel kmod
./@MODULEDIR@/bpf_filter modules-base-kernel kmod

View File

@ -1,4 +1,4 @@
.\" $NetBSD: bmx280thp.4,v 1.4 2022/11/23 23:49:23 wiz Exp $
.\" $NetBSD: bmx280thp.4,v 1.5 2022/12/03 01:04:42 brad Exp $
.\"
.\" Copyright (c) 2022 Brad Spencer <brad@anduin.eldar.org>
.\"
@ -23,6 +23,9 @@
.Sh SYNOPSIS
.Cd "bmx280thp* at iic? addr 0x76"
.Cd "bmx280thp* at iic? addr 0x77"
.Cd "bmx280thp* at spi? slave 0"
.Cd "bmx280thp* at spi? slave 1"
.Sh DESCRIPTION
The
.Nm
@ -35,8 +38,14 @@ The
.Ar addr
argument selects the address at the
.Xr iic 4
bus and the
.Nm
.Ar slave
argument selects which chip select will be used on the
.Xr spi 4
bus.
The precision of the measurement can be changed through
The precision of the measurement which is related to the over
sampling performed on the measurement can be changed through
.Xr sysctl 8
nodes.
.Sh SYSCTL VARIABLES
@ -82,6 +91,7 @@ The default is 25 which should be more than enough for most purposes.
.Sh SEE ALSO
.Xr envsys 4 ,
.Xr iic 4 ,
.Xr spi 4 ,
.Xr envstat 8 ,
.Xr sysctl 8
.Sh HISTORY
@ -98,4 +108,3 @@ driver was written by
.Sh BUGS
The driver does not support the continuous read mode that the BMP280
and BME280 has.
This driver does not support the SPI interface.

View File

@ -1,4 +1,4 @@
.\" $NetBSD: spi.4,v 1.12 2021/12/07 17:50:27 brad Exp $
.\" $NetBSD: spi.4,v 1.13 2022/12/03 01:04:42 brad Exp $
.\"
.\" Copyright (c) 2006 Urbana-Champaign Independent Media Center.
.\" Copyright (c) 2006 Garrett D'Amore.
@ -131,6 +131,8 @@ includes the following machine-independent
.Tn SPI
drivers:
.Bl -tag -width mcp23s17gpio(4) -offset indent
.It Xr bmx280thp 4
Bosch BMP280 / BME280 sensor.
.It Xr m25p 4
STMicroelectronics M25P family of NOR flash devices.
.It Xr mcp23s17gpio 4

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.1303 2022/11/05 17:31:38 jmcneill Exp $
# $NetBSD: files,v 1.1304 2022/12/03 01:04:42 brad Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20171118
@ -437,6 +437,10 @@ file dev/ic/ssdfb.c ssdfb
device scmd
file dev/ic/scmd.c scmd
# Bosch BMP280 / BME280 sensor (attaches via I2C or SPI)
device bmx280thp
file dev/ic/bmx280.c bmx280thp
# Generic HID support (used by USB, bluetooth and i2c)
include "dev/hid/files.hid"

264
sys/dev/i2c/bmx280thpi2c.c Normal file
View File

@ -0,0 +1,264 @@
/* $NetBSD: bmx280thpi2c.c,v 1.1 2022/12/03 01:04:43 brad Exp $ */
/*
* Copyright (c) 2022 Brad Spencer <brad@anduin.eldar.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bmx280thpi2c.c,v 1.1 2022/12/03 01:04:43 brad Exp $");
/*
* I2C driver for the Bosch BMP280 / BME280 sensor.
* Uses the common bmx280thp driver to do the real work.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/module.h>
#include <sys/conf.h>
#include <sys/sysctl.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/pool.h>
#include <sys/kmem.h>
#include <dev/sysmon/sysmonvar.h>
#include <dev/i2c/i2cvar.h>
#include <dev/spi/spivar.h>
#include <dev/ic/bmx280reg.h>
#include <dev/ic/bmx280var.h>
extern void bmx280_attach(struct bmx280_sc *);
static int bmx280thpi2c_poke(i2c_tag_t, i2c_addr_t, bool);
static int bmx280thpi2c_match(device_t, cfdata_t, void *);
static void bmx280thpi2c_attach(device_t, device_t, void *);
static int bmx280thpi2c_detach(device_t, int);
#define BMX280_DEBUG
#ifdef BMX280_DEBUG
#define DPRINTF(s, l, x) \
do { \
if (l <= s->sc_bmx280debug) \
printf x; \
} while (/*CONSTCOND*/0)
#else
#define DPRINTF(s, l, x)
#endif
CFATTACH_DECL_NEW(bmx280thpi2c, sizeof(struct bmx280_sc),
bmx280thpi2c_match, bmx280thpi2c_attach, bmx280thpi2c_detach, NULL);
/* For the BMX280, a read consists of writing on the I2C bus
* a I2C START, I2C SLAVE address, then the starting register.
* If that works, then following will be another I2C START,
* I2C SLAVE address, followed by as many I2C reads that is
* desired and then a I2C STOP
*/
static int
bmx280thpi2c_read_register_direct(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg,
uint8_t *buf, size_t blen)
{
int error;
error = iic_exec(tag,I2C_OP_WRITE,addr,&reg,1,NULL,0,0);
if (error == 0) {
error = iic_exec(tag,I2C_OP_READ_WITH_STOP,addr,NULL,0,
buf,blen,0);
}
return error;
}
static int
bmx280thpi2c_read_register(struct bmx280_sc *sc, uint8_t reg,
uint8_t *buf, size_t blen)
{
int error;
KASSERT(blen > 0);
error = bmx280thpi2c_read_register_direct(sc->sc_tag, sc->sc_addr, reg,
buf, blen);
return error;
}
/* For the BMX280, a write consists of sending a I2C START, I2C SLAVE
* address and then pairs of registers and data until a I2C STOP is
* sent.
*/
static int
bmx280thpi2c_write_register(struct bmx280_sc *sc,
uint8_t *buf, size_t blen)
{
int error;
KASSERT(blen > 0);
/* XXX - there should be a KASSERT for blen at least
being an even number */
error = iic_exec(sc->sc_tag,I2C_OP_WRITE_WITH_STOP,sc->sc_addr,NULL,0,
buf,blen,0);
return error;
}
static int
bmx280thpi2c_acquire_bus(struct bmx280_sc *sc)
{
return(iic_acquire_bus(sc->sc_tag, 0));
}
static void
bmx280thpi2c_release_bus(struct bmx280_sc *sc)
{
iic_release_bus(sc->sc_tag, 0);
}
static int
bmx280thpi2c_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
{
uint8_t reg = BMX280_REGISTER_ID;
uint8_t buf[1];
int error;
error = bmx280thpi2c_read_register_direct(tag, addr, reg, buf, 1);
if (matchdebug) {
printf("poke X 1: %d\n", error);
}
return error;
}
static int
bmx280thpi2c_match(device_t parent, cfdata_t match, void *aux)
{
struct i2c_attach_args *ia = aux;
int error, match_result;
const bool matchdebug = false;
if (iic_use_direct_match(ia, match, NULL, &match_result))
return match_result;
/* indirect config - check for configured address */
if (ia->ia_addr != BMX280_TYPICAL_ADDR_1 &&
ia->ia_addr != BMX280_TYPICAL_ADDR_2)
return 0;
/*
* Check to see if something is really at this i2c address. This will
* keep phantom devices from appearing
*/
if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
if (matchdebug)
printf("in match acquire bus failed\n");
return 0;
}
error = bmx280thpi2c_poke(ia->ia_tag, ia->ia_addr, matchdebug);
iic_release_bus(ia->ia_tag, 0);
return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
}
static void
bmx280thpi2c_attach(device_t parent, device_t self, void *aux)
{
struct bmx280_sc *sc;
struct i2c_attach_args *ia;
ia = aux;
sc = device_private(self);
sc->sc_dev = self;
sc->sc_tag = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
sc->sc_bmx280debug = 0;
sc->sc_func_acquire_bus = &bmx280thpi2c_acquire_bus;
sc->sc_func_release_bus = &bmx280thpi2c_release_bus;
sc->sc_func_read_register = &bmx280thpi2c_read_register;
sc->sc_func_write_register = &bmx280thpi2c_write_register;
mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
bmx280_attach(sc);
return;
}
static int
bmx280thpi2c_detach(device_t self, int flags)
{
struct bmx280_sc *sc;
sc = device_private(self);
mutex_enter(&sc->sc_mutex);
/* Remove the sensors */
if (sc->sc_sme != NULL) {
sysmon_envsys_unregister(sc->sc_sme);
sc->sc_sme = NULL;
}
mutex_exit(&sc->sc_mutex);
/* Remove the sysctl tree */
sysctl_teardown(&sc->sc_bmx280log);
/* Remove the mutex */
mutex_destroy(&sc->sc_mutex);
return 0;
}
MODULE(MODULE_CLASS_DRIVER, bmx280thpi2c, "iic,bmx280thp");
#ifdef _MODULE
/* Like other drivers, we do this because the bmx280 common
* driver has the definitions already.
*/
#undef CFDRIVER_DECL
#define CFDRIVER_DECL(name, class, attr)
#include "ioconf.c"
#endif
static int
bmx280thpi2c_modcmd(modcmd_t cmd, void *opaque)
{
switch (cmd) {
case MODULE_CMD_INIT:
#ifdef _MODULE
return config_init_component(cfdriver_ioconf_bmx280thpi2c,
cfattach_ioconf_bmx280thpi2c, cfdata_ioconf_bmx280thpi2c);
#else
return 0;
#endif
case MODULE_CMD_FINI:
#ifdef _MODULE
return config_fini_component(cfdriver_ioconf_bmx280thpi2c,
cfattach_ioconf_bmx280thpi2c, cfdata_ioconf_bmx280thpi2c);
#else
return 0;
#endif
default:
return ENOTTY;
}
}

View File

@ -1,4 +1,4 @@
# $NetBSD: files.i2c,v 1.125 2022/11/21 21:24:01 brad Exp $
# $NetBSD: files.i2c,v 1.126 2022/12/03 01:04:43 brad Exp $
obsolete defflag opt_i2cbus.h I2C_SCAN
define i2cbus { }
@ -437,6 +437,5 @@ attach aht20temp at iic
file dev/i2c/aht20.c aht20temp
# Bosch Sensortec BMP280/BME280 Temperature, Humidity and Pressure sensor
device bmx280thp
attach bmx280thp at iic
file dev/i2c/bmx280.c bmx280thp
attach bmx280thp at iic with bmx280thpi2c
file dev/i2c/bmx280thpi2c.c bmx280thpi2c

View File

@ -1,4 +1,4 @@
/* $NetBSD: bmx280.c,v 1.6 2022/12/01 02:29:37 brad Exp $ */
/* $NetBSD: bmx280.c,v 1.1 2022/12/03 01:04:43 brad Exp $ */
/*
* Copyright (c) 2022 Brad Spencer <brad@anduin.eldar.org>
@ -17,11 +17,12 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bmx280.c,v 1.6 2022/12/01 02:29:37 brad Exp $");
__KERNEL_RCSID(0, "$NetBSD: bmx280.c,v 1.1 2022/12/03 01:04:43 brad Exp $");
/*
Driver for the Bosch BMP280/BME280 temperature, humidity (sometimes) and
(usually barometric) pressure sensor
* Common driver for the Bosch BMP280/BME280 temperature, humidity (sometimes) and
* (usually barometric) pressure sensor. Calls out to specific frontends to
* the move bits around.
*/
#include <sys/param.h>
@ -34,21 +35,15 @@ __KERNEL_RCSID(0, "$NetBSD: bmx280.c,v 1.6 2022/12/01 02:29:37 brad Exp $");
#include <sys/proc.h>
#include <dev/sysmon/sysmonvar.h>
#include <dev/spi/spivar.h>
#include <dev/i2c/i2cvar.h>
#include <dev/i2c/bmx280reg.h>
#include <dev/i2c/bmx280var.h>
#include <dev/ic/bmx280reg.h>
#include <dev/ic/bmx280var.h>
static int bmx280_write_register(i2c_tag_t, i2c_addr_t,
uint8_t *, size_t);
static int bmx280_read_register(i2c_tag_t, i2c_addr_t, uint8_t *,
uint8_t *, size_t);
static void bmx280_store_raw_blob_tp(struct bmx280_sc *, uint8_t *);
static void bmx280_store_raw_blob_h(struct bmx280_sc *, uint8_t *);
static int bmx280_poke(i2c_tag_t, i2c_addr_t, bool);
static int bmx280_match(device_t, cfdata_t, void *);
static void bmx280_attach(device_t, device_t, void *);
static int bmx280_detach(device_t, int);
void bmx280_attach(struct bmx280_sc *);
static void bmx280_refresh(struct sysmon_envsys *, envsys_data_t *);
static int bmx280_verify_sysctl(SYSCTLFN_ARGS);
static int bmx280_verify_sysctl_osrs(SYSCTLFN_ARGS);
@ -65,9 +60,6 @@ static int bmx280_verify_sysctl_irr(SYSCTLFN_ARGS);
#define DPRINTF(s, l, x)
#endif
CFATTACH_DECL_NEW(bmx280thp, sizeof(struct bmx280_sc),
bmx280_match, bmx280_attach, bmx280_detach, NULL);
static struct bmx280_sensor bmx280_sensors[] = {
{
.desc = "temperature",
@ -283,67 +275,6 @@ bmx280_store_raw_blob_h(struct bmx280_sc *sc, uint8_t *b) {
sc->sc_cal_blob.dig_H6 = (int8_t)b[7];
}
/* For the BMX280, a write consists of sending a I2C START, I2C SLAVE
* address and then pairs of registers and data until a I2C STOP is
* sent.
*/
static int
bmx280_write_register(i2c_tag_t tag, i2c_addr_t addr,
uint8_t *buf, size_t blen)
{
int error;
KASSERT(blen > 0);
/* XXX - there should be a KASSERT for blen at least
being an even number */
error = iic_exec(tag,I2C_OP_WRITE_WITH_STOP,addr,NULL,0,
buf,blen,0);
return error;
}
/* For the BMX280, a read consists of writing on the I2C bus
* a I2C START, I2C SLAVE address, then the starting register.
* If that works, then following will be another I2C START,
* I2C SLAVE address, followed by as many I2C reads that is
* desired and then a I2C STOP
*/
static int
bmx280_read_register(i2c_tag_t tag, i2c_addr_t addr, uint8_t *reg,
uint8_t *buf, size_t blen)
{
int error;
KASSERT(blen > 0);
error = iic_exec(tag,I2C_OP_WRITE,addr,reg,1,NULL,0,0);
if (error == 0) {
error = iic_exec(tag,I2C_OP_READ_WITH_STOP,addr,NULL,0,
buf,blen,0);
}
return error;
}
static int
bmx280_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
{
uint8_t reg = BMX280_REGISTER_ID;
uint8_t buf[1];
int error;
error = bmx280_read_register(tag, addr, &reg, buf, 1);
if (matchdebug) {
printf("poke X 1: %d\n", error);
}
return error;
}
static int
bmx280_sysctl_init(struct bmx280_sc *sc)
{
@ -351,6 +282,8 @@ bmx280_sysctl_init(struct bmx280_sc *sc)
const struct sysctlnode *cnode;
int sysctlroot_num, sysctlwait_num;
sc->sc_func_attach = &bmx280_attach;
if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
0, CTLTYPE_NODE, device_xname(sc->sc_dev),
SYSCTL_DESCR("bmx280 controls"), NULL, 0, NULL, 0, CTL_HW,
@ -446,54 +379,13 @@ bmx280_sysctl_init(struct bmx280_sc *sc)
return 0;
}
static int
bmx280_match(device_t parent, cfdata_t match, void *aux)
void
bmx280_attach(struct bmx280_sc *sc)
{
struct i2c_attach_args *ia = aux;
int error, match_result;
const bool matchdebug = false;
if (iic_use_direct_match(ia, match, NULL, &match_result))
return match_result;
/* indirect config - check for configured address */
if (ia->ia_addr != BMX280_TYPICAL_ADDR_1 &&
ia->ia_addr != BMX280_TYPICAL_ADDR_2)
return 0;
/*
* Check to see if something is really at this i2c address. This will
* keep phantom devices from appearing
*/
if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
if (matchdebug)
printf("in match acquire bus failed\n");
return 0;
}
error = bmx280_poke(ia->ia_tag, ia->ia_addr, matchdebug);
iic_release_bus(ia->ia_tag, 0);
return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
}
static void
bmx280_attach(device_t parent, device_t self, void *aux)
{
struct bmx280_sc *sc;
struct i2c_attach_args *ia;
int error, i;
uint8_t reg, chip_id;
uint8_t buf[2];
ia = aux;
sc = device_private(self);
sc->sc_dev = self;
sc->sc_tag = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
sc->sc_bmx280debug = 0;
sc->sc_bmx280dump = false;
sc->sc_has_humidity = false;
sc->sc_readattempts = 25;
@ -513,33 +405,33 @@ bmx280_attach(device_t parent, device_t self, void *aux)
sc->sc_numsensors = __arraycount(bmx280_sensors);
if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
aprint_error_dev(self,
aprint_error_dev(sc->sc_dev,
"Unable to create sysmon structure\n");
sc->sc_sme = NULL;
return;
}
error = iic_acquire_bus(sc->sc_tag, 0);
error = (*(sc->sc_func_acquire_bus))(sc);
if (error) {
aprint_error_dev(self, "Could not acquire iic bus: %d\n",
aprint_error_dev(sc->sc_dev, "Could not acquire the bus: %d\n",
error);
goto out;
}
buf[0] = BMX280_REGISTER_RESET;
buf[1] = BMX280_TRIGGER_RESET;
error = bmx280_write_register(sc->sc_tag, sc->sc_addr, buf, 2);
error = (*(sc->sc_func_write_register))(sc, buf, 2);
if (error) {
aprint_error_dev(self, "Failed to reset chip: %d\n",
aprint_error_dev(sc->sc_dev, "Failed to reset chip: %d\n",
error);
}
delay(30000);
reg = BMX280_REGISTER_ID;
error = bmx280_read_register(sc->sc_tag, sc->sc_addr, &reg, &chip_id, 1);
error = (*(sc->sc_func_read_register))(sc, reg, &chip_id, 1);
if (error) {
aprint_error_dev(self, "Failed to read ID: %d\n",
aprint_error_dev(sc->sc_dev, "Failed to read ID: %d\n",
error);
}
@ -553,15 +445,15 @@ bmx280_attach(device_t parent, device_t self, void *aux)
}
if ((error = bmx280_sysctl_init(sc)) != 0) {
aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
aprint_error_dev(sc->sc_dev, "Can't setup sysctl tree (%d)\n", error);
goto out;
}
uint8_t raw_blob_tp[24];
reg = BMX280_REGISTER_DIG_T1;
error = bmx280_read_register(sc->sc_tag, sc->sc_addr, &reg, raw_blob_tp, 24);
error = (*(sc->sc_func_read_register))(sc, reg, raw_blob_tp, 24);
if (error) {
aprint_error_dev(self, "Failed to read the calibration registers for tp: %d\n",
aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for tp: %d\n",
error);
}
@ -578,16 +470,16 @@ bmx280_attach(device_t parent, device_t self, void *aux)
uint8_t raw_blob_h[8];
reg = BMX280_REGISTER_DIG_H1;
error = bmx280_read_register(sc->sc_tag, sc->sc_addr, &reg, raw_blob_h, 1);
error = (*(sc->sc_func_read_register))(sc, reg, raw_blob_h, 1);
if (error) {
aprint_error_dev(self, "Failed to read the calibration registers for h1: %d\n",
aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for h1: %d\n",
error);
}
reg = BMX280_REGISTER_DIG_H2;
error = bmx280_read_register(sc->sc_tag, sc->sc_addr, &reg, &raw_blob_h[1], 7);
error = (*(sc->sc_func_read_register))(sc, reg, &raw_blob_h[1], 7);
if (error) {
aprint_error_dev(self, "Failed to read the calibration registers for h2 - h6: %d\n",
aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for h2 - h6: %d\n",
error);
}
@ -601,10 +493,10 @@ bmx280_attach(device_t parent, device_t self, void *aux)
bmx280_store_raw_blob_h(sc,raw_blob_h);
}
iic_release_bus(sc->sc_tag, 0);
(*(sc->sc_func_release_bus))(sc);
if (error != 0) {
aprint_error_dev(self, "Unable to setup device\n");
aprint_error_dev(sc->sc_dev, "Unable to setup device\n");
goto out;
}
@ -626,7 +518,7 @@ bmx280_attach(device_t parent, device_t self, void *aux)
error = sysmon_envsys_sensor_attach(sc->sc_sme,
&sc->sc_sensors[i]);
if (error) {
aprint_error_dev(self,
aprint_error_dev(sc->sc_dev,
"Unable to attach sensor %d: %d\n", i, error);
goto out;
}
@ -639,14 +531,14 @@ bmx280_attach(device_t parent, device_t self, void *aux)
DPRINTF(sc, 2, ("bmx280_attach: registering with envsys\n"));
if (sysmon_envsys_register(sc->sc_sme)) {
aprint_error_dev(self,
aprint_error_dev(sc->sc_dev,
"unable to register with sysmon\n");
sysmon_envsys_destroy(sc->sc_sme);
sc->sc_sme = NULL;
return;
}
aprint_normal_dev(self, "Bosch Sensortec %s, Chip ID: 0x%02x\n",
aprint_normal_dev(sc->sc_dev, "Bosch Sensortec %s, Chip ID: 0x%02x\n",
(chip_id == BMX280_ID_BMP280) ? "BMP280" : (chip_id == BMX280_ID_BME280) ? "BME280" : "Unknown chip",
chip_id);
@ -763,7 +655,7 @@ bmx280_set_control_and_trigger(struct bmx280_sc *sc,
s++;
DPRINTF(sc, 2, ("%s: control register set up: num: %d ; %02x %02x ; %02x %02x ; %02x %02x\n",
device_xname(sc->sc_dev), s, cr[0], cr[1], cr[2], cr[3], cr[4], cr[5]));
error = bmx280_write_register(sc->sc_tag, sc->sc_addr, cr, s);
error = (*(sc->sc_func_write_register))(sc, cr, s);
if (error) {
DPRINTF(sc, 2, ("%s: write control registers: %d\n",
device_xname(sc->sc_dev), error));
@ -803,7 +695,7 @@ bmx280_wait_for_data(struct bmx280_sc *sc)
reg = BMX280_REGISTER_STATUS;
do {
delay(1000);
ierror = bmx280_read_register(sc->sc_tag, sc->sc_addr, &reg, &running, 1);
ierror = (*(sc->sc_func_read_register))(sc, reg, &running, 1);
if (ierror) {
DPRINTF(sc, 2, ("%s: Refresh failed to read back status: %d\n",
device_xname(sc->sc_dev), ierror));
@ -858,7 +750,7 @@ bmx280_read_data(struct bmx280_sc *sc,
DPRINTF(sc, 2, ("%s: read data: reg: %02x ; len: %d ; tstart: %d ; pstart: %d\n",
device_xname(sc->sc_dev), reg, rlen, rtstart, rpstart));
ierror = bmx280_read_register(sc->sc_tag, sc->sc_addr, &reg, raw_press_temp_hum, rlen);
ierror = (*(sc->sc_func_read_register))(sc, reg, raw_press_temp_hum, rlen);
if (ierror) {
DPRINTF(sc, 2, ("%s: failed to read pressure and temp registers: %d\n",
device_xname(sc->sc_dev), ierror));
@ -948,7 +840,7 @@ bmx280_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
}
mutex_enter(&sc->sc_mutex);
error = iic_acquire_bus(sc->sc_tag, 0);
error = (*(sc->sc_func_acquire_bus))(sc);
if (error) {
DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
device_xname(sc->sc_dev), error));
@ -1084,39 +976,15 @@ bmx280_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
device_xname(sc->sc_dev), error));
}
iic_release_bus(sc->sc_tag, 0);
(*(sc->sc_func_release_bus))(sc);
out:
mutex_exit(&sc->sc_mutex);
}
static int
bmx280_detach(device_t self, int flags)
{
struct bmx280_sc *sc;
sc = device_private(self);
mutex_enter(&sc->sc_mutex);
/* Remove the sensors */
if (sc->sc_sme != NULL) {
sysmon_envsys_unregister(sc->sc_sme);
sc->sc_sme = NULL;
}
mutex_exit(&sc->sc_mutex);
/* Remove the sysctl tree */
sysctl_teardown(&sc->sc_bmx280log);
/* Remove the mutex */
mutex_destroy(&sc->sc_mutex);
return 0;
}
MODULE(MODULE_CLASS_DRIVER, bmx280thp, "iic,sysmon_envsys");
MODULE(MODULE_CLASS_DRIVER, bmx280thp, NULL);
#ifdef _MODULE
CFDRIVER_DECL(bmx280thp, DV_DULL, NULL);
#include "ioconf.c"
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: bmx280reg.h,v 1.1 2022/11/21 21:24:01 brad Exp $ */
/* $NetBSD: bmx280reg.h,v 1.1 2022/12/03 01:04:43 brad Exp $ */
/*
* Copyright (c) 2022 Brad Spencer <brad@anduin.eldar.org>
@ -16,8 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _DEV_I2C_BMX280REG_H_
#define _DEV_I2C_BMX280REG_H_
#ifndef _DEV_IC_BMX280REG_H_
#define _DEV_IC_BMX280REG_H_
#define BMX280_TYPICAL_ADDR_1 0x76
#define BMX280_TYPICAL_ADDR_2 0x77

View File

@ -1,4 +1,4 @@
/* $NetBSD: bmx280var.h,v 1.2 2022/11/23 23:45:29 brad Exp $ */
/* $NetBSD: bmx280var.h,v 1.1 2022/12/03 01:04:43 brad Exp $ */
/*
* Copyright (c) 2022 Brad Spencer <brad@anduin.eldar.org>
@ -16,8 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _DEV_I2C_BMX280VAR_H_
#define _DEV_I2C_BMX280VAR_H_
#ifndef _DEV_IC_BMX280VAR_H_
#define _DEV_IC_BMX280VAR_H_
#define BMX280_NUM_SENSORS 3
#define BMX280_TEMP_SENSOR 0
@ -51,6 +51,7 @@ struct bmx280_sc {
device_t sc_dev;
i2c_tag_t sc_tag;
i2c_addr_t sc_addr;
struct spi_handle *sc_sh;
kmutex_t sc_mutex;
int sc_numsensors;
struct sysmon_envsys *sc_sme;
@ -68,6 +69,11 @@ struct bmx280_sc {
int sc_waitfactor_t;
int sc_waitfactor_p;
int sc_waitfactor_h;
void (*sc_func_attach)(struct bmx280_sc *);
int (*sc_func_acquire_bus)(struct bmx280_sc *);
void (*sc_func_release_bus)(struct bmx280_sc *);
int (*sc_func_read_register)(struct bmx280_sc *, uint8_t, uint8_t *, size_t);
int (*sc_func_write_register)(struct bmx280_sc *, uint8_t *, size_t);
};
struct bmx280_sensor {

205
sys/dev/spi/bmx280thpspi.c Normal file
View File

@ -0,0 +1,205 @@
/* $NetBSD: bmx280thpspi.c,v 1.1 2022/12/03 01:04:43 brad Exp $ */
/*
* Copyright (c) 2022 Brad Spencer <brad@anduin.eldar.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bmx280thpspi.c,v 1.1 2022/12/03 01:04:43 brad Exp $");
/*
* SPI driver for the Bosch BMP280 / BME280 sensor.
* Uses the common bmx280thp driver to do the real work.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/module.h>
#include <sys/conf.h>
#include <sys/sysctl.h>
#include <sys/mutex.h>
#include <sys/condvar.h>
#include <sys/pool.h>
#include <sys/kmem.h>
#include <dev/sysmon/sysmonvar.h>
#include <dev/i2c/i2cvar.h>
#include <dev/spi/spivar.h>
#include <dev/ic/bmx280reg.h>
#include <dev/ic/bmx280var.h>
extern void bmx280_attach(struct bmx280_sc *);
static int bmx280thpspi_match(device_t, cfdata_t, void *);
static void bmx280thpspi_attach(device_t, device_t, void *);
static int bmx280thpspi_detach(device_t, int);
#define BMX280_DEBUG
#ifdef BMX280_DEBUG
#define DPRINTF(s, l, x) \
do { \
if (l <= s->sc_bmx280debug) \
printf x; \
} while (/*CONSTCOND*/0)
#else
#define DPRINTF(s, l, x)
#endif
CFATTACH_DECL_NEW(bmx280thpspi, sizeof(struct bmx280_sc),
bmx280thpspi_match, bmx280thpspi_attach, bmx280thpspi_detach, NULL);
/* The SPI interface of the chip, assuming that it has managed to get into that
* mode to start with, is pretty simple. Simply send the register MINUS the 7th
* bit which will be 1 and then do as many reads as you want. The chip will
* auto increment for you.
*
* The delays are only hinted at in the data sheet.
*/
static int
bmx280thpspi_read_reg_direct(struct spi_handle *sh, uint8_t reg,
uint8_t *buf, size_t rlen)
{
int err = 0;
uint8_t rreg = reg | 0x80;
if (buf != NULL) {
err = spi_send_recv(sh, 1, &rreg,
rlen, buf);
} else {
err = spi_send(sh, 1, &rreg);
}
return err;
}
static int
bmx280thpspi_read_reg(struct bmx280_sc *sc, uint8_t reg, uint8_t *buf, size_t rlen)
{
return bmx280thpspi_read_reg_direct(sc->sc_sh, reg, buf, rlen);
}
/* SPI writes to this device are normal enough. You send the register
* you want making sure that the high bit, 0x80, is clear and then the
* data. These pairs can be repeated as many times as you like.
*/
static int
bmx280thpspi_write_reg_direct(struct spi_handle *sh, uint8_t *buf, size_t slen)
{
int err = 0;
int i;
/* XXX -
this is probably BAD thing to do... but we must insure that the
registers have a cleared bit.. otherwise it is a read ....
*/
for(i = 0; i < slen;i+=2) {
buf[i] = buf[i] & 0x7F;
}
err = spi_send(sh, slen, buf);
return err;
}
static int
bmx280thpspi_write_reg(struct bmx280_sc *sc, uint8_t *buf, size_t slen)
{
return bmx280thpspi_write_reg_direct(sc->sc_sh, buf, slen);
}
/* These are to satisfy the common code */
static int
bmx280thpspi_acquire_bus(struct bmx280_sc *sc)
{
return 0;
}
static void
bmx280thpspi_release_bus(struct bmx280_sc *sc)
{
return;
}
/* Nothing more is done here. Assumptions on whether or not
* the SPI interface is set up may not be proper.... for better
* or worse... and there is setting that are needed such as the
* SPI mode and bus speed that really should not be done here, so
* any active match might not work anyway.
*/
static int
bmx280thpspi_match(device_t parent, cfdata_t match, void *aux)
{
const bool matchdebug = false;
if (matchdebug) {
printf("Trying to match\n");
}
return 1;
}
static void
bmx280thpspi_attach(device_t parent, device_t self, void *aux)
{
struct bmx280_sc *sc;
struct spi_attach_args *sa;
int error;
sa = aux;
sc = device_private(self);
sc->sc_dev = self;
sc->sc_sh = sa->sa_handle;
sc->sc_bmx280debug = 0;
sc->sc_func_acquire_bus = &bmx280thpspi_acquire_bus;
sc->sc_func_release_bus = &bmx280thpspi_release_bus;
sc->sc_func_read_register = &bmx280thpspi_read_reg;
sc->sc_func_write_register = &bmx280thpspi_write_reg;
/* Configure for 1MHz and SPI mode 0 according to the data sheet.
* The chip will actually handle a number of different modes and
* can go a lot faster, just use this for now...
*/
error = spi_configure(self, sa->sa_handle, SPI_MODE_0, 1000000);
if (error) {
return;
}
/* Please note that if the pins are not set up for SPI, the attachment
* will probably not work out.
*/
bmx280_attach(sc);
return;
}
/* These really do not do a whole lot, as SPI devices do not seem to work
* as modules.
*/
static int
bmx280thpspi_detach(device_t self, int flags)
{
struct bmx280_sc *sc;
sc = device_private(self);
mutex_destroy(&sc->sc_mutex);
return 0;
}

View File

@ -1,4 +1,4 @@
# $NetBSD: files.spi,v 1.9 2022/01/17 16:31:23 thorpej Exp $
# $NetBSD: files.spi,v 1.10 2022/12/03 01:04:43 brad Exp $
define spibus { }
@ -47,3 +47,7 @@ file dev/spi/mcp3k.c mcp3kadc
# Sparkfun Serial motor controller
attach scmd at spi with scmdspi
file dev/spi/scmdspi.c scmdspi
# Bosch BMP280 / BME280 sensor
attach bmx280thp at spi with bmx280thpspi
file dev/spi/bmx280thpspi.c bmx280thpspi

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.273 2022/11/21 21:24:01 brad Exp $
# $NetBSD: Makefile,v 1.274 2022/12/03 01:04:42 brad Exp $
.include <bsd.own.mk>
@ -34,6 +34,7 @@ SUBDIR+= blowfish
SUBDIR+= bpf
SUBDIR+= bpf_filter
SUBDIR+= bmx280thp
SUBDIR+= bmx280thpi2c
SUBDIR+= bufq_disksort
SUBDIR+= bufq_fcfs
SUBDIR+= bufq_priocscan

View File

@ -1,6 +1,6 @@
.include "../Makefile.inc"
.PATH: ${S}/dev/i2c
.PATH: ${S}/dev/ic
KMOD= bmx280thp
IOCONF= bmx280thp.ioconf

View File

@ -1,8 +1,3 @@
ioconf bmx280thp
include "conf/files"
pseudo-root iic*
bmx280thp* at iic? addr 0x76
bmx280thp* at iic? addr 0x77

View File

@ -0,0 +1,11 @@
.include "../Makefile.inc"
.PATH: ${S}/dev/i2c
KMOD= bmx280thpi2c
IOCONF= bmx280thpi2c.ioconf
SRCS= bmx280thpi2c.c
WARNS= 3
.include <bsd.kmodule.mk>

View File

@ -0,0 +1,8 @@
ioconf bmx280thpi2c
include "conf/files"
pseudo-root iic*
bmx280thp* at iic? addr 0x76
bmx280thp* at iic? addr 0x77