/**************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #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 */