nuttx/drivers/sensors/ms58xx.c
Catalin Visinescu 081e4c478a drivers/: Multiple Drivers Are Registered With World Writable - Part 2
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>
2026-07-15 15:27:28 +08:00

1123 lines
29 KiB
C

/****************************************************************************
* drivers/sensors/ms58xx.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 <assert.h>
#include <errno.h>
#include <nuttx/debug.h>
#include <stdlib.h>
#include <nuttx/kmalloc.h>
#include <nuttx/fs/fs.h>
#include <nuttx/arch.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/sensors/ms58xx.h>
#include <nuttx/sensors/msxxxx_crc4.h>
#include <nuttx/random.h>
#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_MS58XX)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Register Definitions *****************************************************/
/* Register Addresses */
#define MS58XX_RESET_REG 0x1e /* Reset Register */
#define MS58XX_PRESS_REG 0x40 /* Pressure Register */
#define MS58XX_TEMP_REG 0x50 /* Temperature Register */
#define MS58XX_ADC_REG 0x00 /* ADC Register */
#define MS58XX_PROM_REG 0xa0 /* PROM Register */
/* PROM Definitions *********************************************************/
#define MS58XX_PROM_LEN 8
/****************************************************************************
* Private Types
****************************************************************************/
struct ms58xx_dev_s
{
FAR struct i2c_master_s *i2c; /* I2C interface */
uint8_t addr; /* I2C address */
enum ms58xx_model_e model;
uint8_t crcindex;
uint8_t crcshift;
int32_t temp; /* Uncompensated temperature (degrees Centigrade) */
int32_t press; /* Uncompensated pressure (millibar) */
uint8_t osr; /* Oversampling ratio bits */
useconds_t delay; /* Oversampling ratio delay */
/* Calibration coefficients */
uint16_t c1;
uint16_t c2;
uint16_t c3;
uint16_t c4;
uint16_t c5;
uint16_t c6;
uint8_t c7;
uint8_t c8;
/* Constants used when calculating the temperature and the pressure */
uint8_t c1s;
uint8_t c2s;
uint8_t c3s;
uint8_t c4s;
uint8_t diffmull;
uint8_t diffdivls;
uint8_t offmull;
uint8_t offdivls;
uint8_t sensmull;
uint8_t sensdivls;
uint8_t offmulvl;
uint8_t sensmulvl;
uint8_t diffmulh;
uint8_t diffdivhs;
uint8_t offmulh;
uint8_t offdivhs;
uint8_t sensmulh;
uint8_t sensdivhs;
uint8_t pressdivs;
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* I2C Helpers */
static int ms58xx_i2c_write(FAR struct ms58xx_dev_s *priv,
FAR const uint8_t *buffer, int buflen);
static int ms58xx_i2c_read(FAR struct ms58xx_dev_s *priv,
FAR uint8_t *buffer, int buflen);
static int ms58xx_readu16(FAR struct ms58xx_dev_s *priv, uint8_t regaddr,
FAR uint16_t *regval);
static int ms58xx_readadc(FAR struct ms58xx_dev_s *priv, FAR uint32_t *adc);
static int ms58xx_setosr(FAR struct ms58xx_dev_s *priv, uint16_t osr);
static int ms58xx_reset(FAR struct ms58xx_dev_s *priv);
static int ms58xx_readprom(FAR struct ms58xx_dev_s *priv);
static int ms58xx_convert(FAR struct ms58xx_dev_s *priv, uint8_t regaddr,
FAR uint32_t *regval);
static int ms58xx_measure(FAR struct ms58xx_dev_s *priv);
/* Character Driver Methods */
static ssize_t ms58xx_read(FAR struct file *filep, FAR char *buffer,
size_t buflen);
static ssize_t ms58xx_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen);
static int ms58xx_ioctl(FAR struct file *filep, int cmd,
unsigned long arg);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations g_fops =
{
NULL, /* open */
NULL, /* close */
ms58xx_read, /* read */
ms58xx_write, /* write */
NULL, /* seek */
ms58xx_ioctl, /* ioctl */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ms58xx_i2c_write
*
* Description:
* Write to the I2C device.
*
****************************************************************************/
static int ms58xx_i2c_write(FAR struct ms58xx_dev_s *priv,
FAR const uint8_t *buffer, int buflen)
{
struct i2c_msg_s msg;
int ret;
/* Setup for the transfer */
msg.frequency = CONFIG_MS58XX_I2C_FREQUENCY,
msg.addr = priv->addr;
msg.flags = 0;
msg.buffer = (FAR uint8_t *)buffer; /* Override const */
msg.length = buflen;
/* Then perform the transfer. */
ret = I2C_TRANSFER(priv->i2c, &msg, 1);
return (ret >= 0) ? OK : ret;
}
/****************************************************************************
* Name: ms58xx_i2c_read
*
* Description:
* Read from the I2C device.
*
****************************************************************************/
static int ms58xx_i2c_read(FAR struct ms58xx_dev_s *priv,
FAR uint8_t *buffer, int buflen)
{
struct i2c_msg_s msg;
int ret;
/* Setup for the transfer */
msg.frequency = CONFIG_MS58XX_I2C_FREQUENCY,
msg.addr = priv->addr,
msg.flags = I2C_M_READ;
msg.buffer = buffer;
msg.length = buflen;
/* Then perform the transfer. */
ret = I2C_TRANSFER(priv->i2c, &msg, 1);
return (ret >= 0) ? OK : ret;
}
/****************************************************************************
* Name: ms58xx_readu16
*
* Description:
* Read from a 16-bit register.
*
****************************************************************************/
static int ms58xx_readu16(FAR struct ms58xx_dev_s *priv, uint8_t regaddr,
FAR uint16_t *regval)
{
uint8_t buffer[2];
int ret;
sninfo("addr: %02x\n", regaddr);
/* Write the register address */
ret = ms58xx_i2c_write(priv, &regaddr, sizeof(regaddr));
if (ret < 0)
{
snerr("ERROR: i2c_write failed: %d\n", ret);
return ret;
}
/* Restart and read 16 bits from the register */
ret = ms58xx_i2c_read(priv, buffer, sizeof(buffer));
if (ret < 0)
{
snerr("ERROR: i2c_read failed: %d\n", ret);
return ret;
}
*regval = (uint16_t)buffer[0] << 8 | (uint16_t)buffer[1];
sninfo("value: %04x ret: %d\n", *regval, ret);
return ret;
}
/****************************************************************************
* Name: ms58xx_readadc
*
* Description:
* Read from the ADC register.
*
****************************************************************************/
static int ms58xx_readadc(FAR struct ms58xx_dev_s *priv, FAR uint32_t *adc)
{
uint8_t regaddr;
uint8_t buffer[3];
int ret;
regaddr = MS58XX_ADC_REG;
sninfo("addr: %02x\n", regaddr);
/* Write the register address */
ret = ms58xx_i2c_write(priv, &regaddr, sizeof(regaddr));
if (ret < 0)
{
snerr("ERROR: i2c_write failed: %d\n", ret);
return ret;
}
/* Restart and read 24 bits from the register */
ret = ms58xx_i2c_read(priv, buffer, sizeof(buffer));
if (ret < 0)
{
snerr("ERROR: i2c_read failed: %d\n", ret);
return ret;
}
*adc = (uint32_t)buffer[0] << 16 |
(uint32_t)buffer[1] << 8 |
(uint32_t)buffer[2];
sninfo("adc: %06x ret: %d\n", *adc, ret);
return ret;
}
/****************************************************************************
* Name: ms58xx_setosr_1
*
* Description:
* Set the oversampling ratio.
*
****************************************************************************/
static int ms58xx_setosr_1(FAR struct ms58xx_dev_s *priv, uint16_t osr)
{
int ret = OK;
switch (osr)
{
case 256:
priv->delay = 600;
priv->osr = 0x0;
break;
case 512:
priv->delay = 1170;
priv->osr = 0x2;
break;
case 1024:
priv->delay = 2280;
priv->osr = 0x4;
break;
case 2048:
priv->delay = 4540;
priv->osr = 0x6;
break;
case 4096:
priv->delay = 9040;
priv->osr = 0x8;
break;
case 8192:
priv->delay = 18080;
priv->osr = 0xa;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
/****************************************************************************
* Name: ms58xx_setosr_2
*
* Description:
* Set the oversampling ratio.
*
****************************************************************************/
static int ms58xx_setosr_2(FAR struct ms58xx_dev_s *priv, uint16_t osr)
{
int ret = OK;
switch (osr)
{
case 256:
priv->delay = 600;
break;
case 512:
priv->delay = 1170;
break;
case 1024:
priv->delay = 2280;
break;
case 2048:
priv->delay = 4540;
break;
case 4096:
priv->delay = 9040;
break;
default:
ret = -EINVAL;
break;
}
if (ret == OK)
{
priv->osr = (osr / 256 - 1) * 2;
}
return ret;
}
/****************************************************************************
* Name: ms58xx_setosr
*
* Description:
* Set the oversampling ratio.
*
****************************************************************************/
static int ms58xx_setosr(FAR struct ms58xx_dev_s *priv, uint16_t osr)
{
int ret = OK;
sninfo("osr: %04x\n", osr);
switch (priv->model)
{
case MS58XX_MODEL_MS5805_02:
case MS58XX_MODEL_MS5837_30:
ret = ms58xx_setosr_1(priv, osr);
break;
case MS58XX_MODEL_MS5803_02:
case MS58XX_MODEL_MS5803_05:
case MS58XX_MODEL_MS5803_07:
case MS58XX_MODEL_MS5803_14:
case MS58XX_MODEL_MS5803_30:
case MS58XX_MODEL_MS5806_02:
ret = ms58xx_setosr_2(priv, osr);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
/****************************************************************************
* Name: ms58xx_readprom
*
* Description:
* Read from the PROM.
*
****************************************************************************/
static int ms58xx_readprom(FAR struct ms58xx_dev_s *priv)
{
uint16_t prom[MS58XX_PROM_LEN];
uint8_t crc;
uint8_t crcindex;
uint8_t crcshift;
uint16_t crcmask;
int ret;
int i;
int len = MS58XX_PROM_LEN;
switch (priv->model)
{
case MS58XX_MODEL_MS5805_02:
case MS58XX_MODEL_MS5837_30:
prom[MS58XX_PROM_LEN - 1] = 0;
len--;
crcindex = 0;
crcshift = 12;
break;
case MS58XX_MODEL_MS5803_02:
case MS58XX_MODEL_MS5803_05:
case MS58XX_MODEL_MS5803_07:
case MS58XX_MODEL_MS5803_14:
case MS58XX_MODEL_MS5803_30:
case MS58XX_MODEL_MS5806_02:
default:
crcindex = 7;
crcshift = 0;
break;
}
/* We have to wait before the prom is ready is be read */
up_udelay(10000);
for (i = 0; i < len; i++)
{
ret = ms58xx_readu16(priv, MS58XX_PROM_REG + i * 2, prom + i);
if (ret < 0)
{
snerr("ERROR: ms58xx_readu16 failed: %d\n", ret);
return ret;
}
}
crcmask = (uint16_t)0xf << crcshift;
crc = (uint8_t)((prom[crcindex] & crcmask) >> crcshift);
if (crc != msxxxx_crc4(prom, crcindex, crcmask))
{
snerr("ERROR: crc mismatch\n");
return -ENODEV;
}
priv->c1 = prom[1];
priv->c2 = prom[2];
priv->c3 = prom[3];
priv->c4 = prom[4];
priv->c5 = prom[5];
priv->c6 = prom[6];
switch (priv->model)
{
case MS58XX_MODEL_MS5803_07:
priv->c7 = (uint8_t)((prom[7] & 0x03f0) >> 4);
priv->c8 = (uint8_t)((prom[7] & 0xf700) >> 10);
break;
case MS58XX_MODEL_MS5806_02:
priv->c7 = (uint8_t)((prom[7] & 0x0ff0) >> 4);
priv->c8 = 0;
break;
case MS58XX_MODEL_MS5803_02:
case MS58XX_MODEL_MS5803_05:
case MS58XX_MODEL_MS5803_14:
case MS58XX_MODEL_MS5803_30:
case MS58XX_MODEL_MS5805_02:
case MS58XX_MODEL_MS5837_30:
default:
priv->c7 = 0;
priv->c8 = 0;
break;
}
return ret;
}
/****************************************************************************
* Name: ms58xx_reset
*
* Description:
* Reset the device.
*
****************************************************************************/
static int ms58xx_reset(FAR struct ms58xx_dev_s *priv)
{
uint8_t regaddr;
int ret;
regaddr = MS58XX_RESET_REG;
sninfo("addr: %02x\n", regaddr);
/* Write the register address */
ret = ms58xx_i2c_write(priv, &regaddr, sizeof(regaddr));
if (ret < 0)
{
snerr("ERROR: i2c_write failed: %d\n", ret);
return ret;
}
/* Check the CRC and read the calibration coefficients */
ret = ms58xx_readprom(priv);
if (ret < 0)
{
snerr("ERROR: ms58xx_readprom failed: %d\n", ret);
}
return ret;
}
/****************************************************************************
* Name: ms58xx_convert
*
* Description:
* Measure the uncompensated temperature or the uncompensated pressure.
*
****************************************************************************/
static int ms58xx_convert(FAR struct ms58xx_dev_s *priv, uint8_t regaddr,
FAR uint32_t *regval)
{
int ret;
regaddr |= priv->osr;
sninfo("addr: %02x\n", regaddr);
/* Write the register address */
ret = ms58xx_i2c_write(priv, &regaddr, sizeof(regaddr));
if (ret < 0)
{
snerr("ERROR: i2c_write failed: %d\n", ret);
}
/* Wait for the conversion to end */
up_udelay(priv->delay);
/* Read the value from the ADC */
ret = ms58xx_readadc(priv, regval);
if (ret < 0)
{
snerr("ERROR: ms58xx_readadc failed: %d\n", ret);
return ret;
}
return ret;
}
/****************************************************************************
* Name: ms58xx_measure
*
* Description:
* Measure the compensated temperature and the compensated pressure.
*
****************************************************************************/
static int ms58xx_measure(FAR struct ms58xx_dev_s *priv)
{
uint32_t rawpress;
uint32_t rawtemp;
int32_t diff;
int32_t temp;
int64_t off;
int64_t sens;
int32_t press;
int64_t diffmul;
int64_t diffdiv;
int64_t offmula;
int64_t offdiva;
int64_t sensmula;
int64_t sensdiva;
int64_t offmulb;
int64_t sensmulb;
int64_t tm;
int64_t tp;
int ret;
ret = ms58xx_convert(priv, MS58XX_PRESS_REG, &rawpress);
if (ret < 0)
{
snerr("ERROR: ms58xx_convert failed: %d\n", ret);
return ret;
}
ret = ms58xx_convert(priv, MS58XX_TEMP_REG, &rawtemp);
if (ret < 0)
{
snerr("ERROR: ms58xx_convert failed: %d\n", ret);
return ret;
}
add_sensor_randomness(rawpress ^ rawtemp);
diff = (int32_t)rawtemp - (int32_t)priv->c5 * ((int32_t)1 << 8);
temp = (int32_t)((int64_t)2000 +
(int64_t)diff * (int64_t)priv->c6 / ((int64_t)1 << 23));
off = (int64_t)priv->c2 * ((int64_t)1 << priv->c2s) +
(int64_t)priv->c4 * (int64_t)diff / ((int64_t)1 << priv->c4s);
sens = (int64_t)priv->c1 * ((int64_t)1 << priv->c1s) +
(int64_t)priv->c3 * (int64_t)diff / ((int64_t)1 << priv->c3s);
if (temp < 2000)
{
diffmul = (int64_t)priv->diffmull;
diffdiv = (int64_t)1 << priv->diffdivls;
offmula = (int64_t)priv->offmull;
offdiva = (int64_t)1 << priv->offdivls;
sensmula = (int64_t)priv->sensmull;
sensdiva = (int64_t)1 << priv->sensdivls;
if (temp < -1500)
{
offmulb = (int64_t)priv->offmulvl;
sensmulb = (int64_t)priv->sensmulvl;
}
else
{
offmulb = 0;
sensmulb = 0;
}
}
else
{
diffmul = (int64_t)priv->diffmulh;
diffdiv = (int64_t)1 << priv->diffdivhs;
offmula = (int64_t)priv->offmulh;
offdiva = (int64_t)1 << priv->offdivhs;
sensmula = (int64_t)priv->sensmulh;
sensdiva = (int64_t)1 << priv->sensdivhs;
offmulb = 0;
sensmulb = 0;
}
tm = (int64_t)temp - (int64_t)2000;
tm *= tm;
tp = (int64_t)temp + (int64_t)1500;
tp *= tp;
off -= offmula * tm / offdiva + offmulb * tp;
sens -= sensmula * tm / sensdiva + sensmulb * tp;
temp -= (int32_t)(diffmul * (int64_t)diff * (int64_t)diff / diffdiv);
press = (int32_t)(((int64_t)rawpress * sens / ((int64_t)1 << 21) - off) /
((int64_t)1 << priv->pressdivs));
switch (priv->model)
{
case MS58XX_MODEL_MS5803_07:
if (press > 110000)
{
press += (int32_t)((((int64_t)priv->c7 - ((int64_t)1 << 5)) *
(int64_t)100 * ((int64_t)1 << 2) -
((int64_t)priv->c8 - ((int64_t)1 << 5)) *
((int64_t)temp - (int64_t)2000) /
((int64_t)1 << 4)) *
((int64_t)press - (int64_t)110000) /
(int64_t)49000000);
}
break;
case MS58XX_MODEL_MS5806_02:
#if CONFIG_MS58XX_VDD >= 22 && CONFIG_MS58XX_VDD <= 30
press += (int32_t)(((int64_t)30 - (int64_t)CONFIG_MS58XX_VDD) *
(int64_t)priv->c7 /
(((int64_t)1 << 6) * (int64_t)10));
#endif
break;
case MS58XX_MODEL_MS5803_02:
case MS58XX_MODEL_MS5803_05:
case MS58XX_MODEL_MS5803_14:
case MS58XX_MODEL_MS5803_30:
case MS58XX_MODEL_MS5805_02:
case MS58XX_MODEL_MS5837_30:
break;
}
priv->temp = temp;
priv->press = press;
return ret;
}
/****************************************************************************
* Name: ms58xx_read
*
* Description:
* A dummy read method.
*
****************************************************************************/
static ssize_t ms58xx_read(FAR struct file *filep, FAR char *buffer,
size_t buflen)
{
ssize_t size;
FAR struct inode *inode = filep->f_inode;
FAR struct ms58xx_dev_s *priv = inode->i_private;
FAR struct ms58xx_measure_s *p = (FAR struct ms58xx_measure_s *)buffer;
size = buflen;
while (size >= sizeof(*p))
{
if (ms58xx_measure(priv) < 0)
{
return -1;
}
p->temperature = priv->temp;
p->pressure = priv->press;
p++;
size -= sizeof(*p);
}
return size;
}
/****************************************************************************
* Name: ms58xx_write
*
* Description:
* A dummy write method.
*
****************************************************************************/
static ssize_t ms58xx_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen)
{
return -ENOSYS;
}
/****************************************************************************
* Name: ms58xx_ioctl
*
* Description:
* The standard ioctl method.
*
****************************************************************************/
static int ms58xx_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
FAR struct inode *inode = filep->f_inode;
FAR struct ms58xx_dev_s *priv = inode->i_private;
int ret = OK;
/* Handle ioctl commands */
switch (cmd)
{
/* Measure the temperature and the pressure. Arg: None. */
case SNIOC_MEASURE:
DEBUGASSERT(arg == 0);
ret = ms58xx_measure(priv);
break;
/* Return the temperature last measured. Arg: int32_t* pointer. */
case SNIOC_TEMPERATURE:
{
FAR int32_t *ptr = (FAR int32_t *)((uintptr_t)arg);
DEBUGASSERT(ptr != NULL);
*ptr = priv->temp;
sninfo("temp: %08x\n", *ptr);
}
break;
/* Return the pressure last measured. Arg: int32_t* pointer. */
case SNIOC_PRESSURE:
{
FAR int32_t *ptr = (FAR int32_t *)((uintptr_t)arg);
DEBUGASSERT(ptr != NULL);
*ptr = priv->press;
sninfo("press: %08x\n", *ptr);
}
break;
/* Reset the device. Arg: None. */
case SNIOC_RESET:
DEBUGASSERT(arg == 0);
ret = ms58xx_reset(priv);
break;
/* Change the oversampling ratio. Arg: uint16_t value. */
case SNIOC_OVERSAMPLING:
ret = ms58xx_setosr(priv, (uint16_t)arg);
sninfo("osr: %04x ret: %d\n", *(FAR uint16_t *)arg, ret);
break;
/* Unrecognized commands */
default:
snerr("ERROR: Unrecognized cmd: %d arg: %ld\n", cmd, arg);
ret = -ENOTTY;
break;
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ms58xx_register
*
* Description:
* Register the MS58XX character device as 'devpath'.
*
* Input Parameters:
* devpath - The full path to the driver to register, e.g., "/dev/press0".
* i2c - An I2C driver instance.
* addr - The I2C address of the MS58XX.
* osr - The oversampling ratio.
* model - The MS58XX model.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int ms58xx_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
uint8_t addr, uint16_t osr, enum ms58xx_model_e model)
{
FAR struct ms58xx_dev_s *priv;
int ret;
/* Sanity check */
DEBUGASSERT(i2c != NULL);
DEBUGASSERT(((model == MS58XX_MODEL_MS5803_02 ||
model == MS58XX_MODEL_MS5803_05 ||
model == MS58XX_MODEL_MS5803_07 ||
model == MS58XX_MODEL_MS5803_14 ||
model == MS58XX_MODEL_MS5803_30 ||
model == MS58XX_MODEL_MS5806_02) &&
(addr == MS58XX_ADDR0 || addr == MS58XX_ADDR1)) ||
((model == MS58XX_MODEL_MS5805_02 ||
model == MS58XX_MODEL_MS5837_30) &&
addr == MS58XX_ADDR0));
/* Initialize the device's structure */
priv = kmm_malloc(sizeof(*priv));
if (priv == NULL)
{
snerr("ERROR: Failed to allocate instance\n");
return -ENOMEM;
}
priv->i2c = i2c;
priv->addr = addr;
priv->model = model;
priv->temp = 0;
priv->press = 0;
switch (priv->model)
{
case MS58XX_MODEL_MS5803_02:
case MS58XX_MODEL_MS5805_02:
case MS58XX_MODEL_MS5806_02:
default:
priv->c1s = 16;
priv->c2s = 17;
priv->c3s = 7;
priv->c4s = 6;
break;
case MS58XX_MODEL_MS5803_05:
priv->c1s = 17;
priv->c2s = 18;
priv->c3s = 7;
priv->c4s = 5;
break;
case MS58XX_MODEL_MS5803_07:
priv->c1s = 17;
priv->c2s = 18;
priv->c3s = 6;
priv->c4s = 5;
break;
case MS58XX_MODEL_MS5803_14:
case MS58XX_MODEL_MS5803_30:
case MS58XX_MODEL_MS5837_30:
priv->c1s = 15;
priv->c2s = 16;
priv->c3s = 8;
priv->c4s = 7;
break;
}
switch (priv->model)
{
case MS58XX_MODEL_MS5803_02:
case MS58XX_MODEL_MS5806_02:
priv->diffmull = 1;
priv->diffdivls = 31;
priv->offmull = 61;
priv->offdivls = 4;
priv->sensmull = 2;
priv->sensdivls = 0;
priv->offmulvl = 20;
priv->sensmulvl = 12;
priv->diffmulh = 0;
priv->diffdivhs = 0;
priv->offmulh = 0;
priv->offdivhs = 0;
priv->sensmulh = 0;
priv->sensdivhs = 0;
break;
case MS58XX_MODEL_MS5803_05:
case MS58XX_MODEL_MS5803_07:
priv->diffmull = 3;
priv->diffdivls = 33;
priv->offmull = 3;
priv->offdivls = 3;
priv->sensmull = 7;
priv->sensdivls = 3;
priv->offmulvl = 0;
priv->sensmulvl = 3;
priv->diffmulh = 0;
priv->diffdivhs = 0;
priv->offmulh = 0;
priv->offdivhs = 0;
priv->sensmulh = 0;
priv->sensdivhs = 0;
break;
case MS58XX_MODEL_MS5803_14:
case MS58XX_MODEL_MS5803_30:
priv->diffmull = 3;
priv->diffdivls = 33;
priv->offmull = 3;
priv->offdivls = 1;
priv->sensmull = 5;
priv->sensdivls = 3;
priv->offmulvl = 7;
priv->sensmulvl = 4;
priv->diffmulh = 7;
priv->diffdivhs = 37;
priv->offmulh = 1;
priv->offdivhs = 4;
priv->sensmulh = 0;
priv->sensdivhs = 0;
break;
case MS58XX_MODEL_MS5805_02:
priv->diffmull = 11;
priv->diffdivls = 35;
priv->offmull = 31;
priv->offdivls = 3;
priv->sensmull = 63;
priv->sensdivls = 5;
priv->offmulvl = 0;
priv->sensmulvl = 0;
priv->diffmulh = 0;
priv->diffdivhs = 0;
priv->offmulh = 0;
priv->offdivhs = 0;
priv->sensmulh = 0;
priv->sensdivhs = 0;
break;
case MS58XX_MODEL_MS5837_30:
priv->diffmull = 3;
priv->diffdivls = 33;
priv->offmull = 3;
priv->offdivls = 1;
priv->sensmull = 5;
priv->sensdivls = 3;
priv->offmulvl = 7;
priv->sensmulvl = 4;
priv->diffmulh = 2;
priv->diffdivhs = 37;
priv->offmulh = 1;
priv->offdivhs = 4;
priv->sensmulh = 0;
priv->sensdivhs = 0;
break;
}
switch (priv->model)
{
case MS58XX_MODEL_MS5803_02:
case MS58XX_MODEL_MS5803_05:
case MS58XX_MODEL_MS5803_14:
case MS58XX_MODEL_MS5805_02:
case MS58XX_MODEL_MS5806_02:
default:
priv->pressdivs = 15;
break;
case MS58XX_MODEL_MS5803_30:
case MS58XX_MODEL_MS5837_30:
priv->pressdivs = 13;
break;
}
ret = ms58xx_setosr(priv, osr);
if (ret < 0)
{
snerr("ERROR: ms58xx_setosr failed: %d\n", ret);
goto errout;
}
ret = ms58xx_reset(priv);
if (ret < 0)
{
snerr("ERROR: ms58xx_reset failed: %d\n", ret);
goto errout;
}
/* Register the character driver */
ret = register_driver(devpath, &g_fops, 0600, priv);
if (ret < 0)
{
snerr("ERROR: Failed to register driver: %d\n", ret);
goto errout;
}
return ret;
errout:
kmm_free(priv);
return ret;
}
#endif /* CONFIG_I2C && CONFIG_SENSORS_MS58XX */