423 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * hp206c.c - HOPERF HP206C precision barometer and altimeter sensor4 *5 * Copyright (c) 2016, Intel Corporation.6 *7 * (7-bit I2C slave address 0x76)8 *9 * Datasheet:10 * http://www.hoperf.com/upload/sensor/HP206C_DataSheet_EN_V2.0.pdf11 */12 13#include <linux/module.h>14#include <linux/mod_devicetable.h>15#include <linux/i2c.h>16#include <linux/iio/iio.h>17#include <linux/iio/sysfs.h>18#include <linux/delay.h>19#include <linux/util_macros.h>20 21#include <linux/unaligned.h>22 23/* I2C commands: */24#define HP206C_CMD_SOFT_RST 0x0625 26#define HP206C_CMD_ADC_CVT 0x4027 28#define HP206C_CMD_ADC_CVT_OSR_4096 0x0029#define HP206C_CMD_ADC_CVT_OSR_2048 0x0430#define HP206C_CMD_ADC_CVT_OSR_1024 0x0831#define HP206C_CMD_ADC_CVT_OSR_512 0x0c32#define HP206C_CMD_ADC_CVT_OSR_256 0x1033#define HP206C_CMD_ADC_CVT_OSR_128 0x1434 35#define HP206C_CMD_ADC_CVT_CHNL_PT 0x0036#define HP206C_CMD_ADC_CVT_CHNL_T 0x0237 38#define HP206C_CMD_READ_P 0x3039#define HP206C_CMD_READ_T 0x3240 41#define HP206C_CMD_READ_REG 0x8042#define HP206C_CMD_WRITE_REG 0xc043 44#define HP206C_REG_INT_EN 0x0b45#define HP206C_REG_INT_CFG 0x0c46 47#define HP206C_REG_INT_SRC 0x0d48#define HP206C_FLAG_DEV_RDY 0x4049 50#define HP206C_REG_PARA 0x0f51#define HP206C_FLAG_CMPS_EN 0x8052 53/* Maximum spin for DEV_RDY */54#define HP206C_MAX_DEV_RDY_WAIT_COUNT 2055#define HP206C_DEV_RDY_WAIT_US 2000056 57struct hp206c_data {58 struct mutex mutex;59 struct i2c_client *client;60 int temp_osr_index;61 int pres_osr_index;62};63 64struct hp206c_osr_setting {65 u8 osr_mask;66 unsigned int temp_conv_time_us;67 unsigned int pres_conv_time_us;68};69 70/* Data from Table 5 in datasheet. */71static const struct hp206c_osr_setting hp206c_osr_settings[] = {72 { HP206C_CMD_ADC_CVT_OSR_4096, 65600, 131100 },73 { HP206C_CMD_ADC_CVT_OSR_2048, 32800, 65600 },74 { HP206C_CMD_ADC_CVT_OSR_1024, 16400, 32800 },75 { HP206C_CMD_ADC_CVT_OSR_512, 8200, 16400 },76 { HP206C_CMD_ADC_CVT_OSR_256, 4100, 8200 },77 { HP206C_CMD_ADC_CVT_OSR_128, 2100, 4100 },78};79static const int hp206c_osr_rates[] = { 4096, 2048, 1024, 512, 256, 128 };80static const char hp206c_osr_rates_str[] = "4096 2048 1024 512 256 128";81 82static inline int hp206c_read_reg(struct i2c_client *client, u8 reg)83{84 return i2c_smbus_read_byte_data(client, HP206C_CMD_READ_REG | reg);85}86 87static inline int hp206c_write_reg(struct i2c_client *client, u8 reg, u8 val)88{89 return i2c_smbus_write_byte_data(client,90 HP206C_CMD_WRITE_REG | reg, val);91}92 93static int hp206c_read_20bit(struct i2c_client *client, u8 cmd)94{95 int ret;96 u8 values[3];97 98 ret = i2c_smbus_read_i2c_block_data(client, cmd, sizeof(values), values);99 if (ret < 0)100 return ret;101 if (ret != sizeof(values))102 return -EIO;103 return get_unaligned_be24(&values[0]) & GENMASK(19, 0);104}105 106/* Spin for max 160ms until DEV_RDY is 1, or return error. */107static int hp206c_wait_dev_rdy(struct iio_dev *indio_dev)108{109 int ret;110 int count = 0;111 struct hp206c_data *data = iio_priv(indio_dev);112 struct i2c_client *client = data->client;113 114 while (++count <= HP206C_MAX_DEV_RDY_WAIT_COUNT) {115 ret = hp206c_read_reg(client, HP206C_REG_INT_SRC);116 if (ret < 0) {117 dev_err(&indio_dev->dev, "Failed READ_REG INT_SRC: %d\n", ret);118 return ret;119 }120 if (ret & HP206C_FLAG_DEV_RDY)121 return 0;122 usleep_range(HP206C_DEV_RDY_WAIT_US, HP206C_DEV_RDY_WAIT_US * 3 / 2);123 }124 return -ETIMEDOUT;125}126 127static int hp206c_set_compensation(struct i2c_client *client, bool enabled)128{129 int val;130 131 val = hp206c_read_reg(client, HP206C_REG_PARA);132 if (val < 0)133 return val;134 if (enabled)135 val |= HP206C_FLAG_CMPS_EN;136 else137 val &= ~HP206C_FLAG_CMPS_EN;138 139 return hp206c_write_reg(client, HP206C_REG_PARA, val);140}141 142/* Do a soft reset */143static int hp206c_soft_reset(struct iio_dev *indio_dev)144{145 int ret;146 struct hp206c_data *data = iio_priv(indio_dev);147 struct i2c_client *client = data->client;148 149 ret = i2c_smbus_write_byte(client, HP206C_CMD_SOFT_RST);150 if (ret) {151 dev_err(&client->dev, "Failed to reset device: %d\n", ret);152 return ret;153 }154 155 usleep_range(400, 600);156 157 ret = hp206c_wait_dev_rdy(indio_dev);158 if (ret) {159 dev_err(&client->dev, "Device not ready after soft reset: %d\n", ret);160 return ret;161 }162 163 ret = hp206c_set_compensation(client, true);164 if (ret)165 dev_err(&client->dev, "Failed to enable compensation: %d\n", ret);166 return ret;167}168 169static int hp206c_conv_and_read(struct iio_dev *indio_dev,170 u8 conv_cmd, u8 read_cmd,171 unsigned int sleep_us)172{173 int ret;174 struct hp206c_data *data = iio_priv(indio_dev);175 struct i2c_client *client = data->client;176 177 ret = hp206c_wait_dev_rdy(indio_dev);178 if (ret < 0) {179 dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);180 return ret;181 }182 183 ret = i2c_smbus_write_byte(client, conv_cmd);184 if (ret < 0) {185 dev_err(&indio_dev->dev, "Failed convert: %d\n", ret);186 return ret;187 }188 189 usleep_range(sleep_us, sleep_us * 3 / 2);190 191 ret = hp206c_wait_dev_rdy(indio_dev);192 if (ret < 0) {193 dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);194 return ret;195 }196 197 ret = hp206c_read_20bit(client, read_cmd);198 if (ret < 0)199 dev_err(&indio_dev->dev, "Failed read: %d\n", ret);200 201 return ret;202}203 204static int hp206c_read_raw(struct iio_dev *indio_dev,205 struct iio_chan_spec const *chan, int *val,206 int *val2, long mask)207{208 int ret;209 struct hp206c_data *data = iio_priv(indio_dev);210 const struct hp206c_osr_setting *osr_setting;211 u8 conv_cmd;212 213 mutex_lock(&data->mutex);214 215 switch (mask) {216 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:217 switch (chan->type) {218 case IIO_TEMP:219 *val = hp206c_osr_rates[data->temp_osr_index];220 ret = IIO_VAL_INT;221 break;222 223 case IIO_PRESSURE:224 *val = hp206c_osr_rates[data->pres_osr_index];225 ret = IIO_VAL_INT;226 break;227 default:228 ret = -EINVAL;229 }230 break;231 232 case IIO_CHAN_INFO_RAW:233 switch (chan->type) {234 case IIO_TEMP:235 osr_setting = &hp206c_osr_settings[data->temp_osr_index];236 conv_cmd = HP206C_CMD_ADC_CVT |237 osr_setting->osr_mask |238 HP206C_CMD_ADC_CVT_CHNL_T;239 ret = hp206c_conv_and_read(indio_dev,240 conv_cmd,241 HP206C_CMD_READ_T,242 osr_setting->temp_conv_time_us);243 if (ret >= 0) {244 /* 20 significant bits are provided.245 * Extend sign over the rest.246 */247 *val = sign_extend32(ret, 19);248 ret = IIO_VAL_INT;249 }250 break;251 252 case IIO_PRESSURE:253 osr_setting = &hp206c_osr_settings[data->pres_osr_index];254 conv_cmd = HP206C_CMD_ADC_CVT |255 osr_setting->osr_mask |256 HP206C_CMD_ADC_CVT_CHNL_PT;257 ret = hp206c_conv_and_read(indio_dev,258 conv_cmd,259 HP206C_CMD_READ_P,260 osr_setting->pres_conv_time_us);261 if (ret >= 0) {262 *val = ret;263 ret = IIO_VAL_INT;264 }265 break;266 default:267 ret = -EINVAL;268 }269 break;270 271 case IIO_CHAN_INFO_SCALE:272 switch (chan->type) {273 case IIO_TEMP:274 *val = 0;275 *val2 = 10000;276 ret = IIO_VAL_INT_PLUS_MICRO;277 break;278 279 case IIO_PRESSURE:280 *val = 0;281 *val2 = 1000;282 ret = IIO_VAL_INT_PLUS_MICRO;283 break;284 default:285 ret = -EINVAL;286 }287 break;288 289 default:290 ret = -EINVAL;291 }292 293 mutex_unlock(&data->mutex);294 return ret;295}296 297static int hp206c_write_raw(struct iio_dev *indio_dev,298 struct iio_chan_spec const *chan,299 int val, int val2, long mask)300{301 int ret = 0;302 struct hp206c_data *data = iio_priv(indio_dev);303 304 if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)305 return -EINVAL;306 mutex_lock(&data->mutex);307 switch (chan->type) {308 case IIO_TEMP:309 data->temp_osr_index = find_closest_descending(val,310 hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));311 break;312 case IIO_PRESSURE:313 data->pres_osr_index = find_closest_descending(val,314 hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));315 break;316 default:317 ret = -EINVAL;318 }319 mutex_unlock(&data->mutex);320 return ret;321}322 323static const struct iio_chan_spec hp206c_channels[] = {324 {325 .type = IIO_TEMP,326 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |327 BIT(IIO_CHAN_INFO_SCALE) |328 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),329 },330 {331 .type = IIO_PRESSURE,332 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |333 BIT(IIO_CHAN_INFO_SCALE) |334 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),335 }336};337 338static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(hp206c_osr_rates_str);339 340static struct attribute *hp206c_attributes[] = {341 &iio_const_attr_sampling_frequency_available.dev_attr.attr,342 NULL,343};344 345static const struct attribute_group hp206c_attribute_group = {346 .attrs = hp206c_attributes,347};348 349static const struct iio_info hp206c_info = {350 .attrs = &hp206c_attribute_group,351 .read_raw = hp206c_read_raw,352 .write_raw = hp206c_write_raw,353};354 355static int hp206c_probe(struct i2c_client *client)356{357 const struct i2c_device_id *id = i2c_client_get_device_id(client);358 struct iio_dev *indio_dev;359 struct hp206c_data *data;360 int ret;361 362 if (!i2c_check_functionality(client->adapter,363 I2C_FUNC_SMBUS_BYTE |364 I2C_FUNC_SMBUS_BYTE_DATA |365 I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {366 dev_err(&client->dev, "Adapter does not support "367 "all required i2c functionality\n");368 return -ENODEV;369 }370 371 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));372 if (!indio_dev)373 return -ENOMEM;374 375 data = iio_priv(indio_dev);376 data->client = client;377 mutex_init(&data->mutex);378 379 indio_dev->info = &hp206c_info;380 indio_dev->name = id->name;381 indio_dev->modes = INDIO_DIRECT_MODE;382 indio_dev->channels = hp206c_channels;383 indio_dev->num_channels = ARRAY_SIZE(hp206c_channels);384 385 i2c_set_clientdata(client, indio_dev);386 387 /* Do a soft reset on probe */388 ret = hp206c_soft_reset(indio_dev);389 if (ret) {390 dev_err(&client->dev, "Failed to reset on startup: %d\n", ret);391 return -ENODEV;392 }393 394 return devm_iio_device_register(&client->dev, indio_dev);395}396 397static const struct i2c_device_id hp206c_id[] = {398 {"hp206c"},399 {}400};401MODULE_DEVICE_TABLE(i2c, hp206c_id);402 403static const struct acpi_device_id hp206c_acpi_match[] = {404 {"HOP206C", 0},405 { },406};407MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);408 409static struct i2c_driver hp206c_driver = {410 .probe = hp206c_probe,411 .id_table = hp206c_id,412 .driver = {413 .name = "hp206c",414 .acpi_match_table = hp206c_acpi_match,415 },416};417 418module_i2c_driver(hp206c_driver);419 420MODULE_DESCRIPTION("HOPERF HP206C precision barometer and altimeter sensor");421MODULE_AUTHOR("Leonard Crestez <leonard.crestez@intel.com>");422MODULE_LICENSE("GPL v2");423