684 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * STMicroelectronics hts221 sensor driver4 *5 * Copyright 2016 STMicroelectronics Inc.6 *7 * Lorenzo Bianconi <lorenzo.bianconi@st.com>8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/device.h>13#include <linux/iio/sysfs.h>14#include <linux/delay.h>15#include <linux/pm.h>16#include <linux/regmap.h>17#include <linux/regulator/consumer.h>18#include <linux/bitfield.h>19 20#include "hts221.h"21 22#define HTS221_REG_WHOAMI_ADDR 0x0f23#define HTS221_REG_WHOAMI_VAL 0xbc24 25#define HTS221_REG_CNTRL1_ADDR 0x2026#define HTS221_REG_CNTRL2_ADDR 0x2127 28#define HTS221_ODR_MASK 0x0329#define HTS221_BDU_MASK BIT(2)30#define HTS221_ENABLE_MASK BIT(7)31 32/* calibration registers */33#define HTS221_REG_0RH_CAL_X_H 0x3634#define HTS221_REG_1RH_CAL_X_H 0x3a35#define HTS221_REG_0RH_CAL_Y_H 0x3036#define HTS221_REG_1RH_CAL_Y_H 0x3137#define HTS221_REG_0T_CAL_X_L 0x3c38#define HTS221_REG_1T_CAL_X_L 0x3e39#define HTS221_REG_0T_CAL_Y_H 0x3240#define HTS221_REG_1T_CAL_Y_H 0x3341#define HTS221_REG_T1_T0_CAL_Y_H 0x3542 43struct hts221_odr {44 u8 hz;45 u8 val;46};47 48#define HTS221_AVG_DEPTH 849struct hts221_avg {50 u8 addr;51 u8 mask;52 u16 avg_avl[HTS221_AVG_DEPTH];53};54 55static const struct hts221_odr hts221_odr_table[] = {56 { 1, 0x01 }, /* 1Hz */57 { 7, 0x02 }, /* 7Hz */58 { 13, 0x03 }, /* 12.5Hz */59};60 61static const struct hts221_avg hts221_avg_list[] = {62 {63 .addr = 0x10,64 .mask = 0x07,65 .avg_avl = {66 4, /* 0.4 %RH */67 8, /* 0.3 %RH */68 16, /* 0.2 %RH */69 32, /* 0.15 %RH */70 64, /* 0.1 %RH */71 128, /* 0.07 %RH */72 256, /* 0.05 %RH */73 512, /* 0.03 %RH */74 },75 },76 {77 .addr = 0x10,78 .mask = 0x38,79 .avg_avl = {80 2, /* 0.08 degC */81 4, /* 0.05 degC */82 8, /* 0.04 degC */83 16, /* 0.03 degC */84 32, /* 0.02 degC */85 64, /* 0.015 degC */86 128, /* 0.01 degC */87 256, /* 0.007 degC */88 },89 },90};91 92static const struct iio_chan_spec hts221_channels[] = {93 {94 .type = IIO_HUMIDITYRELATIVE,95 .address = 0x28,96 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |97 BIT(IIO_CHAN_INFO_OFFSET) |98 BIT(IIO_CHAN_INFO_SCALE) |99 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),100 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),101 .scan_index = 0,102 .scan_type = {103 .sign = 's',104 .realbits = 16,105 .storagebits = 16,106 .endianness = IIO_LE,107 },108 },109 {110 .type = IIO_TEMP,111 .address = 0x2a,112 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |113 BIT(IIO_CHAN_INFO_OFFSET) |114 BIT(IIO_CHAN_INFO_SCALE) |115 BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),116 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),117 .scan_index = 1,118 .scan_type = {119 .sign = 's',120 .realbits = 16,121 .storagebits = 16,122 .endianness = IIO_LE,123 },124 },125 IIO_CHAN_SOFT_TIMESTAMP(2),126};127 128static int hts221_check_whoami(struct hts221_hw *hw)129{130 int err, data;131 132 err = regmap_read(hw->regmap, HTS221_REG_WHOAMI_ADDR, &data);133 if (err < 0) {134 dev_err(hw->dev, "failed to read whoami register\n");135 return err;136 }137 138 if (data != HTS221_REG_WHOAMI_VAL) {139 dev_err(hw->dev, "wrong whoami {%02x vs %02x}\n",140 data, HTS221_REG_WHOAMI_VAL);141 return -ENODEV;142 }143 144 return 0;145}146 147static int hts221_update_odr(struct hts221_hw *hw, u8 odr)148{149 int i, err;150 151 for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)152 if (hts221_odr_table[i].hz == odr)153 break;154 155 if (i == ARRAY_SIZE(hts221_odr_table))156 return -EINVAL;157 158 err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,159 HTS221_ODR_MASK,160 FIELD_PREP(HTS221_ODR_MASK,161 hts221_odr_table[i].val));162 if (err < 0)163 return err;164 165 hw->odr = odr;166 167 return 0;168}169 170static int hts221_update_avg(struct hts221_hw *hw,171 enum hts221_sensor_type type,172 u16 val)173{174 const struct hts221_avg *avg = &hts221_avg_list[type];175 int i, err, data;176 177 for (i = 0; i < HTS221_AVG_DEPTH; i++)178 if (avg->avg_avl[i] == val)179 break;180 181 if (i == HTS221_AVG_DEPTH)182 return -EINVAL;183 184 data = ((i << __ffs(avg->mask)) & avg->mask);185 err = regmap_update_bits(hw->regmap, avg->addr,186 avg->mask, data);187 if (err < 0)188 return err;189 190 hw->sensors[type].cur_avg_idx = i;191 192 return 0;193}194 195static ssize_t hts221_sysfs_sampling_freq(struct device *dev,196 struct device_attribute *attr,197 char *buf)198{199 int i;200 ssize_t len = 0;201 202 for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)203 len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",204 hts221_odr_table[i].hz);205 buf[len - 1] = '\n';206 207 return len;208}209 210static ssize_t211hts221_sysfs_rh_oversampling_avail(struct device *dev,212 struct device_attribute *attr,213 char *buf)214{215 const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_H];216 ssize_t len = 0;217 int i;218 219 for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)220 len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",221 avg->avg_avl[i]);222 buf[len - 1] = '\n';223 224 return len;225}226 227static ssize_t228hts221_sysfs_temp_oversampling_avail(struct device *dev,229 struct device_attribute *attr,230 char *buf)231{232 const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_T];233 ssize_t len = 0;234 int i;235 236 for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)237 len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",238 avg->avg_avl[i]);239 buf[len - 1] = '\n';240 241 return len;242}243 244int hts221_set_enable(struct hts221_hw *hw, bool enable)245{246 int err;247 248 err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,249 HTS221_ENABLE_MASK,250 FIELD_PREP(HTS221_ENABLE_MASK, enable));251 if (err < 0)252 return err;253 254 hw->enabled = enable;255 256 return 0;257}258 259static int hts221_parse_temp_caldata(struct hts221_hw *hw)260{261 int err, *slope, *b_gen, cal0, cal1;262 s16 cal_x0, cal_x1, cal_y0, cal_y1;263 __le16 val;264 265 err = regmap_read(hw->regmap, HTS221_REG_0T_CAL_Y_H, &cal0);266 if (err < 0)267 return err;268 269 err = regmap_read(hw->regmap, HTS221_REG_T1_T0_CAL_Y_H, &cal1);270 if (err < 0)271 return err;272 cal_y0 = ((cal1 & 0x3) << 8) | cal0;273 274 err = regmap_read(hw->regmap, HTS221_REG_1T_CAL_Y_H, &cal0);275 if (err < 0)276 return err;277 cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0;278 279 err = regmap_bulk_read(hw->regmap, HTS221_REG_0T_CAL_X_L,280 &val, sizeof(val));281 if (err < 0)282 return err;283 cal_x0 = le16_to_cpu(val);284 285 err = regmap_bulk_read(hw->regmap, HTS221_REG_1T_CAL_X_L,286 &val, sizeof(val));287 if (err < 0)288 return err;289 cal_x1 = le16_to_cpu(val);290 291 slope = &hw->sensors[HTS221_SENSOR_T].slope;292 b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen;293 294 *slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0);295 *b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) /296 (cal_x1 - cal_x0);297 *b_gen *= 8;298 299 return 0;300}301 302static int hts221_parse_rh_caldata(struct hts221_hw *hw)303{304 int err, *slope, *b_gen, data;305 s16 cal_x0, cal_x1, cal_y0, cal_y1;306 __le16 val;307 308 err = regmap_read(hw->regmap, HTS221_REG_0RH_CAL_Y_H, &data);309 if (err < 0)310 return err;311 cal_y0 = data;312 313 err = regmap_read(hw->regmap, HTS221_REG_1RH_CAL_Y_H, &data);314 if (err < 0)315 return err;316 cal_y1 = data;317 318 err = regmap_bulk_read(hw->regmap, HTS221_REG_0RH_CAL_X_H,319 &val, sizeof(val));320 if (err < 0)321 return err;322 cal_x0 = le16_to_cpu(val);323 324 err = regmap_bulk_read(hw->regmap, HTS221_REG_1RH_CAL_X_H,325 &val, sizeof(val));326 if (err < 0)327 return err;328 cal_x1 = le16_to_cpu(val);329 330 slope = &hw->sensors[HTS221_SENSOR_H].slope;331 b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen;332 333 *slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0);334 *b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) /335 (cal_x1 - cal_x0);336 *b_gen *= 8;337 338 return 0;339}340 341static int hts221_get_sensor_scale(struct hts221_hw *hw,342 enum iio_chan_type ch_type,343 int *val, int *val2)344{345 s64 tmp;346 s32 rem, div, data;347 348 switch (ch_type) {349 case IIO_HUMIDITYRELATIVE:350 data = hw->sensors[HTS221_SENSOR_H].slope;351 div = (1 << 4) * 1000;352 break;353 case IIO_TEMP:354 data = hw->sensors[HTS221_SENSOR_T].slope;355 div = (1 << 6) * 1000;356 break;357 default:358 return -EINVAL;359 }360 361 tmp = div_s64(data * 1000000000LL, div);362 tmp = div_s64_rem(tmp, 1000000000LL, &rem);363 364 *val = tmp;365 *val2 = rem;366 367 return IIO_VAL_INT_PLUS_NANO;368}369 370static int hts221_get_sensor_offset(struct hts221_hw *hw,371 enum iio_chan_type ch_type,372 int *val, int *val2)373{374 s64 tmp;375 s32 rem, div, data;376 377 switch (ch_type) {378 case IIO_HUMIDITYRELATIVE:379 data = hw->sensors[HTS221_SENSOR_H].b_gen;380 div = hw->sensors[HTS221_SENSOR_H].slope;381 break;382 case IIO_TEMP:383 data = hw->sensors[HTS221_SENSOR_T].b_gen;384 div = hw->sensors[HTS221_SENSOR_T].slope;385 break;386 default:387 return -EINVAL;388 }389 390 tmp = div_s64(data * 1000000000LL, div);391 tmp = div_s64_rem(tmp, 1000000000LL, &rem);392 393 *val = tmp;394 *val2 = rem;395 396 return IIO_VAL_INT_PLUS_NANO;397}398 399static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)400{401 __le16 data;402 int err;403 404 err = hts221_set_enable(hw, true);405 if (err < 0)406 return err;407 408 msleep(50);409 410 err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data));411 if (err < 0)412 return err;413 414 hts221_set_enable(hw, false);415 416 *val = (s16)le16_to_cpu(data);417 418 return IIO_VAL_INT;419}420 421static int hts221_read_raw(struct iio_dev *iio_dev,422 struct iio_chan_spec const *ch,423 int *val, int *val2, long mask)424{425 struct hts221_hw *hw = iio_priv(iio_dev);426 int ret;427 428 ret = iio_device_claim_direct_mode(iio_dev);429 if (ret)430 return ret;431 432 switch (mask) {433 case IIO_CHAN_INFO_RAW:434 ret = hts221_read_oneshot(hw, ch->address, val);435 break;436 case IIO_CHAN_INFO_SCALE:437 ret = hts221_get_sensor_scale(hw, ch->type, val, val2);438 break;439 case IIO_CHAN_INFO_OFFSET:440 ret = hts221_get_sensor_offset(hw, ch->type, val, val2);441 break;442 case IIO_CHAN_INFO_SAMP_FREQ:443 *val = hw->odr;444 ret = IIO_VAL_INT;445 break;446 case IIO_CHAN_INFO_OVERSAMPLING_RATIO: {447 u8 idx;448 const struct hts221_avg *avg;449 450 switch (ch->type) {451 case IIO_HUMIDITYRELATIVE:452 avg = &hts221_avg_list[HTS221_SENSOR_H];453 idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx;454 *val = avg->avg_avl[idx];455 ret = IIO_VAL_INT;456 break;457 case IIO_TEMP:458 avg = &hts221_avg_list[HTS221_SENSOR_T];459 idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx;460 *val = avg->avg_avl[idx];461 ret = IIO_VAL_INT;462 break;463 default:464 ret = -EINVAL;465 break;466 }467 break;468 }469 default:470 ret = -EINVAL;471 break;472 }473 474 iio_device_release_direct_mode(iio_dev);475 476 return ret;477}478 479static int hts221_write_raw(struct iio_dev *iio_dev,480 struct iio_chan_spec const *chan,481 int val, int val2, long mask)482{483 struct hts221_hw *hw = iio_priv(iio_dev);484 int ret;485 486 ret = iio_device_claim_direct_mode(iio_dev);487 if (ret)488 return ret;489 490 switch (mask) {491 case IIO_CHAN_INFO_SAMP_FREQ:492 ret = hts221_update_odr(hw, val);493 break;494 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:495 switch (chan->type) {496 case IIO_HUMIDITYRELATIVE:497 ret = hts221_update_avg(hw, HTS221_SENSOR_H, val);498 break;499 case IIO_TEMP:500 ret = hts221_update_avg(hw, HTS221_SENSOR_T, val);501 break;502 default:503 ret = -EINVAL;504 break;505 }506 break;507 default:508 ret = -EINVAL;509 break;510 }511 512 iio_device_release_direct_mode(iio_dev);513 514 return ret;515}516 517static int hts221_validate_trigger(struct iio_dev *iio_dev,518 struct iio_trigger *trig)519{520 struct hts221_hw *hw = iio_priv(iio_dev);521 522 return hw->trig == trig ? 0 : -EINVAL;523}524 525static IIO_DEVICE_ATTR(in_humidity_oversampling_ratio_available, S_IRUGO,526 hts221_sysfs_rh_oversampling_avail, NULL, 0);527static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, S_IRUGO,528 hts221_sysfs_temp_oversampling_avail, NULL, 0);529static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hts221_sysfs_sampling_freq);530 531static struct attribute *hts221_attributes[] = {532 &iio_dev_attr_sampling_frequency_available.dev_attr.attr,533 &iio_dev_attr_in_humidity_oversampling_ratio_available.dev_attr.attr,534 &iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr,535 NULL,536};537 538static const struct attribute_group hts221_attribute_group = {539 .attrs = hts221_attributes,540};541 542static const struct iio_info hts221_info = {543 .attrs = &hts221_attribute_group,544 .read_raw = hts221_read_raw,545 .write_raw = hts221_write_raw,546 .validate_trigger = hts221_validate_trigger,547};548 549static const unsigned long hts221_scan_masks[] = {0x3, 0x0};550 551static int hts221_init_regulators(struct device *dev)552{553 int err;554 555 err = devm_regulator_get_enable(dev, "vdd");556 if (err)557 return dev_err_probe(dev, err, "failed to get vdd regulator\n");558 559 msleep(50);560 561 return 0;562}563 564int hts221_probe(struct device *dev, int irq, const char *name,565 struct regmap *regmap)566{567 struct iio_dev *iio_dev;568 struct hts221_hw *hw;569 int err;570 u8 data;571 572 iio_dev = devm_iio_device_alloc(dev, sizeof(*hw));573 if (!iio_dev)574 return -ENOMEM;575 576 dev_set_drvdata(dev, iio_dev);577 578 hw = iio_priv(iio_dev);579 hw->name = name;580 hw->dev = dev;581 hw->irq = irq;582 hw->regmap = regmap;583 584 err = hts221_init_regulators(dev);585 if (err)586 return err;587 588 err = hts221_check_whoami(hw);589 if (err < 0)590 return err;591 592 iio_dev->modes = INDIO_DIRECT_MODE;593 iio_dev->available_scan_masks = hts221_scan_masks;594 iio_dev->channels = hts221_channels;595 iio_dev->num_channels = ARRAY_SIZE(hts221_channels);596 iio_dev->name = HTS221_DEV_NAME;597 iio_dev->info = &hts221_info;598 599 /* enable Block Data Update */600 err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,601 HTS221_BDU_MASK,602 FIELD_PREP(HTS221_BDU_MASK, 1));603 if (err < 0)604 return err;605 606 err = hts221_update_odr(hw, hts221_odr_table[0].hz);607 if (err < 0)608 return err;609 610 /* configure humidity sensor */611 err = hts221_parse_rh_caldata(hw);612 if (err < 0) {613 dev_err(hw->dev, "failed to get rh calibration data\n");614 return err;615 }616 617 data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3];618 err = hts221_update_avg(hw, HTS221_SENSOR_H, data);619 if (err < 0) {620 dev_err(hw->dev, "failed to set rh oversampling ratio\n");621 return err;622 }623 624 /* configure temperature sensor */625 err = hts221_parse_temp_caldata(hw);626 if (err < 0) {627 dev_err(hw->dev,628 "failed to get temperature calibration data\n");629 return err;630 }631 632 data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3];633 err = hts221_update_avg(hw, HTS221_SENSOR_T, data);634 if (err < 0) {635 dev_err(hw->dev,636 "failed to set temperature oversampling ratio\n");637 return err;638 }639 640 if (hw->irq > 0) {641 err = hts221_allocate_buffers(iio_dev);642 if (err < 0)643 return err;644 645 err = hts221_allocate_trigger(iio_dev);646 if (err)647 return err;648 }649 650 return devm_iio_device_register(hw->dev, iio_dev);651}652EXPORT_SYMBOL_NS(hts221_probe, IIO_HTS221);653 654static int hts221_suspend(struct device *dev)655{656 struct iio_dev *iio_dev = dev_get_drvdata(dev);657 struct hts221_hw *hw = iio_priv(iio_dev);658 659 return regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,660 HTS221_ENABLE_MASK,661 FIELD_PREP(HTS221_ENABLE_MASK, false));662}663 664static int hts221_resume(struct device *dev)665{666 struct iio_dev *iio_dev = dev_get_drvdata(dev);667 struct hts221_hw *hw = iio_priv(iio_dev);668 int err = 0;669 670 if (hw->enabled)671 err = regmap_update_bits(hw->regmap, HTS221_REG_CNTRL1_ADDR,672 HTS221_ENABLE_MASK,673 FIELD_PREP(HTS221_ENABLE_MASK,674 true));675 return err;676}677 678EXPORT_NS_SIMPLE_DEV_PM_OPS(hts221_pm_ops, hts221_suspend, hts221_resume,679 IIO_HTS221);680 681MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");682MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver");683MODULE_LICENSE("GPL v2");684