/* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ /* Device mapping is done via three parameters: * 1. If BMP_NVI_MPU_SUPPORT (defined below) is set, the code is included to * support the device behind an Invensense MPU running an NVI (NVidia/ * Invensense) driver. * If BMP_NVI_MPU_SUPPORT is 0 then this driver is only for the device in a * stand-alone configuration without any dependancies on an Invensense MPU. * 2. Device tree platform configuration nvi_config: * - auto = automatically detect if connected to host or MPU * - mpu = connected to MPU * - host = connected to host * This is only available if BMP_NVI_MPU_SUPPORT is set. * 3. device in board file: * - bmpX80 = automatically detect the device * - force the device for: * - bmp180 * - bmp280 * If you have no clue what the device is and don't know how it is * connected then use auto and bmpX80. The auto-detect mechanisms are for * platforms that have multiple possible configurations but takes longer to * initialize. No device identification and connect testing is done for * specific configurations. */ /* The NVS = NVidia Sensor framework */ /* NVI = NVidia/Invensense */ /* See Nvs.cpp in the HAL for the NVS implementation of batch/flush. */ /* See NvsIio.cpp in the HAL for the IIO enable/disable extension mechanism. */ #include #include #include #include #include #include #include #include #include #ifndef BMP_NVI_MPU_SUPPORT #define BMP_NVI_MPU_SUPPORT 0 #endif #if BMP_NVI_MPU_SUPPORT #include #endif /* BMP_NVI_MPU_SUPPORT */ #define BMP_DRIVER_VERSION (336) #define BMP_VENDOR "Bosch" #define BMP_NAME "bmpX80" #define BMP180_NAME "bmp180" #define BMP280_NAME "bmp280" #define BMP_KBUF_SIZE (32) #define BMP_PRES_MAX_RANGE_IVAL (1100) #define BMP_PRES_MAX_RANGE_MICRO (0) #define BMP_TEMP_MAX_RANGE_IVAL (125) #define BMP_TEMP_MAX_RANGE_MICRO (0) #define BMP_HW_DELAY_POR_MS (10) #define BMP_POLL_DELAY_MS_DFLT (200) #define BMP_MPU_RETRY_COUNT (50) #define BMP_MPU_RETRY_DELAY_MS (20) /* HW registers */ #define BMP_REG_ID (0xD0) #define BMP_REG_ID_BMP180 (0x55) #define BMP_REG_ID_BMP280 (0x56) #define BMP_REG_RESET (0xE0) #define BMP_REG_RESET_VAL (0xB6) #define BMP_REG_CTRL (0xF4) #define BMP_REG_CTRL_MODE_SLEEP (0) #define BMP180_REG_CTRL_MODE_MASK (0x1F) #define BMP180_REG_CTRL_MODE_PRES (0x34) #define BMP180_REG_CTRL_MODE_TEMP (0x2E) #define BMP180_REG_CTRL_SCO (5) #define BMP180_REG_CTRL_OSS (6) #define BMP280_REG_CTRL_MODE_MASK (0x03) #define BMP280_REG_CTRL_MODE_FORCED1 (1) #define BMP280_REG_CTRL_MODE_FORCED2 (2) #define BMP280_REG_CTRL_MODE_NORMAL (3) #define BMP280_REG_CTRL_OSRS_P (2) #define BMP280_REG_CTRL_OSRS_T (5) #define BMP180_REG_OUT_MSB (0xF6) #define BMP180_REG_OUT_LSB (0xF7) #define BMP180_REG_OUT_XLSB (0xF8) #define BMP280_REG_STATUS (0xF3) #define BMP280_REG_STATUS_MEASURING (3) #define BMP280_REG_STATUS_IM_UPDATE (0) #define BMP280_REG_CONFIG (0xF5) #define BMP280_REG_CONFIG_T_SB (5) #define BMP280_REG_PRESS_MSB (0xF7) #define BMP280_REG_PRESS_LSB (0xF8) #define BMP280_REG_PRESS_XLSB (0xF9) #define BMP280_REG_TEMP_MSB (0xFA) #define BMP280_REG_TEMP_LSB (0xFB) #define BMP280_REG_TEMP_XLSB (0xFC) /* ROM registers */ #define BMP180_REG_AC1 (0xAA) #define BMP180_REG_AC2 (0xAC) #define BMP180_REG_AC3 (0xAE) #define BMP180_REG_AC4 (0xB0) #define BMP180_REG_AC5 (0xB2) #define BMP180_REG_AC6 (0xB4) #define BMP180_REG_B1 (0xB6) #define BMP180_REG_B2 (0xB8) #define BMP180_REG_MB (0xBA) #define BMP180_REG_MC (0xBC) #define BMP180_REG_MD (0xBE) #define BMP280_REG_CWORD00 (0x88) #define BMP280_REG_CWORD01 (0x8A) #define BMP280_REG_CWORD02 (0x8C) #define BMP280_REG_CWORD03 (0x8E) #define BMP280_REG_CWORD04 (0x90) #define BMP280_REG_CWORD05 (0x92) #define BMP280_REG_CWORD06 (0x94) #define BMP280_REG_CWORD07 (0x96) #define BMP280_REG_CWORD08 (0x98) #define BMP280_REG_CWORD09 (0x9A) #define BMP280_REG_CWORD10 (0x9C) #define BMP280_REG_CWORD11 (0x9E) #define BMP280_REG_CWORD12 (0xA0) #define BATCH_DRY_RUN (0x1) #define BATCH_WAKE_UPON_FIFO_FULL (0x2) #define WR (0) #define RD (1) #define PORT_N (2) /* _buf_push expects this scan order */ #define BMP_DEV_PRS (0) #define BMP_DEV_TMP (1) #define BMP_DEV_N (2) /* regulator names in order of powering on */ static char *bmp_vregs[] = { "vdd", "vddio", }; static char *bmp_configs[] = { "auto", "mpu", "host", }; static u8 bmp_ids[] = { BMP_REG_ID_BMP180, BMP_REG_ID_BMP280, 0x57, 0x58, }; static unsigned short bmp_i2c_addrs[] = { 0x76, 0x77, }; struct bmp_scale { unsigned int delay_ms; u8 os; /* oversampling */ struct nvs_float resolution; struct nvs_float milliamp; }; struct bmp_hal_dev { int version; unsigned int scale_n; struct bmp_scale *scale; struct nvs_float scale_float; }; union bmp_rom { struct bmp180_rom { s16 ac1; s16 ac2; s16 ac3; u16 ac4; u16 ac5; u16 ac6; s16 b1; s16 b2; s16 mb; s16 mc; s16 md; } bmp180; struct bmp280_rom { u16 dig_T1; s16 dig_T2; s16 dig_T3; u16 dig_P1; s16 dig_P2; s16 dig_P3; s16 dig_P4; s16 dig_P5; s16 dig_P6; s16 dig_P7; s16 dig_P8; s16 dig_P9; s16 reserved; } bmp280; } rom; struct bmp_cmode { unsigned int t_us; u8 t_sb; }; struct bmp_state { struct i2c_client *i2c; struct nvs_fn_if *nvs; void *nvs_st[BMP_DEV_N]; struct sensor_cfg cfg[BMP_DEV_N]; struct regulator_bulk_data vreg[ARRAY_SIZE(bmp_vregs)]; struct workqueue_struct *wq; struct work_struct ws; struct bmp_hal *hal; /* Hardware Abstaction Layer */ union bmp_rom rom; /* calibration data */ unsigned int sts; /* status flags */ unsigned int errs; /* error count */ unsigned int enabled; /* enable status */ unsigned int period_us_min; /* minimum period from MPU */ unsigned int period_us; /* global sampling period */ unsigned int delay_us[BMP_DEV_N]; /* sampling delay */ unsigned int timeout_us[BMP_DEV_N]; /* batch timeout */ unsigned int scale_i; /* oversampling index */ unsigned int scale_user; /* user oversampling index */ unsigned int mpu_bypass_n; /* allow single bypass call */ unsigned int dmp_rd_len_sts; /* status length from DMP */ unsigned int dmp_rd_len_data; /* data length from DMP */ u16 i2c_addr; /* I2C address */ u8 dev_id; /* device ID */ bool initd; /* set if initialized */ bool cmode; /* mode normal (continuous) */ bool mpu_en; /* if device behind MPU */ bool port_en[PORT_N]; /* enable status of MPU write port */ int port_id[PORT_N]; /* MPU port ID */ u8 data_out; /* write value to mode register */ s32 ut; /* uncompensated temperature */ s32 up; /* uncompensated pressure */ s32 t_fine; /* temperature used in pressure calc */ s32 tmp; /* true temperature */ u32 prs; /* true pressure hPa/100 Pa/1 mBar */ u8 nvi_config; /* NVI configuration */ }; struct bmp_hal { struct bmp_hal_dev *dev; const char *part; u8 rom_addr_start; u8 rom_size; bool rom_big_endian; u8 mode_mask; struct bmp_cmode *cmode_tbl; int (*bmp_read)(struct bmp_state *st, s64 ts); #if BMP_NVI_MPU_SUPPORT unsigned int mpu_id; u8 port_rd_reg; u8 port_rd_ctrl; void (*port_rd_handler)(u8 *data, unsigned int len, long long timestamp, void *ext_driver); #endif /* BMP_NVI_MPU_SUPPORT */ }; static void bmp_err(struct bmp_state *st) { st->errs++; if (!st->errs) st->errs--; } static int bmp_i2c_rd(struct bmp_state *st, u8 reg, u16 len, u8 *val) { struct i2c_msg msg[2]; msg[0].addr = st->i2c_addr; msg[0].flags = 0; msg[0].len = 1; msg[0].buf = ® msg[1].addr = st->i2c_addr; msg[1].flags = I2C_M_RD; msg[1].len = len; msg[1].buf = val; if (i2c_transfer(st->i2c->adapter, msg, 2) != 2) { bmp_err(st); return -EIO; } return 0; } static int bmp_i2c_wr(struct bmp_state *st, u8 reg, u8 val) { struct i2c_msg msg; u8 buf[2]; if (st->i2c_addr) { buf[0] = reg; buf[1] = val; msg.addr = st->i2c_addr; msg.flags = 0; msg.len = 2; msg.buf = buf; if (i2c_transfer(st->i2c->adapter, &msg, 1) != 1) { bmp_err(st); return -EIO; } } return 0; } static int bmp_nvi_mpu_bypass_request(struct bmp_state *st) { int ret = 0; #if BMP_NVI_MPU_SUPPORT int i; if (st->mpu_en) { if (!st->mpu_bypass_n) { for (i = 0; i < BMP_MPU_RETRY_COUNT; i++) { ret = nvi_mpu_bypass_request(true); if ((!ret) || (ret == -EPERM)) break; msleep(BMP_MPU_RETRY_DELAY_MS); } if (ret) { if (st->sts & NVS_STS_SPEW_MSG) dev_err(&st->i2c->dev, "%s err=%d\n", __func__, ret); if (ret == -EPERM) ret = 0; } else { st->mpu_bypass_n++; if (st->sts & NVS_STS_SPEW_MSG) dev_info(&st->i2c->dev, "%s\n", __func__); } } else { st->mpu_bypass_n++; } } #endif /* BMP_NVI_MPU_SUPPORT */ return ret; } static int bmp_nvi_mpu_bypass_release(struct bmp_state *st) { int ret = 0; #if BMP_NVI_MPU_SUPPORT if (st->mpu_en) { if (st->mpu_bypass_n == 1) { ret = nvi_mpu_bypass_release(); if (ret) { if (st->sts & NVS_STS_SPEW_MSG) dev_err(&st->i2c->dev, "%s err=%d\n", __func__, ret); } else { st->mpu_bypass_n--; if (st->sts & NVS_STS_SPEW_MSG) dev_info(&st->i2c->dev, "%s\n", __func__); } } else { st->mpu_bypass_n--; } } #endif /* BMP_NVI_MPU_SUPPORT */ return ret; } static int bmp_mode_wr(struct bmp_state *st, u8 mode) { int ret; #if BMP_NVI_MPU_SUPPORT if (st->mpu_en && !st->cmode) { ret = nvi_mpu_data_out(st->port_id[WR], mode); } else { ret = bmp_nvi_mpu_bypass_request(st); if (!ret) { if (st->cmode) { ret = bmp_i2c_wr(st, BMP_REG_CTRL, BMP_REG_CTRL_MODE_SLEEP); if (mode & st->hal->mode_mask) { udelay(BMP_HW_DELAY_POR_MS); ret |= bmp_i2c_wr(st, BMP_REG_CTRL, mode); } } else { ret = bmp_i2c_wr(st, BMP_REG_CTRL, mode); } if (st->sts & NVS_STS_SPEW_MSG) dev_info(&st->i2c->dev, "%s mode=%x err=%d\n", __func__, mode, ret); bmp_nvi_mpu_bypass_release(st); } } #else /* BMP_NVI_MPU_SUPPORT */ ret = bmp_i2c_wr(st, BMP_REG_CTRL, mode); if (st->sts & NVS_STS_SPEW_MSG) dev_info(&st->i2c->dev, "%s mode=%x err=%d\n", __func__, mode, ret); #endif /* BMP_NVI_MPU_SUPPORT */ if (!ret) st->data_out = mode; return ret; } static int bmp_pm(struct bmp_state *st, bool enable) { int ret = 0; if (enable) { ret = nvs_vregs_enable(&st->i2c->dev, st->vreg, ARRAY_SIZE(bmp_vregs)); if (ret) mdelay(BMP_HW_DELAY_POR_MS); } else { if (st->cmode) { ret = nvs_vregs_sts(st->vreg, ARRAY_SIZE(bmp_vregs)); if ((ret < 0) || (ret == ARRAY_SIZE(bmp_vregs))) { ret = bmp_mode_wr(st, BMP_REG_CTRL_MODE_SLEEP); } else if (ret > 0) { nvs_vregs_enable(&st->i2c->dev, st->vreg, ARRAY_SIZE(bmp_vregs)); mdelay(BMP_HW_DELAY_POR_MS); ret = bmp_mode_wr(st, BMP_REG_CTRL_MODE_SLEEP); } } ret |= nvs_vregs_disable(&st->i2c->dev, st->vreg, ARRAY_SIZE(bmp_vregs)); } if (ret > 0) ret = 0; if (ret) { dev_err(&st->i2c->dev, "%s pwr=%x ERR=%d\n", __func__, enable, ret); } else { if (st->sts & NVS_STS_SPEW_MSG) dev_info(&st->i2c->dev, "%s pwr=%x\n", __func__, enable); } return ret; } #if BMP_NVI_MPU_SUPPORT static int bmp_port_free(struct bmp_state *st, int port) { int ret = 0; if (st->port_id[port] >= 0) { ret = nvi_mpu_port_free(st->port_id[port]); if (!ret) st->port_id[port] = -1; } return ret; } static int bmp_ports_free(struct bmp_state *st) { int ret; ret = bmp_port_free(st, WR); ret |= bmp_port_free(st, RD); return ret; } #endif /* BMP_NVI_MPU_SUPPORT */ static void bmp_pm_exit(struct bmp_state *st) { #if BMP_NVI_MPU_SUPPORT bmp_ports_free(st); #endif /* BMP_NVI_MPU_SUPPORT */ bmp_pm(st, false); nvs_vregs_exit(&st->i2c->dev, st->vreg, ARRAY_SIZE(bmp_vregs)); } static int bmp_pm_init(struct bmp_state *st) { int ret; st->delay_us[BMP_DEV_PRS] = (BMP_POLL_DELAY_MS_DFLT * 1000); st->delay_us[BMP_DEV_TMP] = (BMP_POLL_DELAY_MS_DFLT * 1000); st->period_us = (BMP_POLL_DELAY_MS_DFLT * 1000); st->port_id[WR] = -1; st->port_id[RD] = -1; nvs_vregs_init(&st->i2c->dev, st->vreg, ARRAY_SIZE(bmp_vregs), bmp_vregs); ret = bmp_pm(st, true); return ret; } #if BMP_NVI_MPU_SUPPORT static int bmp_ports_enable(struct bmp_state *st, bool enable) { int ret = 0; unsigned int port_mask = 0; unsigned int i; for (i = 0; i < PORT_N; i++) { if (enable != st->port_en[i] && st->port_id[i] >= 0) port_mask |= (1 << st->port_id[i]); } if (port_mask) { ret = nvi_mpu_enable(port_mask, enable); if (!ret) { for (i = 0; i < PORT_N; i++) { if (st->port_id[i] >= 0 && port_mask & (1 << st->port_id[i])) st->port_en[i] = enable; } } } return ret; } #endif /* BMP_NVI_MPU_SUPPORT */ static int bmp_wr(struct bmp_state *st, u8 reg, u8 val) { int ret = 0; ret = bmp_nvi_mpu_bypass_request(st); if (!ret) { ret = bmp_i2c_wr(st, reg, val); bmp_nvi_mpu_bypass_release(st); } return ret; } static unsigned int bmp_cmode_t(struct bmp_state *st, u8 *t_sb, unsigned int period_us, unsigned int scale_i) { unsigned int us = 0; unsigned int i = 0; while (st->hal->cmode_tbl[i].t_us) { *t_sb = st->hal->cmode_tbl[i].t_sb; us = st->hal->cmode_tbl[i].t_us; us += st->hal->dev[BMP_DEV_PRS].scale[scale_i].delay_ms * 1000; if (period_us >= us) return us; i++; if ((!st->mpu_en) && st->hal->cmode_tbl[i].t_us) { us -= st->hal->cmode_tbl[i].t_us; us >>= 1; us += st->hal->cmode_tbl[i].t_us; us += st->hal->dev[BMP_DEV_PRS].scale[scale_i]. delay_ms * 1000; if (period_us > us) return us; } } return us; } static int bmp_mode(struct bmp_state *st, unsigned int period_us, unsigned int scale_user, unsigned int enable) { u8 mode; u8 t_sb; unsigned int i; unsigned int scale_i; unsigned int us = 0; int ret = 0; i = BMP_DEV_PRS; if (st->cmode) { if (scale_user) { /* static scale mode */ scale_i = scale_user - 1; us = bmp_cmode_t(st, &t_sb, period_us, scale_i); } else { /* auto scale mode - matching scale to the period */ scale_i = 0; for (; scale_i < st->hal->dev[i].scale_n; scale_i++) { us = bmp_cmode_t(st, &t_sb, period_us, scale_i); if (period_us >= us) /* HW (us) is fast enough */ break; } if (scale_i >= st->hal->dev[i].scale_n) scale_i = st->hal->dev[i].scale_n - 1; } if (period_us < us) period_us = us; mode = BMP280_REG_CTRL_MODE_NORMAL; mode |= st->hal->dev[BMP_DEV_TMP].scale[scale_i].os << BMP280_REG_CTRL_OSRS_T; if (enable & (1 << BMP_DEV_PRS)) mode |= st->hal->dev[BMP_DEV_PRS].scale[scale_i].os << BMP280_REG_CTRL_OSRS_P; /* else presure will be disabled */ t_sb <<= BMP280_REG_CONFIG_T_SB; ret = bmp_nvi_mpu_bypass_request(st); if (!ret) { ret = bmp_wr(st, BMP280_REG_CONFIG, t_sb); if (ret) mode = BMP_REG_CTRL_MODE_SLEEP; if (st->sts & NVS_STS_SPEW_MSG) dev_info(&st->i2c->dev, "%s cfg=%x err=%d\n", __func__, t_sb, ret); ret |= bmp_mode_wr(st, mode); bmp_nvi_mpu_bypass_release(st); } } else { if (scale_user) { scale_i = scale_user - 1; us = st->hal->dev[i].scale[scale_i].delay_ms * 1000; } else { /* scale is automatic based on period */ scale_i = 0; for (; scale_i < st->hal->dev[i].scale_n; scale_i++) { us = st->hal->dev[i].scale[scale_i].delay_ms; us *= 1000; if (period_us >= us) /* HW (us) is fast enough */ break; } if (scale_i >= st->hal->dev[i].scale_n) scale_i = st->hal->dev[i].scale_n - 1; } if (period_us < us) period_us = us; #if BMP_NVI_MPU_SUPPORT if (scale_i != st->scale_i && st->mpu_en && st->port_id[WR] >= 0) ret = nvi_mpu_delay_ms(st->port_id[WR], st->hal->dev[i].scale[scale_i].delay_ms); #endif /* BMP_NVI_MPU_SUPPORT */ if (st->dev_id == BMP_REG_ID_BMP180) { mode = st->hal->dev[i].scale[scale_i].os << BMP180_REG_CTRL_OSS; mode |= BMP180_REG_CTRL_MODE_TEMP; } else { mode = BMP280_REG_CTRL_MODE_FORCED1; mode |= st->hal->dev[BMP_DEV_TMP].scale[scale_i].os << BMP280_REG_CTRL_OSRS_T; if (enable & (1 << BMP_DEV_PRS)) mode |= st->hal->dev[i].scale[scale_i].os << BMP280_REG_CTRL_OSRS_P; } ret |= bmp_mode_wr(st, mode); } if (!ret) { if (period_us != st->period_us) { if (st->sts & NVS_STS_SPEW_MSG) dev_info(&st->i2c->dev, "%s: period_us=%u\n", __func__, period_us); #if BMP_NVI_MPU_SUPPORT if (st->mpu_en) { us = -1; for (i = 0; i < BMP_DEV_N; i++) { if ((enable & (1 << i)) && st->timeout_us[i] < us) us = st->timeout_us[i]; } ret = nvi_mpu_batch(st->port_id[RD], period_us, us); } if (!ret) #endif /* BMP_NVI_MPU_SUPPORT */ st->period_us = period_us; } if (!ret) st->scale_i = scale_i; } return ret; } static void bmp_calc_180(struct bmp_state *st) { long X1, X2, X3, B3, B5, B6, p; unsigned long B4, B7; long pressure; u8 oss = st->hal->dev[BMP_DEV_PRS].scale[st->scale_i].os; X1 = ((st->ut - st->rom.bmp180.ac6) * st->rom.bmp180.ac5) >> 15; X2 = st->rom.bmp180.mc * (1 << 11) / (X1 + st->rom.bmp180.md); B5 = X1 + X2; st->tmp = (B5 + 8) >> 4; B6 = B5 - 4000; X1 = (st->rom.bmp180.b2 * ((B6 * B6) >> 12)) >> 11; X2 = (st->rom.bmp180.ac2 * B6) >> 11; X3 = X1 + X2; B3 = ((((st->rom.bmp180.ac1 << 2) + X3) << oss) + 2) >> 2; X1 = (st->rom.bmp180.ac3 * B6) >> 13; X2 = (st->rom.bmp180.b1 * ((B6 * B6) >> 12)) >> 16; X3 = ((X1 + X2) + 2) >> 2; B4 = (st->rom.bmp180.ac4 * (unsigned long)(X3 + 32768)) >> 15; B7 = ((unsigned long)st->up - B3) * (50000 >> oss); if (B7 < 0x80000000) p = (B7 << 1) / B4; else p = (B7 / B4) << 1; X1 = (p >> 8) * (p >> 8); X1 = (X1 * 3038) >> 16; X2 = (-7357 * p) >> 16; pressure = p + ((X1 + X2 + 3791) >> 4); st->prs = (int)pressure; } static int bmp_read_sts_180(struct bmp_state *st, u8 *data, s64 ts) { u8 oss; s32 val; int ret = 0; /* BMP180_REG_CTRL_SCO is 0 when data is ready */ if (!(data[0] & (1 << BMP180_REG_CTRL_SCO))) { oss = st->hal->dev[BMP_DEV_PRS].scale[st->scale_i].os; ret = -1; if (data[0] == 0x0A) { /* temperature */ st->ut = ((data[2] << 8) + data[3]); st->data_out = BMP180_REG_CTRL_MODE_PRES | (oss << BMP180_REG_CTRL_OSS); } else { /* pressure */ val = ((data[2] << 16) + (data[3] << 8) + data[4]); val >>= (8 - oss); st->data_out = BMP180_REG_CTRL_MODE_TEMP; st->up = val; bmp_calc_180(st); ret = 1; } } return ret; } static int bmp_read_180(struct bmp_state *st, s64 ts) { u8 data[5]; int ret; ret = bmp_i2c_rd(st, BMP_REG_CTRL, 5, data); if (ret) return ret; ret = bmp_read_sts_180(st, data, ts); if (ret > 0) { if (st->enabled & (1 << BMP_DEV_PRS)) st->nvs->handler(st->nvs_st[BMP_DEV_PRS], &st->prs, ts); if (st->enabled & (1 << BMP_DEV_TMP)) /* nvs handles on-change sensor timing & same values */ st->nvs->handler(st->nvs_st[BMP_DEV_TMP], &st->tmp, ts); bmp_i2c_wr(st, BMP_REG_CTRL, st->data_out); } else if (ret < 0) { bmp_i2c_wr(st, BMP_REG_CTRL, st->data_out); } return 0; } static void bmp_calc_temp_280(struct bmp_state *st) { s32 var1; s32 var2; var1 = st->ut; var1 >>= 3; var2 = st->rom.bmp280.dig_T1; var2 <<= 1; var1 -= var2; var1 *= st->rom.bmp280.dig_T2; var1 >>= 11; var2 = st->ut; var2 >>= 4; var2 -= (s32)st->rom.bmp280.dig_T1; var2 *= var2; var2 >>= 12; var2 *= st->rom.bmp280.dig_T3; var2 >>= 14; st->t_fine = var1 + var2; st->tmp = (st->t_fine * 5 + 128) >> 8; } static int bmp_calc_pres_280(struct bmp_state *st) { s64 var1; s64 var2; s64 var3; s64 p; var1 = st->t_fine; var1 -= 128000; var2 = var1 * var1; var2 *= st->rom.bmp280.dig_P6; var3 = st->rom.bmp280.dig_P5; var3 *= var1; var3 <<= 17; var2 += var3; var3 = st->rom.bmp280.dig_P4; var3 <<= 35; var2 += var3; var3 = var1; var3 *= st->rom.bmp280.dig_P2; var3 <<= 12; var1 *= var1; var1 *= st->rom.bmp280.dig_P3; var1 >>= 8; var1 += var3; var3 = 1; var3 <<= 47; var1 += var3; var1 *= st->rom.bmp280.dig_P1; var1 >>= 33; if (!var1) return -1; p = 1048576 - st->up; p <<= 31; p -= var2; p *= 3125; p = div64_s64(p, var1); var1 = p; var1 >>= 13; var1 *= var1; var1 *= st->rom.bmp280.dig_P9; var1 >>= 25; var2 = st->rom.bmp280.dig_P8; var2 *= p; var2 >>= 19; var3 = st->rom.bmp280.dig_P7; var3 <<= 4; p += var1; p += var2; p >>= 8; p += var3; p >>= 8; st->prs = (u32)p; return 1; } static int bmp_push_280(struct bmp_state *st, u8 *data, s64 ts) { s32 val; int ret; val = (data[0] << 16) | (data[1] << 8) | data[2]; val = le32_to_cpup(&val); val >>= 4; st->up = val; val = (data[3] << 16) | (data[4] << 8) | data[5]; val = le32_to_cpup(&val); val >>= 4; st->ut = val; bmp_calc_temp_280(st); if (st->enabled & (1 << BMP_DEV_PRS)) { ret = bmp_calc_pres_280(st); if (ret > 0) st->nvs->handler(st->nvs_st[BMP_DEV_PRS], &st->prs, ts); } else { ret = 1; } if (st->enabled & (1 << BMP_DEV_TMP)) /* nvs handles on-change sensor timing & same values */ st->nvs->handler(st->nvs_st[BMP_DEV_TMP], &st->tmp, ts); return ret; } static int bmp_read_sts_280(struct bmp_state *st, u8 *data) { if (data[0] & (1 << BMP280_REG_STATUS_IM_UPDATE)) /* registers are updating */ return 0; return 1; } static int bmp_read_280(struct bmp_state *st, s64 ts) { u8 data[10]; int ret; ret = bmp_i2c_rd(st, BMP280_REG_STATUS, 10, data); if (ret) return ret; ret = bmp_read_sts_280(st, data); if (ret > 0) { ret = bmp_push_280(st, &data[4], ts); if (ret > 0) bmp_i2c_wr(st, BMP_REG_CTRL, st->data_out); } return 0; } #if BMP_NVI_MPU_SUPPORT static void bmp_mpu_handler_280(u8 *data, unsigned int len, s64 ts, void *p_val) { struct bmp_state *st = (struct bmp_state *)p_val; unsigned int i; int ret; if (ts < 0 || !data) /* error - just drop */ return; if (!ts) { /* no timestamp means flush done */ for (i = 0; i < BMP_DEV_N; i++) { if (st->nvs_st[i]) st->nvs->handler(st->nvs_st[i], NULL, 0); } return; } if (st->enabled) { if (len == st->dmp_rd_len_sts) /* status data from the DMP not supported */ return; if (len == st->dmp_rd_len_data) { /* this data is from the DMP */ i = 0; ret = 1; } else { i = 4; ret = bmp_read_sts_280(st, data); } if (ret > 0) bmp_push_280(st, &data[i], ts); } } static void bmp_mpu_handler_180(u8 *data, unsigned int len, s64 ts, void *p_val) { struct bmp_state *st = (struct bmp_state *)p_val; unsigned int i; int ret; if (ts < 0) /* error - just drop */ return; if (!ts) { /* no timestamp means flush done */ for (i = 0; i < BMP_DEV_N; i++) { if (st->nvs_st[i]) st->nvs->handler(st->nvs_st[i], NULL, 0); } return; } ret = bmp_read_sts_180(st, data, ts); if (ret > 0) { if (st->enabled & (1 << BMP_DEV_PRS)) st->nvs->handler(st->nvs_st[BMP_DEV_PRS], &st->prs, ts); if (st->enabled & (1 << BMP_DEV_TMP)) /* nvs handles on-change sensor timing & same values */ st->nvs->handler(st->nvs_st[BMP_DEV_TMP], &st->tmp, ts); nvi_mpu_data_out(st->port_id[WR], st->data_out); } else if (ret < 0) { nvi_mpu_data_out(st->port_id[WR], st->data_out); } } #endif /* BMP_NVI_MPU_SUPPORT */ static void bmp_work(struct work_struct *ws) { struct bmp_state *st = container_of((struct work_struct *)ws, struct bmp_state, ws); s64 ts1; s64 ts2; unsigned int ts_diff; unsigned int i; unsigned long delay_us; while (1) { for (i = 0; i < BMP_DEV_N; i++) st->nvs->nvs_mutex_lock(st->nvs_st[i]); if (st->enabled) { ts1 = nvs_timestamp(); st->hal->bmp_read(st, ts1); ts2 = nvs_timestamp(); ts_diff = (ts2 - ts1) / 1000; /* ns => us */ if (st->period_us > ts_diff) delay_us = st->period_us - ts_diff; else delay_us = 0; for (i = 0; i < BMP_DEV_N; i++) st->nvs->nvs_mutex_unlock(st->nvs_st[i]); } else { for (i = 0; i < BMP_DEV_N; i++) st->nvs->nvs_mutex_unlock(st->nvs_st[i]); break; } if (delay_us) { if (st->period_us <= st->cfg[BMP_DEV_PRS].thresh_lo) usleep_range(delay_us, delay_us); else usleep_range(delay_us, st->period_us); } } } static unsigned int bmp_poll_delay(struct bmp_state *st, unsigned int en_msk) { unsigned int i; unsigned int delay_us = -1; bool valid = false; for (i = 0; i < BMP_DEV_N; i++) { if (en_msk & (1 << i)) { if (st->delay_us[i] && st->delay_us[i] < delay_us) { delay_us = st->delay_us[i]; valid = true; } } } if (!valid) delay_us = (BMP_POLL_DELAY_MS_DFLT * 1000); return delay_us; } static int bmp_init_hw(struct bmp_state *st) { u8 *p_rom8; u16 *p_rom16; int i; int ret = 0; st->ut = 0; st->up = 0; st->tmp = 0; st->prs = 0; p_rom8 = (u8 *)&st->rom; ret = bmp_nvi_mpu_bypass_request(st); if (!ret) { ret = bmp_i2c_rd(st, st->hal->rom_addr_start, st->hal->rom_size, p_rom8); bmp_nvi_mpu_bypass_release(st); } if (ret) return ret; p_rom16 = (u16 *)&st->rom; for (i = 0; i < (st->hal->rom_size >> 1); i++) { if (st->hal->rom_big_endian) *p_rom16 = be16_to_cpup(p_rom16); else *p_rom16 = le16_to_cpup(p_rom16); p_rom16++; } st->initd = true; return ret; } static int bmp_dis(struct bmp_state *st) { #if BMP_NVI_MPU_SUPPORT int ret = 0; if (st->mpu_en) ret = bmp_ports_enable(st, false); if (!ret) st->enabled = 0; return ret; #else /* BMP_NVI_MPU_SUPPORT */ st->enabled = 0; return 0; #endif /* BMP_NVI_MPU_SUPPORT */ } static int bmp_disable(struct bmp_state *st, int snsr_id) { bool disable = true; int ret = 0; if (snsr_id >= 0) { if (st->enabled & ~(1 << snsr_id)) { st->enabled &= ~(1 << snsr_id); disable = false; } } if (disable) { ret = bmp_dis(st); if (!ret) bmp_pm(st, false); } return ret; } static int bmp_en(struct bmp_state *st) { int ret = 0; bmp_pm(st, true); if (!st->initd) ret = bmp_init_hw(st); return ret; } static int bmp_enable(void *client, int snsr_id, int enable) { struct bmp_state *st = (struct bmp_state *)client; int ret; if (enable < 0) return st->enabled & (1 << snsr_id); if (enable) { enable = st->enabled | (1 << snsr_id); ret = bmp_en(st); if (!ret) { ret = bmp_mode(st, bmp_poll_delay(st, enable), st->scale_user, enable); #if BMP_NVI_MPU_SUPPORT if (st->mpu_en) ret |= bmp_ports_enable(st, true); #endif /* BMP_NVI_MPU_SUPPORT */ if (ret) { bmp_disable(st, snsr_id); } else { st->enabled = enable; if (!st->mpu_en) { cancel_work_sync(&st->ws); queue_work(st->wq, &st->ws); } } } } else { ret = bmp_disable(st, snsr_id); } return ret; } static int bmp_batch(void *client, int snsr_id, int flags, unsigned int period, unsigned int timeout) { struct bmp_state *st = (struct bmp_state *)client; int ret = 0; unsigned int old_period; unsigned int old_timeout; if (timeout && !st->mpu_en) /* timeout not supported (no HW FIFO) */ return -EINVAL; old_period = st->delay_us[snsr_id]; old_timeout = st->timeout_us[snsr_id]; st->delay_us[snsr_id] = period; st->timeout_us[snsr_id] = timeout; if (st->enabled) { ret = bmp_mode(st, bmp_poll_delay(st, st->enabled), st->scale_user, st->enabled); if (ret) { st->delay_us[snsr_id] = old_period; st->timeout_us[snsr_id] = old_timeout; } } return ret; } static int bmp_batch_read(void *client, int snsr_id, unsigned int *period_us, unsigned int *timeout_us) { struct bmp_state *st = (struct bmp_state *)client; int ret = 0; if (period_us) *period_us = st->period_us; if (timeout_us) *timeout_us = 0; #if BMP_NVI_MPU_SUPPORT if (st->mpu_en) ret = nvi_mpu_batch_read(st->port_id[RD], period_us, timeout_us); #endif /* BMP_NVI_MPU_SUPPORT */ return ret; } static int bmp_flush(void *client, int snsr_id) { int ret = -EINVAL; #if BMP_NVI_MPU_SUPPORT struct bmp_state *st = (struct bmp_state *)client; if (st->mpu_en) ret = nvi_mpu_flush(st->port_id[RD]); #endif /* BMP_NVI_MPU_SUPPORT */ return ret; } static int bmp_resolution(void *client, int snsr_id, int resolution) { struct bmp_state *st = (struct bmp_state *)client; unsigned int us; unsigned int i; int ret; if (snsr_id != BMP_DEV_PRS) return -EINVAL; if (resolution < 0) resolution = 0; if (resolution > st->hal->dev[BMP_DEV_PRS].scale_n) resolution = st->hal->dev[BMP_DEV_PRS].scale_n; if (st->enabled) { ret = bmp_mode(st, st->period_us, resolution, st->enabled); if (ret) return ret; } else { if (resolution) st->scale_i = resolution - 1; else st->scale_i = 0; } st->scale_user = resolution; for (i = 0; i < BMP_DEV_N; i++) { st->cfg[i].resolution.ival = st->hal->dev[i].scale[st->scale_i].resolution.ival; st->cfg[i].resolution.fval = st->hal->dev[i].scale[st->scale_i].resolution.fval; st->cfg[i].milliamp.ival = st->hal->dev[i].scale[st->scale_i].milliamp.ival; st->cfg[i].milliamp.fval = st->hal->dev[i].scale[st->scale_i].milliamp.fval; us = st->hal->dev[i].scale[st->scale_i].delay_ms * 1000; if (us < st->period_us_min) us = st->period_us_min; st->cfg[i].delay_us_min = us; } return 0; } static int bmp_reset(void *client, int snsr_id) { struct bmp_state *st = (struct bmp_state *)client; unsigned int enabled = st->enabled; unsigned int i; int ret; bmp_dis(st); bmp_en(st); ret = bmp_wr(st, BMP_REG_RESET, BMP_REG_RESET_VAL); if (!ret) mdelay(BMP_HW_DELAY_POR_MS); for (i = 0; i < BMP_DEV_N; i++) bmp_enable(st, i, enabled & (1 << i)); return ret; } static int bmp_regs(void *client, int snsr_id, char *buf) { struct bmp_state *st = (struct bmp_state *)client; ssize_t t; u8 data[11]; u16 *cal; unsigned int i; int ret; if (!st->initd) { t = snprintf(buf, PAGE_SIZE, "calibration: NEED ENABLE\n"); } else { t = snprintf(buf, PAGE_SIZE, "calibration:\n"); cal = &st->rom.bmp280.dig_T1; for (i = 0; i < st->hal->rom_size; i = i + 2) t += snprintf(buf + t, PAGE_SIZE - t, "%#2x=%#2x\n", st->hal->rom_addr_start + i, *cal++); } ret = bmp_nvi_mpu_bypass_request(st); if (!ret) { ret = bmp_i2c_rd(st, BMP_REG_ID, 1, data); ret |= bmp_i2c_rd(st, BMP280_REG_STATUS, 10, &data[1]); bmp_nvi_mpu_bypass_release(st); } if (ret) { t += snprintf(buf + t, PAGE_SIZE - t, "registers: ERR %d\n", ret); } else { t += snprintf(buf + t, PAGE_SIZE - t, "registers:\n"); t += snprintf(buf + t, PAGE_SIZE - t, "%#2x=%#2x\n", BMP_REG_ID, data[0]); for (i = 0; i < 10; i++) t += snprintf(buf + t, PAGE_SIZE - t, "%#2x=%#2x\n", BMP280_REG_STATUS + i, data[i + 1]); } return t; } static int bmp_nvs_read(void *client, int snsr_id, char *buf) { struct bmp_state *st = (struct bmp_state *)client; ssize_t t; t = snprintf(buf, PAGE_SIZE, "driver v.%u\n", BMP_DRIVER_VERSION); t += snprintf(buf + t, PAGE_SIZE - t, "mpu_en=%x\n", st->mpu_en); t += snprintf(buf + t, PAGE_SIZE - t, "nvi_config=%hhu\n", st->nvi_config); t += snprintf(buf + t, PAGE_SIZE - t, "cmode_enable=%x\n", st->cmode); if (!st->scale_user) t += snprintf(buf + t, PAGE_SIZE - t, "scale_user=auto\n"); t += snprintf(buf + t, PAGE_SIZE - t, "scale_i=%x\n", st->scale_i); return t; } static struct nvs_fn_dev bmp_fn_dev = { .enable = bmp_enable, .batch = bmp_batch, .batch_read = bmp_batch_read, .flush = bmp_flush, .resolution = bmp_resolution, .reset = bmp_reset, .regs = bmp_regs, .nvs_read = bmp_nvs_read, }; #ifdef CONFIG_PM_SLEEP static int bmp_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct bmp_state *st = i2c_get_clientdata(client); unsigned int i; int ret = 0; st->sts |= NVS_STS_SUSPEND; for (i = 0; i < BMP_DEV_N; i++) { if (st->nvs && st->nvs_st[i]) ret |= st->nvs->suspend(st->nvs_st[i]); } if (st->sts & NVS_STS_SPEW_MSG) dev_info(&client->dev, "%s\n", __func__); return ret; } static int bmp_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct bmp_state *st = i2c_get_clientdata(client); unsigned int i; int ret = 0; for (i = 0; i < BMP_DEV_N; i++) { if (st->nvs && st->nvs_st[i]) ret |= st->nvs->resume(st->nvs_st[i]); } st->sts &= ~NVS_STS_SUSPEND; if (st->sts & NVS_STS_SPEW_MSG) dev_info(&client->dev, "%s\n", __func__); return ret; } #endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(bmp_pm_ops, bmp_suspend, bmp_resume); static void bmp_shutdown(struct i2c_client *client) { struct bmp_state *st = i2c_get_clientdata(client); unsigned int i; st->sts |= NVS_STS_SHUTDOWN; for (i = 0; i < BMP_DEV_N; i++) { if (st->nvs && st->nvs_st[i]) st->nvs->shutdown(st->nvs_st[i]); } if (st->sts & NVS_STS_SPEW_MSG) dev_info(&client->dev, "%s\n", __func__); } static int bmp_remove(struct i2c_client *client) { struct bmp_state *st = i2c_get_clientdata(client); unsigned int i; if (st != NULL) { bmp_shutdown(client); if (st->nvs) { for (i = 0; i < BMP_DEV_N; i++) { if (st->nvs_st[i]) { st->nvs->remove(st->nvs_st[i]); st->nvs_st[i] = NULL; } } } bmp_pm_exit(st); if (st->wq) { destroy_workqueue(st->wq); st->wq = NULL; } } dev_info(&client->dev, "%s\n", __func__); return 0; } struct sensor_cfg bmp_cfg_dflt[] = { { .name = "pressure", .snsr_id = BMP_DEV_PRS, .kbuf_sz = BMP_KBUF_SIZE, .ch_n = 1, .ch_sz = -4, .part = BMP_NAME, .vendor = BMP_VENDOR, .version = 0, .max_range = { .ival = BMP_PRES_MAX_RANGE_IVAL, .fval = BMP_PRES_MAX_RANGE_MICRO, }, }, { .name = "ambient_temperature", .snsr_id = BMP_DEV_TMP, .ch_n = 1, .ch_sz = -4, .part = BMP_NAME, .vendor = BMP_VENDOR, .version = 0, .max_range = { .ival = BMP_TEMP_MAX_RANGE_IVAL, .fval = BMP_TEMP_MAX_RANGE_MICRO, }, .flags = SENSOR_FLAG_ON_CHANGE_MODE, }, }; static struct bmp_scale bmp_scale_prs_180[] = { { .delay_ms = 26, .os = 0x03, .resolution = { .ival = 0, .fval = 10000, }, .milliamp = { .ival = 0, .fval = 12000, }, }, { .delay_ms = 14, .os = 0x02, .resolution = { .ival = 0, .fval = 10000, }, .milliamp = { .ival = 0, .fval = 7000, }, }, { .delay_ms = 8, .os = 0x01, .resolution = { .ival = 0, .fval = 10000, }, .milliamp = { .ival = 0, .fval = 5000, }, }, { .delay_ms = 5, .os = 0x00, .resolution = { .ival = 0, .fval = 10000, }, .milliamp = { .ival = 0, .fval = 3000, }, }, }; static struct bmp_scale bmp_scale_tmp_180[] = { { .delay_ms = 26, .resolution = { .ival = 0, .fval = 100000, }, .milliamp = { .ival = 0, .fval = 12000, }, }, { .delay_ms = 14, .resolution = { .ival = 0, .fval = 100000, }, .milliamp = { .ival = 0, .fval = 7000, }, }, { .delay_ms = 8, .resolution = { .ival = 0, .fval = 100000, }, .milliamp = { .ival = 0, .fval = 5000, }, }, { .delay_ms = 5, .resolution = { .ival = 0, .fval = 100000, }, .milliamp = { .ival = 0, .fval = 3000, }, }, }; static struct bmp_hal_dev bmp_hal_dev_180[] = { { .version = 1, .scale_n = ARRAY_SIZE(bmp_scale_prs_180), .scale = bmp_scale_prs_180, .scale_float = { .ival = 0, .fval = 10000, }, }, { .version = 1, .scale_n = ARRAY_SIZE(bmp_scale_tmp_180), .scale = bmp_scale_tmp_180, .scale_float = { .ival = 0, .fval = 100000, } }, }; static struct bmp_hal bmp_hal_180 = { .dev = bmp_hal_dev_180, .part = BMP180_NAME, .rom_addr_start = BMP180_REG_AC1, .rom_size = 22, .rom_big_endian = true, .mode_mask = BMP180_REG_CTRL_MODE_MASK, .cmode_tbl = NULL, .bmp_read = &bmp_read_180, #if BMP_NVI_MPU_SUPPORT .mpu_id = 0, .port_rd_reg = BMP_REG_CTRL, .port_rd_ctrl = 6, .port_rd_handler = &bmp_mpu_handler_180, #endif /* BMP_NVI_MPU_SUPPORT */ }; static struct bmp_scale bmp_scale_prs_280[] = { { .delay_ms = 44, .os = 0x05, .resolution = { .ival = 0, .fval = 1800, }, .milliamp = { .ival = 0, .fval = 24800, }, }, { .delay_ms = 23, .os = 0x04, .resolution = { .ival = 0, .fval = 3600, }, .milliamp = { .ival = 0, .fval = 12700, }, }, { .delay_ms = 14, .os = 0x03, .resolution = { .ival = 0, .fval = 7200, }, .milliamp = { .ival = 0, .fval = 7020, }, }, { .delay_ms = 9, .os = 0x02, .resolution = { .ival = 0, .fval = 14300, }, .milliamp = { .ival = 0, .fval = 4170, }, }, { .delay_ms = 7, .os = 0x01, .resolution = { .ival = 0, .fval = 28700, }, .milliamp = { .ival = 0, .fval = 2740, }, }, }; static struct bmp_scale bmp_scale_tmp_280[] = { /* os oversampling is useless > 2x and only used for pressure @ 16x */ { .delay_ms = 44, .os = 0x02, .resolution = { .ival = 0, .fval = 300, }, .milliamp = { .ival = 0, .fval = 24800, }, }, { .delay_ms = 23, .os = 0x01, .resolution = { .ival = 0, .fval = 600, }, .milliamp = { .ival = 0, .fval = 12700, }, }, { .delay_ms = 14, .os = 0x01, .resolution = { .ival = 0, .fval = 1200, }, .milliamp = { .ival = 0, .fval = 7020, }, }, { .delay_ms = 9, .os = 0x01, .resolution = { .ival = 0, .fval = 2500, }, .milliamp = { .ival = 0, .fval = 4170, }, }, { .delay_ms = 7, .os = 0x01, .resolution = { .ival = 0, .fval = 5000, }, .milliamp = { .ival = 0, .fval = 2740, }, }, }; static struct bmp_hal_dev bmp_hal_dev_280[] = { { .version = 1, .scale_n = ARRAY_SIZE(bmp_scale_prs_280), .scale = bmp_scale_prs_280, .scale_float = { .ival = 0, .fval = 10000, } }, { .version = 1, .scale_n = ARRAY_SIZE(bmp_scale_tmp_280), .scale = bmp_scale_tmp_280, .scale_float = { .ival = 0, .fval = 10000, }, }, }; static struct bmp_cmode bmp_cmode_280[] = { { .t_us = 4000000, .t_sb = 0x07, }, { .t_us = 2000000, .t_sb = 0x06, }, { .t_us = 1000000, .t_sb = 0x05, }, { .t_us = 500000, .t_sb = 0x04, }, { .t_us = 250000, .t_sb = 0x03, }, { .t_us = 125000, .t_sb = 0x02, }, { .t_us = 62500, .t_sb = 0x01, }, { .t_us = 500, .t_sb = 0x00, }, {}, }; static struct bmp_hal bmp_hal_280 = { .dev = bmp_hal_dev_280, .part = BMP280_NAME, .rom_addr_start = BMP280_REG_CWORD00, .rom_size = 26, .rom_big_endian = false, .mode_mask = BMP280_REG_CTRL_MODE_MASK, .cmode_tbl = bmp_cmode_280, .bmp_read = &bmp_read_280, #if BMP_NVI_MPU_SUPPORT .mpu_id = PRESSURE_ID_BMP280, .port_rd_reg = BMP280_REG_STATUS, .port_rd_ctrl = 10, .port_rd_handler = &bmp_mpu_handler_280, #endif /* BMP_NVI_MPU_SUPPORT */ }; static int bmp_id_hal(struct bmp_state *st) { unsigned int i; int ret = 0; switch (st->dev_id) { case BMP_REG_ID_BMP280: st->hal = &bmp_hal_280; break; case BMP_REG_ID_BMP180: st->hal = &bmp_hal_180; break; default: dev_err(&st->i2c->dev, "%s ERR: Unknown device\n", __func__); st->hal = &bmp_hal_280; /* to prevent NULL pointers */ ret = -ENODEV; break; } /* default scale to fastest and least power usage */ st->scale_user = st->hal->dev[BMP_DEV_PRS].scale_n; st->scale_i = st->scale_user - 1; if (st->hal->cmode_tbl == NULL) st->cmode = false; for (i = 0; i < BMP_DEV_N; i++) memcpy(&st->cfg[i], &bmp_cfg_dflt[i], sizeof(struct sensor_cfg)); for (i = 0; i < BMP_DEV_N; i++) { st->cfg[i].part = st->hal->part; st->cfg[i].version = st->hal->dev[i].version; st->cfg[i].scale.ival = st->hal->dev[i].scale_float.ival; st->cfg[i].scale.fval = st->hal->dev[i].scale_float.fval; } return ret; } static int bmp_id_compare(struct bmp_state *st, u8 val, const char *name) { unsigned int i; int ret = 0; for (i = 0; i < ARRAY_SIZE(bmp_ids); i++) { if (val == bmp_ids[i]) { if ((st->dev_id == BMP_REG_ID_BMP180) && (st->dev_id != val)) dev_err(&st->i2c->dev, "%s ERR: %x != %s\n", __func__, st->dev_id, name); if (val != BMP_REG_ID_BMP180) /* BMP280 may have more ID's than 0x56 */ val = BMP_REG_ID_BMP280; st->dev_id = val; break; } } if (!st->dev_id) { ret = -ENODEV; dev_err(&st->i2c->dev, "%s ERR: ID %x != %s\n", __func__, val, name); } else { dev_dbg(&st->i2c->dev, "%s using ID %x for %s\n", __func__, st->dev_id, name); } return ret; } static int bmp_id_dev(struct bmp_state *st, const char *name) { #if BMP_NVI_MPU_SUPPORT struct nvi_mpu_port nmp; struct nvi_mpu_inf inf; unsigned int i; u8 config_boot; #endif /* BMP_NVI_MPU_SUPPORT */ u8 val = 0; int ret; if (!strcmp(name, BMP180_NAME)) st->dev_id = BMP_REG_ID_BMP180; else if (!strcmp(name, BMP280_NAME)) st->dev_id = BMP_REG_ID_BMP280; #if BMP_NVI_MPU_SUPPORT config_boot = st->nvi_config & NVI_CONFIG_BOOT_MASK; if ((config_boot == NVI_CONFIG_BOOT_MPU) && (!st->dev_id)) { dev_err(&st->i2c->dev, "%s ERR: NVI_CONFIG_BOOT_MPU && %s\n", __func__, name); config_boot = NVI_CONFIG_BOOT_AUTO; } if (config_boot == NVI_CONFIG_BOOT_AUTO) { nmp.addr = st->i2c_addr | 0x80; nmp.reg = BMP_REG_ID; nmp.ctrl = 1; ret = nvi_mpu_dev_valid(&nmp, &val); dev_info(&st->i2c->dev, "%s AUTO ID=%x ret=%d\n", __func__, val, ret); /* see mpu_iio.h for possible return values */ if ((ret == -EAGAIN) || (ret == -EBUSY)) return -EAGAIN; if (!ret) ret = bmp_id_compare(st, val, name); if ((!ret) || ((ret == -EIO) && (st->dev_id))) config_boot = NVI_CONFIG_BOOT_MPU; } if (config_boot == NVI_CONFIG_BOOT_MPU) { st->mpu_en = true; bmp_id_hal(st); nmp.type = SECONDARY_SLAVE_TYPE_PRESSURE; nmp.id = st->hal->mpu_id; nmp.addr = st->i2c_addr; /* write port */ nmp.reg = BMP_REG_CTRL; nmp.ctrl = 1; nmp.data_out = st->data_out; nmp.delay_ms = st->hal->dev[BMP_DEV_PRS]. scale[st->scale_i].delay_ms; nmp.period_us = 0; nmp.shutdown_bypass = false; nmp.handler = NULL; nmp.ext_driver = NULL; ret = nvi_mpu_port_alloc(&nmp); dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n", __func__, ret); /* By requesting the write port first it allows us to * automatically determine if the DMP requires a single * port, in which case this port request will fail. * If this part does not support continuous mode * required for single port operation, then this device * population fails. */ if (ret < 0) { if (st->hal->cmode_tbl) st->cmode = true; else return ret; } else { st->cmode = false; st->port_id[WR] = ret; } nmp.addr = st->i2c_addr | 0x80; /* read port */ nmp.data_out = 0; nmp.delay_ms = 0; nmp.period_us = st->period_us; if (st->cmode) nmp.shutdown_bypass = true; nmp.ext_driver = (void *)st; nmp.reg = st->hal->port_rd_reg; nmp.ctrl = st->hal->port_rd_ctrl; nmp.handler = st->hal->port_rd_handler; ret = nvi_mpu_port_alloc(&nmp); dev_dbg(&st->i2c->dev, "%s MPU port/ret=%d\n", __func__, ret); if (ret < 0) { bmp_ports_free(st); dev_err(&st->i2c->dev, "%s ERR %d\n", __func__, ret); return ret; } st->port_id[RD] = ret; ret = nvi_mpu_info(st->port_id[RD], &inf); if (ret) return ret; st->period_us_min = inf.period_us_min; for (i = 0; i < BMP_DEV_N; i++) { st->cfg[i].fifo_rsrv_evnt_cnt = inf.fifo_reserve; st->cfg[i].fifo_max_evnt_cnt = inf.fifo_max; st->cfg[i].delay_us_max = inf.period_us_max; } st->dmp_rd_len_sts = inf.dmp_rd_len_sts; st->dmp_rd_len_data = inf.dmp_rd_len_data; return 0; } #endif /* BMP_NVI_MPU_SUPPORT */ /* NVI_CONFIG_BOOT_HOST */ st->mpu_en = false; if (!st->dev_id) { ret = bmp_i2c_rd(st, BMP_REG_ID, 1, &val); dev_dbg(&st->i2c->dev, "%s Host read ID=%x ret=%d\n", __func__, val, ret); if (!ret) bmp_id_compare(st, val, name); } ret = bmp_id_hal(st); return ret; } static int bmp_id_i2c(struct bmp_state *st, const struct i2c_device_id *id) { int i; int ret; for (i = 0; i < ARRAY_SIZE(bmp_i2c_addrs); i++) { if (st->i2c->addr == bmp_i2c_addrs[i]) break; } if (i < ARRAY_SIZE(bmp_i2c_addrs)) { st->i2c_addr = st->i2c->addr; ret = bmp_id_dev(st, id->name); } else { for (i = 0; i < ARRAY_SIZE(bmp_i2c_addrs); i++) { st->i2c_addr = bmp_i2c_addrs[i]; ret = bmp_id_dev(st, BMP_NAME); if ((ret == -EAGAIN) || (!ret)) break; } } if (ret) st->i2c_addr = 0; return ret; } static int bmp_of_dt(struct bmp_state *st, struct device_node *dn) { char const *pchar; u8 cfg; int ret; if (dn) { /* just test if global disable */ ret = nvs_of_dt(dn, NULL, NULL); if (ret == -ENODEV) return -ENODEV; /* this device supports these programmable parameters */ if (!of_property_read_string(dn, "nvi_config", &pchar)) { for (cfg = 0; cfg < ARRAY_SIZE(bmp_configs); cfg++) { if (!strcasecmp(pchar, bmp_configs[cfg])) { st->nvi_config = cfg; break; } } } if (!of_property_read_u8(dn, "cmode_enable", &cfg)) { if (cfg) st->cmode = true; else st->cmode = false; } } return 0; } static int bmp_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bmp_state *st; unsigned int i; unsigned int n; int ret; dev_info(&client->dev, "%s %s\n", id->name, __func__); st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL); if (st == NULL) { dev_err(&client->dev, "%s devm_kzalloc ERR\n", __func__); return -ENOMEM; } i2c_set_clientdata(client, st); st->i2c = client; ret = bmp_of_dt(st, client->dev.of_node); if (ret) { if (ret == -ENODEV) { dev_info(&client->dev, "%s DT disabled\n", __func__); } else { dev_err(&client->dev, "%s _of_dt ERR\n", __func__); ret = -ENODEV; } goto bmp_probe_err; } bmp_pm_init(st); ret = bmp_id_i2c(st, id); if (ret == -EAGAIN) { ret = -EPROBE_DEFER; goto bmp_probe_exit; } else if (ret) { goto bmp_probe_err; } bmp_init_hw(st); bmp_pm(st, false); bmp_fn_dev.errs = &st->errs; bmp_fn_dev.sts = &st->sts; st->nvs = nvs_iio(); if (st->nvs == NULL) { ret = -ENODEV; goto bmp_probe_err; } st->cfg[BMP_DEV_PRS].resolution.ival = st->scale_user; nvs_of_dt(client->dev.of_node, &st->cfg[BMP_DEV_PRS], NULL); bmp_resolution(st, BMP_DEV_PRS, st->cfg[BMP_DEV_PRS].resolution.ival); nvs_of_dt(client->dev.of_node, &st->cfg[BMP_DEV_TMP], NULL); if (st->cfg[BMP_DEV_PRS].snsr_id < 0) /* pressure disabled so use temperature settings */ bmp_resolution(st, BMP_DEV_PRS, st->cfg[BMP_DEV_TMP].resolution.ival); n = 0; for (i = 0; i < BMP_DEV_N; i++) { ret = st->nvs->probe(&st->nvs_st[i], st, &client->dev, &bmp_fn_dev, &st->cfg[i]); if (!ret) n++; } if (!n) { ret = -ENODEV; goto bmp_probe_exit; } if (!st->mpu_en) { st->wq = create_workqueue(BMP_NAME); if (!st->wq) { ret = -ENOMEM; goto bmp_probe_err; } INIT_WORK(&st->ws, bmp_work); } dev_info(&client->dev, "%s done\n", __func__); return 0; bmp_probe_err: dev_err(&client->dev, "%s ERR %d\n", __func__, ret); bmp_probe_exit: bmp_remove(client); return ret; } static const struct i2c_device_id bmp_i2c_device_id[] = { { BMP_NAME, 0 }, { BMP180_NAME, 0 }, { BMP280_NAME, 0 }, {} }; MODULE_DEVICE_TABLE(i2c, bmp_i2c_device_id); static const struct of_device_id bmp_of_match[] = { { .compatible = "bmp,bmpX80", }, { .compatible = "bmp,bmp180", }, { .compatible = "bmp,bmp280", }, {}, }; MODULE_DEVICE_TABLE(of, bmp_of_match); static struct i2c_driver bmp_driver = { .class = I2C_CLASS_HWMON, .probe = bmp_probe, .remove = bmp_remove, .shutdown = bmp_shutdown, .driver = { .name = BMP_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(bmp_of_match), .pm = &bmp_pm_ops, }, .id_table = bmp_i2c_device_id, }; static int __init bmp_init(void) { return i2c_add_driver(&bmp_driver); } static void __exit bmp_exit(void) { i2c_del_driver(&bmp_driver); } late_initcall(bmp_init); module_exit(bmp_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("BMPX80 driver"); MODULE_AUTHOR("NVIDIA Corporation");