This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 1b8db1992e4 !sensors/hts221: Replace the legacy driver with a uORB 
driver.
1b8db1992e4 is described below

commit 1b8db1992e406d59e0a171cdbab8c5729dde61ca
Author: raiden00pl <[email protected]>
AuthorDate: Mon May 5 16:25:42 2025 +0200

    !sensors/hts221: Replace the legacy driver with a uORB driver.
    
    BREAKING CHANGE: the legacy HTS221 character driver is removed, use
    hts221_register_uorb() instead.
    
    Assisted-by: Claude:claude-fable-5-1
    Signed-off-by: raiden00pl <[email protected]>
---
 Documentation/os/drivers/special/sensors.rst       |    1 +
 .../os/drivers/special/sensors/hts221.rst          |   28 +
 .../os/drivers/special/sensors/sensors_legacy.rst  |    1 -
 .../os/drivers/special/sensors/sensors_uorb.rst    |    1 +
 boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h     |    2 +-
 boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c   |    2 +-
 boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c    |   38 +-
 .../olimex-stm32-p407/configs/mqttc/defconfig      |    1 -
 drivers/sensors/CMakeLists.txt                     |    2 +-
 drivers/sensors/Kconfig                            |   13 +-
 drivers/sensors/Make.defs                          |    2 +-
 drivers/sensors/hts221.c                           | 1220 --------------------
 drivers/sensors/hts221_uorb.c                      | 1216 +++++++++++++++++++
 include/nuttx/sensors/hts221.h                     |  124 +-
 14 files changed, 1289 insertions(+), 1362 deletions(-)

diff --git a/Documentation/os/drivers/special/sensors.rst 
b/Documentation/os/drivers/special/sensors.rst
index a2a695fd0d7..52046f59f8a 100644
--- a/Documentation/os/drivers/special/sensors.rst
+++ b/Documentation/os/drivers/special/sensors.rst
@@ -49,3 +49,4 @@ tool for monitoring sensor activity at runtime.
     sensors/gnss_lowerhalf.rst
     sensors/bh1745nuc.rst
     sensors/lps22hb.rst
+    sensors/hts221.rst
diff --git a/Documentation/os/drivers/special/sensors/hts221.rst 
b/Documentation/os/drivers/special/sensors/hts221.rst
new file mode 100644
index 00000000000..288cd35ba12
--- /dev/null
+++ b/Documentation/os/drivers/special/sensors/hts221.rst
@@ -0,0 +1,28 @@
+======
+HTS221
+======
+
+STMicroelectronics HTS221 humidity and temperature sensor on I2C,
+:doc:`uORB </os/drivers/special/sensors/sensors_uorb>` interface.
+
+Configuration
+=============
+
+- ``CONFIG_SENSORS_HTS221``
+- ``CONFIG_HTS221_I2C_FREQUENCY``
+
+Usage
+=====
+
+.. code-block:: c
+
+   #include <nuttx/sensors/hts221.h>
+
+   int hts221_register_uorb(int devno, FAR struct i2c_master_s *i2c,
+                            uint8_t addr, FAR hts221_config_t *config);
+
+Registers ``sensor_ambient_temp<devno>`` (°C) and ``sensor_humi<devno>``
+(%rH). ``config`` holds the optional data-ready interrupt and power
+callbacks; with the interrupt the interval selects the 1, 7 or 12.5 Hz
+output data rate, without it the sensor is polled in one-shot mode.
+``SNIOC_OVERSAMPLING`` sets the number of averaged samples per topic.
diff --git a/Documentation/os/drivers/special/sensors/sensors_legacy.rst 
b/Documentation/os/drivers/special/sensors/sensors_legacy.rst
index 44a920d889d..91719d3df55 100644
--- a/Documentation/os/drivers/special/sensors/sensors_legacy.rst
+++ b/Documentation/os/drivers/special/sensors/sensors_legacy.rst
@@ -35,7 +35,6 @@ Drivers that are available also with the new sensor framework 
are marked with ``
 - hall3ph
 - hc_sr04
 - hdc1008
-- hts221
 - ina219
 - ina226
 - ina3221
diff --git a/Documentation/os/drivers/special/sensors/sensors_uorb.rst 
b/Documentation/os/drivers/special/sensors/sensors_uorb.rst
index 446302ff216..2f7630e1492 100644
--- a/Documentation/os/drivers/special/sensors/sensors_uorb.rst
+++ b/Documentation/os/drivers/special/sensors/sensors_uorb.rst
@@ -559,6 +559,7 @@ Implemented Drivers
 - gnss
 - goldfish_gnss
 - goldfish_sensor
+- :doc:`hts221`
 - hyt271
 - l3gd20
 - :doc:`lis2mdl`
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h 
b/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
index bbb3d58430c..35877761b1a 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
@@ -149,7 +149,7 @@ int nrf52_lsm303agr_initialize(char *devpath);
  ****************************************************************************/
 
 #ifdef CONFIG_SENSORS_HTS221
-int nrf52_hts221_initialize(char *devpath);
+int nrf52_hts221_initialize(int devno);
 #endif
 
 /****************************************************************************
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c 
b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
index 0a6ae05d9bc..e43d87ab134 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
@@ -210,7 +210,7 @@ int nrf52_bringup(void)
 #endif /* CONFIG_SENSORS_LSM303AGR */
 
 #ifdef CONFIG_SENSORS_HTS221
-  ret = nrf52_hts221_initialize("/dev/hts2210");
+  ret = nrf52_hts221_initialize(0);
   if (ret < 0)
     {
       syslog(LOG_ERR,
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c 
b/boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c
index a621d1cf1e0..ee7c04a18fd 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c
@@ -51,8 +51,6 @@
  * Private Function Prototypes
  ****************************************************************************/
 
-static int nrf52_hts221_irq_attach(struct hts221_config_s *state,
-                                   xcpt_t isr, void *arg);
 static void nrf52_hts221_irq_enable(const struct hts221_config_s *state,
                                     bool enable);
 static void nrf52_hts221_irq_clear(const struct hts221_config_s *state);
@@ -65,7 +63,7 @@ static int nrf52_hts221_set_power(const struct 
hts221_config_s *state,
 
 static hts221_config_t g_hts221_config =
 {
-  .irq_attach = nrf52_hts221_irq_attach,
+  .irq_attach = NULL,   /* DRDY not wired, the driver polls */
   .irq_enable = nrf52_hts221_irq_enable,
   .irq_clear  = nrf52_hts221_irq_clear,
   .set_power  = nrf52_hts221_set_power
@@ -75,22 +73,6 @@ static hts221_config_t g_hts221_config =
  * Private Functions
  ****************************************************************************/
 
-/****************************************************************************
- * Name: nrf52_hts221_irq_attach
- ****************************************************************************/
-
-static int nrf52_hts221_irq_attach(struct hts221_config_s *state,
-                                   xcpt_t isr, void *arg)
-{
-  sinfo("Attach HTS221 IRQ\n");
-
-  /* TODO: IRQ on rising edge */
-
-  /* nrf52_gpiosetevent(GPIO_HTS221_IRQ, true, false, false, isr, arg); */
-
-  return OK;
-}
-
 /****************************************************************************
  * Name: nrf52_hts221_irq_enable
  ****************************************************************************/
@@ -130,32 +112,30 @@ static int nrf52_hts221_set_power(const struct 
hts221_config_s *state,
  *
  ****************************************************************************/
 
-int nrf52_hts221_initialize(char *devpath)
+int nrf52_hts221_initialize(int devno)
 {
   struct i2c_master_s *i2c;
-  int ret = OK;
+  int ret;
 
   sninfo("Initializing HTS221!\n");
 
-#ifdef CONFIG_NRF52_I2C0_MASTER
   i2c = nrf52_i2cbus_initialize(0);
   if (i2c == NULL)
     {
       return -ENODEV;
     }
 
-  sninfo("INFO: Initializing HTS221 hum-temp sensor over I2C%d\n", ret);
+  sninfo("INFO: Initializing HTS221 hum-temp sensor over I2C0\n");
 
-  ret = hts221_register(devpath, i2c, HTS221HUM_ADDR, &g_hts221_config);
+  ret = hts221_register_uorb(devno, i2c, HTS221HUM_ADDR, &g_hts221_config);
   if (ret < 0)
     {
-      snerr("ERROR: Failed to initialize HTS221 hum-temp driver %s\n",
-            devpath);
-      return -ENODEV;
+      snerr("ERROR: Failed to initialize HTS221 hum-temp driver: %d\n",
+            ret);
+      return ret;
     }
 
   sninfo("INFO: HTS221 sensor has been initialized successfully\n");
-#endif
 
-  return ret;
+  return OK;
 }
diff --git a/boards/arm/stm32f4/olimex-stm32-p407/configs/mqttc/defconfig 
b/boards/arm/stm32f4/olimex-stm32-p407/configs/mqttc/defconfig
index 6dc5ccbb18b..f2acbb04e7a 100644
--- a/boards/arm/stm32f4/olimex-stm32-p407/configs/mqttc/defconfig
+++ b/boards/arm/stm32f4/olimex-stm32-p407/configs/mqttc/defconfig
@@ -26,7 +26,6 @@ CONFIG_FS_FAT=y
 CONFIG_FS_PROCFS=y
 CONFIG_HAVE_CXX=y
 CONFIG_HAVE_CXXINITIALIZE=y
-CONFIG_HTS221_DEBUG=y
 CONFIG_INIT_ENTRYPOINT="nsh_main"
 CONFIG_INTELHEX_BINARY=y
 CONFIG_LIBM=y
diff --git a/drivers/sensors/CMakeLists.txt b/drivers/sensors/CMakeLists.txt
index e062a53e9d7..ac9e8088092 100644
--- a/drivers/sensors/CMakeLists.txt
+++ b/drivers/sensors/CMakeLists.txt
@@ -249,7 +249,7 @@ if(CONFIG_SENSORS)
     endif()
 
     if(CONFIG_SENSORS_HTS221)
-      list(APPEND SRCS hts221.c)
+      list(APPEND SRCS hts221_uorb.c)
     endif()
 
     if(CONFIG_SENSORS_LIS2MDL)
diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index 786ea1e0a06..6cfd31c83d3 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -866,6 +866,7 @@ config SENSORS_HTS221
        bool "STMicro HTS221 humidity sensor"
        default n
        select I2C
+       select SCHED_LPWORK
        ---help---
                Enable driver support for the STMicro HTS221 humidity sensor.
 
@@ -876,18 +877,6 @@ config HTS221_I2C_FREQUENCY
        default 400000
        range 1 400000
 
-config HTS221_DEBUG
-       bool "Debug support for the HTS221"
-       default n
-       ---help---
-               Enables debug features for the HTS221
-
-config HTS221_NPOLLWAITERS
-       int "Number of waiters to poll"
-       default 1
-       ---help---
-               Number of waiters to poll
-
 endif # SENSORS_HTS221
 
 config SENSORS_L3GD20
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index e643938382e..fc230481f4b 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -243,7 +243,7 @@ ifeq ($(CONFIG_SENSORS_ISL29023),y)
 endif
 
 ifeq ($(CONFIG_SENSORS_HTS221),y)
-  CSRCS += hts221.c
+  CSRCS += hts221_uorb.c
 endif
 
 ifeq ($(CONFIG_SENSORS_LIS2MDL),y)
diff --git a/drivers/sensors/hts221.c b/drivers/sensors/hts221.c
deleted file mode 100644
index 4da88fa26d2..00000000000
--- a/drivers/sensors/hts221.c
+++ /dev/null
@@ -1,1220 +0,0 @@
-/****************************************************************************
- * drivers/sensors/hts221.c
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.  The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
-
-/* WARNING for developers:
- *
- * This driver uses the legacy style of writing sensor drivers for NuttX. The
- * project has since decided to adopt a new sensor framework in order to
- * have a consistent API and feature-set.
- *
- * Sensors which use the uORB framework are typically suffixed "_uorb". You
- * can also visit the documentation about the new sensor framework to learn
- * more.
- */
-
-#warning "This is a deprecated legacy sensor driver."
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <assert.h>
-#include <nuttx/debug.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <errno.h>
-
-#include <nuttx/arch.h>
-#include <nuttx/fs/fs.h>
-#include <nuttx/i2c/i2c_master.h>
-#include <nuttx/irq.h>
-#include <nuttx/kmalloc.h>
-#include <nuttx/mutex.h>
-#include <nuttx/poll.h>
-#include <nuttx/signal.h>
-#include <nuttx/random.h>
-
-#include <nuttx/sensors/hts221.h>
-
-/****************************************************************************
- * Pre-Processor Definitions
- ****************************************************************************/
-
-#ifdef CONFIG_HTS221_DEBUG
-#  define hts221_dbg(x, ...)    _info(x, ##__VA_ARGS__)
-#else
-#  define hts221_dbg(x, ...)    sninfo(x, ##__VA_ARGS__)
-#endif
-
-#define HTS221_WHO_AM_I             0x0f
-#define HTS221_AV_CONF              0x10
-#define HTS221_CTRL_REG1            0x20
-#define HTS221_CTRL_REG2            0x21
-#define HTS221_CTRL_REG3            0x22
-#define HTS221_STATUS_REG           0x27
-#define HTS221_HUM_OUT_L            0x28
-#define HTS221_HUM_OUT_H            0x29
-#define HTS221_TEMP_OUT_L           0x2a
-#define HTS221_TEMP_OUT_H           0x2b
-
-/* Calibration registers */
-
-#define HTS221_CALIB_H0_RH_X2       0x30
-#define HTS221_CALIB_H1_RH_X2       0x31
-#define HTS221_CALIB_T0_DEGC_X8     0x32
-#define HTS221_CALIB_T1_DEGC_X8     0x33
-#define HTS221_CALIB_T1_T0_MSB      0x35
-#define HTS221_CALIB_H0T0_OUT_L     0x36
-#define HTS221_CALIB_H0T0_OUT_H     0x37
-#define HTS221_CALIB_H1T0_OUT_L     0x3a
-#define HTS221_CALIB_H1T0_OUT_H     0x3b
-#define HTS221_CALIB_T0_OUT_L       0x3c
-#define HTS221_CALIB_T0_OUT_H       0x3d
-#define HTS221_CALIB_T1_OUT_L       0x3e
-#define HTS221_CALIB_T1_OUT_H       0x3f
-
-/* HTS221_CTRL_REG1 */
-
-#define HTS221_CTRL_REG1_PD         (1 << 7)
-#define HTS221_CTRL_REG1_BDU        (1 << 2)
-
-/* HTS221_CTRL_REG2 */
-
-#define HTS221_CTRL_REG2_BOOT       (1 << 7)
-#define HTS221_CTRL_REG2_ONE_SHOT   (1 << 0)
-
-/* HTS221_CTRL_REG3 */
-
-#define HTS221_CTRL_REG3_DRDY_L_H   (1 << 7)
-#define HTS221_CTRL_REG3_PP_OD      (1 << 6)
-#define HTS221_CTRL_REG3_DRDY_EN    (1 << 2)
-
-/* HTS221_STATUS_REG */
-
-#define HTS221_STATUS_REG_H_DA      (1 << 1)
-#define HTS221_STATUS_REG_T_DA      (1 << 0)
-
-#define HTS221_I2C_RETRIES          10
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-static int hts221_open(FAR struct file *filep);
-static int hts221_close(FAR struct file *filep);
-static ssize_t hts221_read(FAR struct file *filep, FAR char *buffer,
-                           size_t buflen);
-static ssize_t hts221_write(FAR struct file *filep, FAR const char *buffer,
-                            size_t buflen);
-static int hts221_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
-static int hts221_poll(FAR struct file *filep, FAR struct pollfd_s *fds,
-                       bool setup);
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-struct hts221_dev_s
-{
-  FAR struct i2c_master_s *i2c;
-  uint8_t addr;
-  FAR hts221_config_t *config;
-  mutex_t devlock;
-  volatile bool int_pending;
-  FAR struct pollfd_s *fds[CONFIG_HTS221_NPOLLWAITERS];
-  struct
-  {
-    int16_t t0_out;
-    int16_t t1_out;
-    int16_t h0_t0_out;
-    int16_t h1_t0_out;
-    unsigned int t0_x8:10;
-    unsigned int t1_x8:10;
-    uint8_t h0_x2;
-    uint8_t h1_x2;
-  } calib;
-};
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-static const struct file_operations g_humidityops =
-{
-  hts221_open,   /* open */
-  hts221_close,  /* close */
-  hts221_read,   /* read */
-  hts221_write,  /* write */
-  NULL,          /* seek */
-  hts221_ioctl,  /* ioctl */
-  NULL,          /* mmap */
-  NULL,          /* truncate */
-  hts221_poll    /* poll */
-};
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-static int hts221_do_transfer(FAR struct hts221_dev_s *priv,
-                              FAR struct i2c_msg_s *msgv,
-                              size_t nmsg)
-{
-  int ret = -EIO;
-  int retries;
-
-  for (retries = 0; retries < HTS221_I2C_RETRIES; retries++)
-    {
-      ret = I2C_TRANSFER(priv->i2c, msgv, nmsg);
-      if (ret >= 0)
-        {
-          return 0;
-        }
-      else
-        {
-          /* Some error. Try to reset I2C bus and keep trying. */
-
-#ifdef CONFIG_I2C_RESET
-          if (retries == HTS221_I2C_RETRIES - 1)
-            {
-              break;
-            }
-
-          ret = I2C_RESET(priv->i2c);
-          if (ret < 0)
-            {
-              hts221_dbg("I2C_RESET failed: %d\n", ret);
-              return ret;
-            }
-#endif
-        }
-    }
-
-  hts221_dbg("xfer failed: %d\n", ret);
-  return ret;
-}
-
-static int32_t hts221_write_reg8(FAR struct hts221_dev_s *priv,
-                                 const uint8_t *command)
-{
-  struct i2c_msg_s msgv[2] =
-  {
-    {
-      .frequency = CONFIG_HTS221_I2C_FREQUENCY,
-      .addr      = priv->addr,
-      .flags     = 0,
-      .buffer    = (FAR void *)&command[0],
-      .length    = 1
-    },
-    {
-      .frequency = CONFIG_HTS221_I2C_FREQUENCY,
-      .addr      = priv->addr,
-      .flags     = I2C_M_NOSTART,
-      .buffer    = (FAR void *)&command[1],
-      .length    = 1
-    }
-  };
-
-  return hts221_do_transfer(priv, msgv, 2);
-}
-
-static int hts221_read_reg(FAR struct hts221_dev_s *priv,
-                           FAR const uint8_t *command, FAR uint8_t *value)
-{
-  struct i2c_msg_s msgv[2] =
-  {
-    {
-      .frequency = CONFIG_HTS221_I2C_FREQUENCY,
-      .addr      = priv->addr,
-      .flags     = 0,
-      .buffer    = (FAR void *)command,
-      .length    = 1
-    },
-    {
-      .frequency = CONFIG_HTS221_I2C_FREQUENCY,
-      .addr      = priv->addr,
-      .flags     = I2C_M_READ,
-      .buffer    = value,
-      .length    = 1
-    }
-  };
-
-  return hts221_do_transfer(priv, msgv, 2);
-}
-
-static int hts221_get_id(FAR struct hts221_dev_s *priv, uint8_t *value)
-{
-  int ret = OK;
-  uint8_t cmd = HTS221_WHO_AM_I;
-
-  ret = hts221_read_reg(priv, &cmd, value);
-
-  hts221_dbg("Who am I request: 0x%02X\n", *value);
-
-  return ret;
-}
-
-static int hts221_cfgr_resolution(FAR struct hts221_dev_s *priv,
-                                  FAR hts221_settings_t *settings)
-{
-  int ret;
-  uint8_t value;
-  const uint8_t addr = HTS221_AV_CONF;
-  uint8_t regval = 0;
-  uint8_t cmd[2] =
-  {
-    0
-  };
-
-  const uint8_t mask = 0x3f;
-
-  ret = hts221_read_reg(priv, &addr, &regval);
-  hts221_dbg("Default resolution: 0x%02X\n", regval);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  value   = (uint8_t)settings->humid_resol |
-            ((uint8_t)settings->temp_resol << 3);
-  regval &= ~mask;
-  cmd[0]  = addr;
-  cmd[1]  = regval | value;
-  hts221_dbg("New resolution: 0x%02X\n", cmd[1]);
-
-  ret = hts221_write_reg8(priv, cmd);
-
-  hts221_dbg("Resolution changed: temp=%d humid=%d ret=%d\n",
-               settings->temp_resol, settings->humid_resol, ret);
-
-  return ret;
-}
-
-static int hts221_config_ctrl_reg3(FAR struct hts221_dev_s *priv,
-                                   FAR hts221_settings_t *settings)
-{
-  int ret = OK;
-  uint8_t regval = 0;
-  uint8_t addr = HTS221_CTRL_REG3;
-  const uint8_t mask = 0xc4;
-  uint8_t data_to_write[2] =
-  {
-    0
-  };
-
-  ret = hts221_read_reg(priv, &addr, &regval);
-  hts221_dbg("CTRL_REG%d: 0x%02X\n", 3, regval);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  regval &= ~mask;
-  regval |= (uint8_t)(settings->is_high_edge ?
-                      0 : HTS221_CTRL_REG3_DRDY_L_H);
-  regval |= (uint8_t)(settings->is_open_drain ? HTS221_CTRL_REG3_PP_OD : 0);
-  regval |= (uint8_t)(settings->is_data_rdy ? HTS221_CTRL_REG3_DRDY_EN : 0);
-
-  data_to_write[0] = addr;
-  data_to_write[1] = regval;
-
-  ret = hts221_write_reg8(priv, data_to_write);
-  if (ret >= 0)
-    {
-      ret = hts221_read_reg(priv, &addr, &regval);
-      if (ret >= 0)
-        {
-          hts221_dbg("wrote 0x%02X => CTRL_REG%d: 0x%02X\n",
-                     data_to_write[1], 3, regval);
-        }
-    }
-
-  return ret;
-}
-
-static int hts221_config_ctrl_reg2(FAR struct hts221_dev_s *priv,
-                                   FAR hts221_settings_t *settings)
-{
-  int ret = OK;
-  uint8_t regval = 0;
-  uint8_t addr = HTS221_CTRL_REG2;
-  const uint8_t mask = 0x80;
-  uint8_t data_to_write[2] =
-  {
-    0
-  };
-
-  int retries = 5;
-
-  if (!settings->is_boot)
-    {
-      return OK;
-    }
-
-  ret = hts221_read_reg(priv, &addr, &regval);
-  hts221_dbg("CTRL_REG%d: 0x%02X\n", 2, regval);
-
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  regval &= ~mask;
-  regval |= HTS221_CTRL_REG2_BOOT;
-
-  data_to_write[0] = addr;
-  data_to_write[1] = regval;
-
-  ret = hts221_write_reg8(priv, data_to_write);
-  if (ret >= 0)
-    {
-      /* Wait until boot bit is cleared. */
-
-      do
-        {
-          ret = hts221_read_reg(priv, &addr, &regval);
-          if (ret >= 0)
-            {
-              hts221_dbg("wrote 0x%02X => CTRL_REG%d: 0x%02X\n",
-                         data_to_write[1], 2, regval);
-            }
-          else
-            {
-              break;
-            }
-
-          if ((regval & HTS221_CTRL_REG2_BOOT) == 0)
-            {
-              /* After boot bit is cleared, wait additional 5 msec as
-               * recommended in HTS221 application note.
-               */
-
-              up_mdelay(5);
-              break;
-            }
-
-          nxsched_usleep(10 * 1000);
-          retries--;
-        }
-      while (retries);
-
-      if (ret >= 0 && (regval & HTS221_CTRL_REG2_BOOT) != 0)
-        {
-          ret = -ETIMEDOUT;
-        }
-    }
-
-  return ret;
-}
-
-static int hts221_config_ctrl_reg1(FAR struct hts221_dev_s *priv,
-                                   FAR hts221_settings_t *settings)
-{
-  int ret = OK;
-  uint8_t regval = 0;
-  uint8_t addr = HTS221_CTRL_REG1;
-  const uint8_t mask = 0x87;
-  uint8_t data_to_write[2] =
-  {
-    0
-  };
-
-  ret = hts221_read_reg(priv, &addr, &regval);
-  hts221_dbg("CTRL_REG%d: 0x%02X\n", 1, regval);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  regval &= ~mask;
-  regval |= (uint8_t)(settings->odr & 0xff);
-  regval |= (uint8_t)(settings->is_bdu ? HTS221_CTRL_REG1_BDU : 0);
-
-  data_to_write[0] = addr;
-  data_to_write[1] = regval;
-
-  ret = hts221_write_reg8(priv, data_to_write);
-  if (ret >= 0)
-    {
-      ret = hts221_read_reg(priv, &addr, &regval);
-      if (ret >= 0)
-        {
-          hts221_dbg("wrote 0x%02X => CTRL_REG%d: 0x%02X\n",
-                     data_to_write[1], 1, regval);
-        }
-    }
-
-  return ret;
-}
-
-static int hts221_power_on_off(FAR struct hts221_dev_s *priv, bool on)
-{
-  int ret = OK;
-  uint8_t regval = 0;
-  uint8_t addr = HTS221_CTRL_REG1;
-  uint8_t data_to_write[2];
-
-  ret = hts221_read_reg(priv, &addr, &regval);
-  hts221_dbg("CTRL_REG%d: 0x%02X\n", 1, regval);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  if (on)
-    {
-      regval |= HTS221_CTRL_REG1_PD;
-    }
-  else
-    {
-      regval &= ~HTS221_CTRL_REG1_PD;
-    }
-
-  data_to_write[0] = addr;
-  data_to_write[1] = regval;
-
-  ret = hts221_write_reg8(priv, data_to_write);
-  if (ret >= 0)
-    {
-      ret = hts221_read_reg(priv, &addr, &regval);
-      if (ret >= 0)
-        {
-          hts221_dbg("wrote 0x%02X => CTRL_REG%d: 0x%02X\n",
-                     data_to_write[1], 1, regval);
-        }
-    }
-
-  return ret;
-}
-
-static int hts221_config(FAR struct hts221_dev_s *priv,
-                         FAR hts221_settings_t *cfgr)
-{
-  int ret = OK;
-
-  ret = hts221_config_ctrl_reg2(priv, cfgr); /* Performs sensor reset. */
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  ret = hts221_cfgr_resolution(priv, cfgr);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  ret = hts221_config_ctrl_reg3(priv, cfgr);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  ret = hts221_config_ctrl_reg1(priv, cfgr);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  return ret;
-}
-
-static int hts221_start_conversion(FAR struct hts221_dev_s *priv)
-{
-  int ret;
-  uint8_t addr = HTS221_CTRL_REG2;
-  uint8_t data_to_write[2];
-
-  ret = hts221_power_on_off(priv, true);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  data_to_write[0] = addr;
-  data_to_write[1] = (uint8_t) HTS221_CTRL_REG2_ONE_SHOT;
-
-  ret = hts221_write_reg8(priv, data_to_write);
-  if (ret < 0)
-    {
-      hts221_dbg("Cannot start conversion\n");
-      ret = ERROR;
-    }
-
-  return ret;
-}
-
-static int hts221_check_status(FAR struct hts221_dev_s *priv,
-                               FAR hts221_status_t *status)
-{
-  int ret = OK;
-  uint8_t addr = HTS221_STATUS_REG;
-  const uint8_t humid_mask = 0x02;
-  const uint8_t temp_mask = 0x01;
-  uint8_t regval = 0;
-
-  ret = hts221_read_reg(priv, &addr, &regval);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  status->is_humid_ready = ((regval & humid_mask) ? true : false);
-  status->is_temp_ready = ((regval & temp_mask) ? true : false);
-
-  return ret;
-}
-
-static int hts221_read_raw_data(FAR struct hts221_dev_s *priv,
-                                FAR hts221_raw_data_t *data)
-{
-  int ret = OK;
-  uint8_t addr_humid_low = HTS221_HUM_OUT_L;
-  uint8_t addr_humid_high = HTS221_HUM_OUT_H;
-  uint8_t addr_temp_low = HTS221_TEMP_OUT_L;
-  uint8_t addr_temp_high = HTS221_TEMP_OUT_H;
-  irqstate_t flags;
-
-  ret = hts221_read_reg(priv, &addr_humid_low, &data->humid_low_bits);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  ret = hts221_read_reg(priv, &addr_humid_high, &data->humid_high_bits);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  ret = hts221_read_reg(priv, &addr_temp_low, &data->temp_low_bits);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  ret = hts221_read_reg(priv, &addr_temp_high, &data->temp_high_bits);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  /* Add low-order bytes to entropy pool. */
-
-  add_sensor_randomness(((uint32_t)data->humid_low_bits << 8) |
-                        data->temp_low_bits);
-
-  flags = enter_critical_section();
-  priv->int_pending = false;
-  leave_critical_section(flags);
-
-  hts221_dbg("Humid: 0x%02X, 0x%02X Temper: 0x%02X 0x%02X\n",
-               data->humid_high_bits, data->humid_low_bits,
-               data->temp_high_bits, data->temp_low_bits);
-
-  return ret;
-}
-
-static int hts221_load_calibration_data(FAR struct hts221_dev_s *priv)
-{
-  int ret;
-  uint8_t addr;
-  uint8_t t0_degc_x8   = 0;
-  uint8_t t1_degc_x8   = 0;
-  uint8_t t1_t0_msb    = 0;
-  uint8_t t0_out_lsb   = 0;
-  uint8_t t0_out_msb   = 0;
-  uint8_t t1_out_lsb   = 0;
-  uint8_t t1_out_msb   = 0;
-  uint8_t h0_rh_x2     = 0;
-  uint8_t h1_rh_x2     = 0;
-  uint8_t h0t0_out_lsb = 0;
-  uint8_t h0t0_out_msb = 0;
-  uint8_t h1t0_out_lsb = 0;
-  uint8_t h1t0_out_msb = 0;
-
-  addr = HTS221_CALIB_T0_DEGC_X8;
-  ret = hts221_read_reg(priv, &addr, &t0_degc_x8);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_T1_DEGC_X8;
-  ret = hts221_read_reg(priv, &addr, &t1_degc_x8);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_T1_T0_MSB;
-  ret = hts221_read_reg(priv, &addr, &t1_t0_msb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_T0_OUT_L;
-  ret = hts221_read_reg(priv, &addr, &t0_out_lsb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_T0_OUT_H;
-  ret = hts221_read_reg(priv, &addr, &t0_out_msb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_T1_OUT_L;
-  ret = hts221_read_reg(priv, &addr, &t1_out_lsb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_T1_OUT_H;
-  ret = hts221_read_reg(priv, &addr, &t1_out_msb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_H0_RH_X2;
-  ret = hts221_read_reg(priv, &addr, &h0_rh_x2);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_H1_RH_X2;
-  ret = hts221_read_reg(priv, &addr, &h1_rh_x2);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_H0T0_OUT_L;
-  ret = hts221_read_reg(priv, &addr, &h0t0_out_lsb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_H0T0_OUT_H;
-  ret = hts221_read_reg(priv, &addr, &h0t0_out_msb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_H1T0_OUT_L;
-  ret = hts221_read_reg(priv, &addr, &h1t0_out_lsb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  addr = HTS221_CALIB_H1T0_OUT_H;
-  ret = hts221_read_reg(priv, &addr, &h1t0_out_msb);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  priv->calib.t0_x8     = t0_degc_x8 | ((t1_t0_msb & 0x3) << 8);
-  priv->calib.t1_x8     = t1_degc_x8 | ((t1_t0_msb & (0x3 << 2)) << (8 - 2));
-  priv->calib.t0_out    = (uint16_t) (t0_out_lsb | (t0_out_msb << 8));
-  priv->calib.t1_out    = (uint16_t) (t1_out_lsb | (t1_out_msb << 8));
-  priv->calib.h0_x2     = h0_rh_x2;
-  priv->calib.h1_x2     = h1_rh_x2;
-  priv->calib.h0_t0_out = (uint16_t) (h0t0_out_lsb | (h0t0_out_msb << 8));
-  priv->calib.h1_t0_out = (uint16_t) (h1t0_out_lsb | (h1t0_out_msb << 8));
-
-  hts221_dbg("calib.t0_x8: %d\n", priv->calib.t0_x8);
-  hts221_dbg("calib.t1_x8: %d\n", priv->calib.t1_x8);
-  hts221_dbg("calib.t0_out: %d\n", priv->calib.t0_out);
-  hts221_dbg("calib.t1_out: %d\n", priv->calib.t1_out);
-  hts221_dbg("calib.h0_x2: %d\n", priv->calib.h0_x2);
-  hts221_dbg("calib.h1_x2: %d\n", priv->calib.h1_x2);
-  hts221_dbg("calib.h0_t0_out: %d\n", priv->calib.h0_t0_out);
-  hts221_dbg("calib.h1_t0_out: %d\n", priv->calib.h1_t0_out);
-
-  /* As calibration coefficients are unique to each sensor device,
-   * they are a good candidate to be added to entropy pool.
-   */
-
-  up_rngaddentropy(RND_SRC_HW, (FAR uint32_t *)&priv->calib,
-                   sizeof(priv->calib) / sizeof(uint32_t));
-
-  return OK;
-}
-
-static int hts221_calculate_temperature(FAR struct hts221_dev_s *priv,
-                                        FAR int *temperature,
-                                        FAR hts221_raw_data_t *raw_data)
-{
-  int16_t t_out = (raw_data->temp_high_bits << 8) | raw_data->temp_low_bits;
-  int x0 = priv->calib.t0_out;
-  int x1 = priv->calib.t1_out;
-  int y0 = priv->calib.t0_x8;
-  int y1 = priv->calib.t1_x8;
-  int x = t_out;
-  int64_t y;
-  int x1_x0_diff;
-
-  x1_x0_diff = x1 - x0;
-
-  y = (y0 * x1_x0_diff + (y1 - y0) * (x - x0));
-  y *= HTS221_TEMPERATURE_PRECISION;
-  y /= x1_x0_diff * 8;
-
-  *temperature = (int)y;
-
-  hts221_dbg("Interpolation data temper: %d\n", *temperature);
-
-  return OK;
-}
-
-static int hts221_calculate_humidity(FAR struct hts221_dev_s *priv,
-                                     FAR unsigned int *humidity,
-                                     FAR hts221_raw_data_t *raw_data)
-{
-  int16_t h_out;
-  int x0 = priv->calib.h0_t0_out;
-  int x1 = priv->calib.h1_t0_out;
-  int y0 = priv->calib.h0_x2;
-  int y1 = priv->calib.h1_x2;
-  int x;
-  int64_t y;
-  int x1_x0_diff;
-
-  h_out = (raw_data->humid_high_bits << 8) | raw_data->humid_low_bits;
-  x = h_out;
-  x1_x0_diff = x1 - x0;
-
-  y  = (y0 * x1_x0_diff + (y1 - y0) * (x - x0));
-  y *= HTS221_HUMIDITY_PRECISION;
-  y /= x1_x0_diff * 2;
-
-  *humidity = (int)y;
-
-  hts221_dbg("Interpolation data humidity: %d\n", *humidity);
-
-  return OK;
-}
-
-static int hts221_read_convert_data(FAR struct hts221_dev_s *priv,
-                                    FAR hts221_conv_data_t *data)
-{
-  int ret = OK;
-  hts221_raw_data_t raw_data;
-
-  ret = hts221_read_raw_data(priv, &raw_data);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  ret = hts221_calculate_temperature(priv, &data->temperature, &raw_data);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  hts221_dbg("Temperature calculated\n");
-
-  ret = hts221_calculate_humidity(priv, &data->humidity, &raw_data);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  hts221_dbg("Humidity calculated\n");
-  return ret;
-}
-
-#ifdef CONFIG_HTS221_DEBUG
-static int hts221_dump_registers(FAR struct hts221_dev_s *priv)
-{
-  int ret = OK;
-  uint8_t av_addr = HTS221_AV_CONF;
-  uint8_t ctrl_reg1_addr = HTS221_CTRL_REG1;
-  uint8_t ctrl_reg2_addr = HTS221_CTRL_REG2;
-  uint8_t ctrl_reg3_addr = HTS221_CTRL_REG3;
-  uint8_t regval = 0;
-
-  ret = hts221_read_reg(priv, &av_addr, &regval);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  hts221_dbg("AV_CONF_REG: 0x%02X\n", regval);
-
-  ret = hts221_read_reg(priv, &ctrl_reg1_addr, &regval);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  hts221_dbg("CTRL_REG_1: 0x%02X\n", regval);
-
-  ret = hts221_read_reg(priv, &ctrl_reg2_addr, &regval);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  hts221_dbg("CTRL_REG_2: 0x%02X\n", regval);
-
-  ret = hts221_read_reg(priv, &ctrl_reg3_addr, &regval);
-  if (ret < 0)
-    {
-      return ERROR;
-    }
-
-  hts221_dbg("CTRL_REG_3: 0x%02X\n", regval);
-  return ret;
-}
-#endif
-
-static int hts221_open(FAR struct file *filep)
-{
-  FAR struct inode *inode = filep->f_inode;
-  FAR struct hts221_dev_s *priv = inode->i_private;
-  int ret;
-
-  /* Get exclusive access */
-
-  ret = nxmutex_lock(&priv->devlock);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  priv->config->set_power(priv->config, true);
-  priv->config->irq_enable(priv->config, true);
-
-  nxmutex_unlock(&priv->devlock);
-  hts221_dbg("Sensor is powered on\n");
-  return OK;
-}
-
-static int hts221_close(FAR struct file *filep)
-{
-  FAR struct inode *inode = filep->f_inode;
-  FAR struct hts221_dev_s *priv = inode->i_private;
-  int ret;
-
-  /* Get exclusive access */
-
-  ret = nxmutex_lock(&priv->devlock);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  priv->config->irq_enable(priv->config, false);
-  ret = hts221_power_on_off(priv, false);
-  priv->config->set_power(priv->config, false);
-
-  nxmutex_unlock(&priv->devlock);
-  hts221_dbg("CLOSED\n");
-  return ret;
-}
-
-static ssize_t hts221_read(FAR struct file *filep, FAR char *buffer,
-                           size_t buflen)
-{
-  FAR struct inode *inode = filep->f_inode;
-  FAR struct hts221_dev_s *priv = inode->i_private;
-  hts221_conv_data_t data;
-  ssize_t length = 0;
-  int ret;
-
-  /* Get exclusive access */
-
-  ret = nxmutex_lock(&priv->devlock);
-  if (ret < 0)
-    {
-      return (ssize_t)ret;
-    }
-
-  ret = hts221_read_convert_data(priv, &data);
-  if (ret < 0)
-    {
-      hts221_dbg("cannot read data: %d\n", ret);
-    }
-  else
-    {
-      /* This interface is mainly intended for easy debugging in nsh. */
-
-      length = snprintf(buffer, buflen, "%d %u\n",
-                        data.temperature, data.humidity);
-      if (length > buflen)
-        {
-          length = buflen;
-        }
-    }
-
-  nxmutex_unlock(&priv->devlock);
-  return length;
-}
-
-static ssize_t hts221_write(FAR struct file *filep, FAR const char *buffer,
-                            size_t buflen)
-{
-  ssize_t length = 0;
-
-  return length;
-}
-
-static int hts221_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
-{
-  FAR struct inode *inode = filep->f_inode;
-  FAR struct hts221_dev_s *priv = inode->i_private;
-  int ret;
-
-  /* Get exclusive access */
-
-  ret = nxmutex_lock(&priv->devlock);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  switch (cmd)
-    {
-      case SNIOC_GET_DEV_ID:
-        ret = hts221_get_id(priv, (FAR uint8_t *) arg);
-        break;
-
-      case SNIOC_CFGR:
-        ret = hts221_config(priv, (FAR hts221_settings_t *) arg);
-        break;
-
-      case SNIOC_START_CONVERSION:
-        ret = hts221_start_conversion(priv);
-        break;
-
-      case SNIOC_CHECK_STATUS_REG:
-        ret = hts221_check_status(priv, (FAR hts221_status_t *) arg);
-        break;
-
-      case SNIOC_READ_RAW_DATA:
-        ret = hts221_read_raw_data(priv, (FAR hts221_raw_data_t *) arg);
-        break;
-
-#ifdef CONFIG_HTS221_DEBUG
-      case SNIOC_DUMP_REGS:
-        ret = hts221_dump_registers(priv);
-        break;
-#endif
-
-      case SNIOC_READ_CONVERT_DATA:
-        ret = hts221_read_convert_data(priv, (FAR hts221_conv_data_t *) arg);
-        break;
-
-      default:
-        ret = -ENOTTY;
-        break;
-    }
-
-  nxmutex_unlock(&priv->devlock);
-  return ret;
-}
-
-static bool hts221_sample(FAR struct hts221_dev_s *priv)
-{
-  int ret;
-  hts221_status_t status =
-    {
-      .is_humid_ready = false,
-      .is_temp_ready = false
-    };
-
-  ret = hts221_check_status(priv, &status);
-  if (ret < 0)
-    {
-      return false;
-    }
-
-  return status.is_humid_ready || status.is_temp_ready;
-}
-
-static int hts221_poll(FAR struct file *filep, FAR struct pollfd_s *fds,
-                       bool setup)
-{
-  FAR struct inode *inode;
-  FAR struct hts221_dev_s *priv;
-  irqstate_t flags;
-  int ret = OK;
-  int i;
-
-  DEBUGASSERT(fds);
-  inode = filep->f_inode;
-
-  DEBUGASSERT(inode->i_private);
-  priv = inode->i_private;
-
-  /* Get exclusive access */
-
-  ret = nxmutex_lock(&priv->devlock);
-  if (ret < 0)
-    {
-      return ret;
-    }
-
-  if (setup)
-    {
-      /* Ignore waits that do not include POLLIN */
-
-      if ((fds->events & POLLIN) == 0)
-        {
-          ret = -EDEADLK;
-          goto out;
-        }
-
-      /* This is a request to set up the poll.  Find an available slot for
-       * the poll structure reference.
-       */
-
-      for (i = 0; i < CONFIG_HTS221_NPOLLWAITERS; i++)
-        {
-          /* Find an available slot */
-
-          if (!priv->fds[i])
-            {
-              /* Bind the poll structure and this slot */
-
-              priv->fds[i] = fds;
-              fds->priv = &priv->fds[i];
-              break;
-            }
-        }
-
-      if (i >= CONFIG_HTS221_NPOLLWAITERS)
-        {
-          fds->priv = NULL;
-          ret = -EBUSY;
-          goto out;
-        }
-
-      flags = enter_critical_section();
-      if (priv->int_pending || hts221_sample(priv))
-        {
-          poll_notify(&fds, 1, POLLIN);
-        }
-
-      leave_critical_section(flags);
-    }
-  else if (fds->priv)
-    {
-      /* This is a request to tear down the poll. */
-
-      FAR struct pollfd_s **slot = (FAR struct pollfd_s **)fds->priv;
-
-      DEBUGASSERT(slot != NULL);
-
-      /* Remove all memory of the poll setup */
-
-      *slot = NULL;
-      fds->priv = NULL;
-    }
-
-out:
-  nxmutex_unlock(&priv->devlock);
-  return ret;
-}
-
-static int hts221_int_handler(int irq, FAR void *context, FAR void *arg)
-{
-  FAR struct hts221_dev_s *priv = (FAR struct hts221_dev_s *)arg;
-
-  DEBUGASSERT(priv != NULL);
-
-  priv->int_pending = true;
-  hts221_dbg("Hts221 interrupt\n");
-  poll_notify(priv->fds, CONFIG_HTS221_NPOLLWAITERS, POLLIN);
-
-  return OK;
-}
-
-int hts221_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
-                    uint8_t addr, FAR hts221_config_t *config)
-{
-  int ret = 0;
-  FAR struct hts221_dev_s *priv;
-
-  priv = kmm_zalloc(sizeof(struct hts221_dev_s));
-
-  if (!priv)
-    {
-      hts221_dbg("Memory cannot be allocated for hts221 sensor");
-      return -ENOMEM;
-    }
-
-  priv->addr   = addr;
-  priv->i2c    = i2c;
-  priv->config = config;
-  nxmutex_init(&priv->devlock);
-
-  priv->config->set_power(priv->config, true);
-
-  ret = hts221_load_calibration_data(priv);
-  if (ret < 0)
-    {
-      nxmutex_destroy(&priv->devlock);
-      kmm_free(priv);
-      hts221_dbg("Cannot calibrate hts221 sensor\n");
-      return ret;
-    }
-
-  ret = register_driver(devpath, &g_humidityops, 0600, priv);
-
-  hts221_dbg("Registered with %d\n", ret);
-
-  if (ret < 0)
-    {
-      nxmutex_destroy(&priv->devlock);
-      kmm_free(priv);
-      hts221_dbg("Error occurred during the driver registering\n");
-      return ret;
-    }
-
-  if (priv->config->irq_clear)
-    {
-      priv->config->irq_clear(priv->config);
-    }
-
-  priv->config->irq_attach(priv->config, hts221_int_handler, priv);
-  priv->config->irq_enable(priv->config, false);
-  priv->config->set_power(priv->config, false);
-  return OK;
-}
diff --git a/drivers/sensors/hts221_uorb.c b/drivers/sensors/hts221_uorb.c
new file mode 100644
index 00000000000..8ea5dfd7adf
--- /dev/null
+++ b/drivers/sensors/hts221_uorb.c
@@ -0,0 +1,1216 @@
+/****************************************************************************
+ * drivers/sensors/hts221_uorb.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 <nuttx/config.h>
+
+#include <errno.h>
+#include <debug.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <nuttx/nuttx.h>
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mutex.h>
+#include <nuttx/random.h>
+#include <nuttx/signal.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/sensors/sensor.h>
+#include <nuttx/sensors/hts221.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register map */
+
+#define HTS221_WHO_AM_I             0x0f
+#define HTS221_AV_CONF              0x10
+#define HTS221_CTRL_REG1            0x20
+#define HTS221_CTRL_REG2            0x21
+#define HTS221_CTRL_REG3            0x22
+#define HTS221_STATUS_REG           0x27
+#define HTS221_HUM_OUT_L            0x28
+#define HTS221_HUM_OUT_H            0x29
+#define HTS221_TEMP_OUT_L           0x2a
+#define HTS221_TEMP_OUT_H           0x2b
+
+/* Calibration registers */
+
+#define HTS221_CALIB_H0_RH_X2       0x30
+#define HTS221_CALIB_H1_RH_X2       0x31
+#define HTS221_CALIB_T0_DEGC_X8     0x32
+#define HTS221_CALIB_T1_DEGC_X8     0x33
+#define HTS221_CALIB_T1_T0_MSB      0x35
+#define HTS221_CALIB_H0T0_OUT_L     0x36
+#define HTS221_CALIB_H0T0_OUT_H     0x37
+#define HTS221_CALIB_H1T0_OUT_L     0x3a
+#define HTS221_CALIB_H1T0_OUT_H     0x3b
+#define HTS221_CALIB_T0_OUT_L       0x3c
+#define HTS221_CALIB_T0_OUT_H       0x3d
+#define HTS221_CALIB_T1_OUT_L       0x3e
+#define HTS221_CALIB_T1_OUT_H       0x3f
+
+/* HTS221_AV_CONF: AVGH in bits 0-2, AVGT in bits 3-5 */
+
+#define HTS221_AV_CONF_AVGH_SHIFT   0
+#define HTS221_AV_CONF_AVGT_SHIFT   3
+#define HTS221_AV_CONF_MASK         0x3f
+#define HTS221_AVGT_DEFAULT         3        /* 16 samples */
+#define HTS221_AVGH_DEFAULT         3        /* 32 samples */
+#define HTS221_AVG_CODES            8
+
+/* HTS221_CTRL_REG1 */
+
+#define HTS221_CTRL_REG1_PD         (1 << 7)
+#define HTS221_CTRL_REG1_BDU        (1 << 2)
+#define HTS221_CTRL_REG1_ODR_MASK   0x03
+#define HTS221_ODR_ONESHOT          0
+#define HTS221_ODR_1HZ              1
+#define HTS221_ODR_7HZ              2
+#define HTS221_ODR_12_5HZ           3
+
+/* HTS221_CTRL_REG2 */
+
+#define HTS221_CTRL_REG2_BOOT       (1 << 7)
+#define HTS221_CTRL_REG2_ONE_SHOT   (1 << 0)
+
+/* HTS221_CTRL_REG3 */
+
+#define HTS221_CTRL_REG3_DRDY_L_H   (1 << 7)
+#define HTS221_CTRL_REG3_PP_OD      (1 << 6)
+#define HTS221_CTRL_REG3_DRDY_EN    (1 << 2)
+
+/* HTS221_STATUS_REG */
+
+#define HTS221_STATUS_REG_H_DA      (1 << 1)
+#define HTS221_STATUS_REG_T_DA      (1 << 0)
+#define HTS221_STATUS_REG_DA        (HTS221_STATUS_REG_H_DA | \
+                                     HTS221_STATUS_REG_T_DA)
+
+#define HTS221_DEVID                0xbc
+
+#define HTS221_BOOT_RETRIES         5
+#define HTS221_ONE_SHOT_RETRIES     10
+
+/* Output data rate periods in us */
+
+#define HTS221_PERIOD_12_5HZ        80000
+#define HTS221_PERIOD_7HZ           142857
+#define HTS221_PERIOD_1HZ           1000000
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Each measurement channel needs its own lower-half. */
+
+struct hts221_sensor_s
+{
+  FAR struct sensor_lowerhalf_s lower;   /* Lower-half driver */
+  FAR struct hts221_dev_s      *dev;     /* Parent device */
+  bool                          enabled; /* Channel activated */
+};
+
+struct hts221_dev_s
+{
+  struct hts221_sensor_s   temp;     /* Temperature lower-half */
+  struct hts221_sensor_s   hum;      /* Humidity lower-half */
+  FAR struct i2c_master_s *i2c;      /* I2C interface */
+  FAR hts221_config_t     *config;   /* Board callbacks, may be NULL */
+  uint8_t                  addr;     /* I2C address */
+  uint8_t                  avgt;     /* Temperature averaging code */
+  uint8_t                  avgh;     /* Humidity averaging code */
+  uint8_t                  odr;      /* Output data rate code */
+  uint32_t                 interval; /* Requested interval in us */
+  struct work_s            work;     /* Measurement work */
+  mutex_t                  lock;     /* Serialize device access */
+  bool                     running;  /* Sampling in progress */
+  struct
+  {
+    int16_t t0_out;
+    int16_t t1_out;
+    int16_t h0_t0_out;
+    int16_t h1_t0_out;
+    unsigned int t0_x8:10;
+    unsigned int t1_x8:10;
+    uint8_t h0_x2;
+    uint8_t h1_x2;
+  } calib;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int hts221_read_reg(FAR struct hts221_dev_s *priv, uint8_t regaddr,
+                           FAR uint8_t *regval);
+static int hts221_write_reg(FAR struct hts221_dev_s *priv, uint8_t regaddr,
+                            uint8_t regval);
+static int hts221_modify_reg(FAR struct hts221_dev_s *priv,
+                             uint8_t regaddr, uint8_t mask, uint8_t value);
+static int hts221_load_calibration(FAR struct hts221_dev_s *priv);
+static int hts221_boot(FAR struct hts221_dev_s *priv);
+static bool hts221_use_irq(FAR struct hts221_dev_s *priv);
+static int hts221_apply_settings(FAR struct hts221_dev_s *priv);
+static int hts221_board_power(FAR struct hts221_dev_s *priv, bool on);
+static int hts221_power(FAR struct hts221_dev_s *priv, bool on);
+static int hts221_wait_data(FAR struct hts221_dev_s *priv, int retries);
+static int hts221_read_raw(FAR struct hts221_dev_s *priv,
+                           FAR int16_t *t_out, FAR int16_t *h_out);
+static sensor_data_t hts221_interpolate(int y0, int y1, int x0, int x1,
+                                        int x, int div);
+static void hts221_push(FAR struct hts221_dev_s *priv, int16_t t_out,
+                        int16_t h_out, bool temp_en, bool hum_en);
+static void hts221_worker(FAR void *arg);
+static int hts221_int_handler(int irq, FAR void *context, FAR void *arg);
+static int hts221_start(FAR struct hts221_dev_s *priv);
+static void hts221_stop(FAR struct hts221_dev_s *priv);
+static int hts221_set_oversampling(FAR struct hts221_sensor_s *sensor,
+                                   unsigned long samples);
+
+/* Sensor lower-half operations */
+
+static int hts221_activate(FAR struct sensor_lowerhalf_s *lower,
+                           FAR struct file *filep, bool enable);
+static int hts221_set_interval(FAR struct sensor_lowerhalf_s *lower,
+                               FAR struct file *filep,
+                               FAR uint32_t *period_us);
+static int hts221_selftest(FAR struct sensor_lowerhalf_s *lower,
+                           FAR struct file *filep, unsigned long arg);
+static int hts221_get_info(FAR struct sensor_lowerhalf_s *lower,
+                           FAR struct file *filep,
+                           FAR struct sensor_device_info_s *info);
+static int hts221_control(FAR struct sensor_lowerhalf_s *lower,
+                          FAR struct file *filep, int cmd,
+                          unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct sensor_ops_s g_hts221_ops =
+{
+  .activate     = hts221_activate,
+  .set_interval = hts221_set_interval,
+  .selftest     = hts221_selftest,
+  .get_info     = hts221_get_info,
+  .control      = hts221_control,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: hts221_read_reg
+ ****************************************************************************/
+
+static int hts221_read_reg(FAR struct hts221_dev_s *priv, uint8_t regaddr,
+                           FAR uint8_t *regval)
+{
+  struct i2c_config_s config;
+
+  config.frequency = CONFIG_HTS221_I2C_FREQUENCY;
+  config.address   = priv->addr;
+  config.addrlen   = 7;
+
+  return i2c_writeread(priv->i2c, &config, &regaddr, 1, regval, 1);
+}
+
+/****************************************************************************
+ * Name: hts221_write_reg
+ ****************************************************************************/
+
+static int hts221_write_reg(FAR struct hts221_dev_s *priv, uint8_t regaddr,
+                            uint8_t regval)
+{
+  struct i2c_config_s config;
+  uint8_t buf[2];
+
+  config.frequency = CONFIG_HTS221_I2C_FREQUENCY;
+  config.address   = priv->addr;
+  config.addrlen   = 7;
+
+  buf[0] = regaddr;
+  buf[1] = regval;
+
+  return i2c_write(priv->i2c, &config, buf, 2);
+}
+
+/****************************************************************************
+ * Name: hts221_modify_reg
+ ****************************************************************************/
+
+static int hts221_modify_reg(FAR struct hts221_dev_s *priv,
+                             uint8_t regaddr, uint8_t mask, uint8_t value)
+{
+  uint8_t regval;
+  int ret;
+
+  ret = hts221_read_reg(priv, regaddr, &regval);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  regval &= ~mask;
+  regval |= value & mask;
+
+  return hts221_write_reg(priv, regaddr, regval);
+}
+
+/****************************************************************************
+ * Name: hts221_load_calibration
+ *
+ * Description:
+ *   Read the factory calibration coefficients used to convert raw readings
+ *   into physical units.
+ *
+ ****************************************************************************/
+
+static int hts221_load_calibration(FAR struct hts221_dev_s *priv)
+{
+  uint8_t t0_degc_x8   = 0;
+  uint8_t t1_degc_x8   = 0;
+  uint8_t t1_t0_msb    = 0;
+  uint8_t t0_out_lsb   = 0;
+  uint8_t t0_out_msb   = 0;
+  uint8_t t1_out_lsb   = 0;
+  uint8_t t1_out_msb   = 0;
+  uint8_t h0_rh_x2     = 0;
+  uint8_t h1_rh_x2     = 0;
+  uint8_t h0t0_out_lsb = 0;
+  uint8_t h0t0_out_msb = 0;
+  uint8_t h1t0_out_lsb = 0;
+  uint8_t h1t0_out_msb = 0;
+  int ret;
+
+  ret = hts221_read_reg(priv, HTS221_CALIB_T0_DEGC_X8, &t0_degc_x8);
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_T1_DEGC_X8, &t1_degc_x8);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_T1_T0_MSB, &t1_t0_msb);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_T0_OUT_L, &t0_out_lsb);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_T0_OUT_H, &t0_out_msb);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_T1_OUT_L, &t1_out_lsb);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_T1_OUT_H, &t1_out_msb);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_H0_RH_X2, &h0_rh_x2);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_H1_RH_X2, &h1_rh_x2);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_H0T0_OUT_L, &h0t0_out_lsb);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_H0T0_OUT_H, &h0t0_out_msb);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_H1T0_OUT_L, &h1t0_out_lsb);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_CALIB_H1T0_OUT_H, &h1t0_out_msb);
+    }
+
+  if (ret < 0)
+    {
+      snerr("ERROR: Failed to read HTS221 calibration data: %d\n", ret);
+      return ret;
+    }
+
+  priv->calib.t0_x8     = t0_degc_x8 | ((t1_t0_msb & 0x3) << 8);
+  priv->calib.t1_x8     = t1_degc_x8 | ((t1_t0_msb & (0x3 << 2)) << (8 - 2));
+  priv->calib.t0_out    = t0_out_lsb | (t0_out_msb << 8);
+  priv->calib.t1_out    = t1_out_lsb | (t1_out_msb << 8);
+  priv->calib.h0_x2     = h0_rh_x2;
+  priv->calib.h1_x2     = h1_rh_x2;
+  priv->calib.h0_t0_out = h0t0_out_lsb | (h0t0_out_msb << 8);
+  priv->calib.h1_t0_out = h1t0_out_lsb | (h1t0_out_msb << 8);
+
+  /* As calibration coefficients are unique to each sensor device,
+   * they are a good candidate to be added to the entropy pool.
+   */
+
+  up_rngaddentropy(RND_SRC_HW, (FAR uint32_t *)&priv->calib,
+                   sizeof(priv->calib) / sizeof(uint32_t));
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_boot
+ *
+ * Description:
+ *   Reboot the sensor to reload the trimming parameters.  Resets the
+ *   control registers, so it is done before they are programmed.
+ *
+ ****************************************************************************/
+
+static int hts221_boot(FAR struct hts221_dev_s *priv)
+{
+  uint8_t regval;
+  int retries = HTS221_BOOT_RETRIES;
+  int ret;
+
+  ret = hts221_write_reg(priv, HTS221_CTRL_REG2, HTS221_CTRL_REG2_BOOT);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  do
+    {
+      nxsig_usleep(10000);
+      ret = hts221_read_reg(priv, HTS221_CTRL_REG2, &regval);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+  while ((regval & HTS221_CTRL_REG2_BOOT) && --retries);
+
+  if (regval & HTS221_CTRL_REG2_BOOT)
+    {
+      return -ETIMEDOUT;
+    }
+
+  /* After boot bit is cleared, wait additional 5 msec as recommended in
+   * HTS221 application note.
+   */
+
+  up_mdelay(5);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_use_irq
+ *
+ * Description:
+ *   True when the data-ready interrupt drives the sampling: the board
+ *   provides the interrupt and the requested rate maps to a continuous
+ *   output data rate.
+ *
+ ****************************************************************************/
+
+static bool hts221_use_irq(FAR struct hts221_dev_s *priv)
+{
+  return priv->config != NULL && priv->config->irq_attach != NULL &&
+         priv->odr != HTS221_ODR_ONESHOT;
+}
+
+/****************************************************************************
+ * Name: hts221_apply_settings
+ *
+ * Description:
+ *   Program averaging, data-ready pin and output data rate.  The PD bit is
+ *   left untouched.
+ *
+ ****************************************************************************/
+
+static int hts221_apply_settings(FAR struct hts221_dev_s *priv)
+{
+  uint8_t regval;
+  int ret;
+
+  regval = (priv->avgh << HTS221_AV_CONF_AVGH_SHIFT) |
+           (priv->avgt << HTS221_AV_CONF_AVGT_SHIFT);
+  ret = hts221_modify_reg(priv, HTS221_AV_CONF, HTS221_AV_CONF_MASK,
+                          regval);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  regval = 0;
+  if (hts221_use_irq(priv))
+    {
+      regval |= HTS221_CTRL_REG3_DRDY_EN;
+      regval |= priv->config->drdy_active_low ?
+                HTS221_CTRL_REG3_DRDY_L_H : 0;
+      regval |= priv->config->drdy_open_drain ?
+                HTS221_CTRL_REG3_PP_OD : 0;
+    }
+
+  ret = hts221_write_reg(priv, HTS221_CTRL_REG3, regval);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  return hts221_modify_reg(priv, HTS221_CTRL_REG1,
+                           HTS221_CTRL_REG1_ODR_MASK | HTS221_CTRL_REG1_BDU,
+                           priv->odr | HTS221_CTRL_REG1_BDU);
+}
+
+/****************************************************************************
+ * Name: hts221_board_power
+ *
+ * Description:
+ *   Switch the sensor supply through the board callback, if any.
+ *
+ ****************************************************************************/
+
+static int hts221_board_power(FAR struct hts221_dev_s *priv, bool on)
+{
+  if (priv->config != NULL && priv->config->set_power != NULL)
+    {
+      return priv->config->set_power(priv->config, on);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_power
+ *
+ * Description:
+ *   Set or clear the PD bit.
+ *
+ ****************************************************************************/
+
+static int hts221_power(FAR struct hts221_dev_s *priv, bool on)
+{
+  return hts221_modify_reg(priv, HTS221_CTRL_REG1, HTS221_CTRL_REG1_PD,
+                           on ? HTS221_CTRL_REG1_PD : 0);
+}
+
+/****************************************************************************
+ * Name: hts221_wait_data
+ *
+ * Description:
+ *   Wait until both temperature and humidity samples are available.
+ *
+ ****************************************************************************/
+
+static int hts221_wait_data(FAR struct hts221_dev_s *priv, int retries)
+{
+  uint8_t regval;
+  int ret;
+
+  for (; ; )
+    {
+      ret = hts221_read_reg(priv, HTS221_STATUS_REG, &regval);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      if ((regval & HTS221_STATUS_REG_DA) == HTS221_STATUS_REG_DA)
+        {
+          return OK;
+        }
+
+      if (--retries <= 0)
+        {
+          return -EAGAIN;
+        }
+
+      nxsig_usleep(5000);
+    }
+}
+
+/****************************************************************************
+ * Name: hts221_read_raw
+ *
+ * Description:
+ *   Read the raw temperature and humidity output registers.
+ *
+ ****************************************************************************/
+
+static int hts221_read_raw(FAR struct hts221_dev_s *priv,
+                           FAR int16_t *t_out, FAR int16_t *h_out)
+{
+  uint8_t h_l;
+  uint8_t h_h;
+  uint8_t t_l;
+  uint8_t t_h;
+  int ret;
+
+  ret = hts221_read_reg(priv, HTS221_HUM_OUT_L, &h_l);
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_HUM_OUT_H, &h_h);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_TEMP_OUT_L, &t_l);
+    }
+
+  if (ret >= 0)
+    {
+      ret = hts221_read_reg(priv, HTS221_TEMP_OUT_H, &t_h);
+    }
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  *t_out = t_h << 8 | t_l;
+  *h_out = h_h << 8 | h_l;
+
+  add_sensor_randomness(*h_out ^ *t_out);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_interpolate
+ *
+ * Description:
+ *   Linear interpolation between the two factory calibration points
+ *   (x0, y0) and (x1, y1) at x, with the result divided by div.
+ *
+ ****************************************************************************/
+
+static sensor_data_t hts221_interpolate(int y0, int y1, int x0, int x1,
+                                        int x, int div)
+{
+  sensor_data_t slope;
+  int span  = x1 - x0;
+  int delta = x - x0;
+  int rise  = y1 - y0;
+
+  /* Keep the operands within the b16 range */
+
+  while (span > 16383 || span < -16383)
+    {
+      span  /= 2;
+      delta /= 2;
+    }
+
+  slope = sensor_data_div(sensor_data_itof(rise), sensor_data_itof(span));
+
+  return sensor_data_divi(sensor_data_add(sensor_data_itof(y0),
+                                          sensor_data_muli(slope, delta)),
+                          div);
+}
+
+/****************************************************************************
+ * Name: hts221_push
+ *
+ * Description:
+ *   Convert a raw sample with the factory calibration and push it to the
+ *   enabled topics.  Called without the lock held, since the upper half
+ *   takes its own lock in push_event.
+ *
+ ****************************************************************************/
+
+static void hts221_push(FAR struct hts221_dev_s *priv, int16_t t_out,
+                        int16_t h_out, bool temp_en, bool hum_en)
+{
+  struct sensor_temp temp;
+  struct sensor_humi humi;
+
+  temp.timestamp   = sensor_get_timestamp();
+  temp.temperature = hts221_interpolate(priv->calib.t0_x8,
+                                        priv->calib.t1_x8,
+                                        priv->calib.t0_out,
+                                        priv->calib.t1_out, t_out, 8);
+  humi.timestamp   = temp.timestamp;
+  humi.humidity    = hts221_interpolate(priv->calib.h0_x2,
+                                        priv->calib.h1_x2,
+                                        priv->calib.h0_t0_out,
+                                        priv->calib.h1_t0_out, h_out, 2);
+
+  if (temp_en)
+    {
+      priv->temp.lower.push_event(priv->temp.lower.priv, &temp,
+                                  sizeof(temp));
+    }
+
+  if (hum_en)
+    {
+      priv->hum.lower.push_event(priv->hum.lower.priv, &humi,
+                                 sizeof(humi));
+    }
+}
+
+/****************************************************************************
+ * Name: hts221_worker
+ *
+ * Description:
+ *   In one-shot mode trigger a conversion, wait for it and re-queue every
+ *   interval.  With the data-ready interrupt the handler queues the worker
+ *   and the sample is ready.
+ *
+ ****************************************************************************/
+
+static void hts221_worker(FAR void *arg)
+{
+  FAR struct hts221_dev_s *priv = (FAR struct hts221_dev_s *)arg;
+  bool temp_en;
+  bool hum_en;
+  int16_t t_out = 0;
+  int16_t h_out = 0;
+  int ret;
+
+  nxmutex_lock(&priv->lock);
+
+  if (!priv->running)
+    {
+      nxmutex_unlock(&priv->lock);
+      return;
+    }
+
+  if (!hts221_use_irq(priv))
+    {
+      /* Reading the output registers clears stale data-ready flags left by
+       * a boot or a previous run, so that the wait below sees only the
+       * conversion triggered here.
+       */
+
+      ret = hts221_read_raw(priv, &t_out, &h_out);
+      if (ret >= 0)
+        {
+          ret = hts221_write_reg(priv, HTS221_CTRL_REG2,
+                                 HTS221_CTRL_REG2_ONE_SHOT);
+        }
+
+      if (ret >= 0)
+        {
+          ret = hts221_wait_data(priv, HTS221_ONE_SHOT_RETRIES);
+        }
+
+      work_queue(LPWORK, &priv->work, hts221_worker, priv,
+                 USEC2TICK(priv->interval));
+    }
+  else
+    {
+      ret = hts221_wait_data(priv, 1);
+    }
+
+  if (ret == OK)
+    {
+      ret = hts221_read_raw(priv, &t_out, &h_out);
+    }
+
+  temp_en = priv->temp.enabled;
+  hum_en  = priv->hum.enabled;
+
+  nxmutex_unlock(&priv->lock);
+
+  if (ret == OK)
+    {
+      hts221_push(priv, t_out, h_out, temp_en, hum_en);
+    }
+  else if (ret != -EAGAIN)
+    {
+      snerr("ERROR: HTS221 measurement failed: %d\n", ret);
+    }
+}
+
+/****************************************************************************
+ * Name: hts221_int_handler
+ ****************************************************************************/
+
+static int hts221_int_handler(int irq, FAR void *context, FAR void *arg)
+{
+  FAR struct hts221_dev_s *priv = (FAR struct hts221_dev_s *)arg;
+
+  DEBUGASSERT(priv != NULL);
+
+  if (priv->config->irq_clear != NULL)
+    {
+      priv->config->irq_clear(priv->config);
+    }
+
+  return work_queue(LPWORK, &priv->work, hts221_worker, priv, 0);
+}
+
+/****************************************************************************
+ * Name: hts221_start
+ *
+ * Description:
+ *   Power on, program the settings and start sampling.  Called with the
+ *   lock held.
+ *
+ ****************************************************************************/
+
+static int hts221_start(FAR struct hts221_dev_s *priv)
+{
+  int ret;
+
+  ret = hts221_board_power(priv, true);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = hts221_apply_settings(priv);
+  if (ret >= 0)
+    {
+      ret = hts221_power(priv, true);
+    }
+
+  if (ret < 0)
+    {
+      hts221_board_power(priv, false);
+      return ret;
+    }
+
+  priv->running = true;
+
+  if (hts221_use_irq(priv))
+    {
+      if (priv->config->irq_clear != NULL)
+        {
+          priv->config->irq_clear(priv->config);
+        }
+
+      if (priv->config->irq_enable != NULL)
+        {
+          priv->config->irq_enable(priv->config, true);
+        }
+    }
+
+  /* Take the first sample now; it also drains a sample that may already
+   * be waiting so that the DRDY line goes low.
+   */
+
+  return work_queue(LPWORK, &priv->work, hts221_worker, priv, 0);
+}
+
+/****************************************************************************
+ * Name: hts221_stop
+ *
+ * Description:
+ *   Stop sampling and power off.  Called with the lock held.
+ *
+ ****************************************************************************/
+
+static void hts221_stop(FAR struct hts221_dev_s *priv)
+{
+  priv->running = false;
+  work_cancel(LPWORK, &priv->work);
+
+  if (priv->config != NULL && priv->config->irq_enable != NULL)
+    {
+      priv->config->irq_enable(priv->config, false);
+    }
+
+  hts221_write_reg(priv, HTS221_CTRL_REG2, 0);
+  hts221_power(priv, false);
+  hts221_board_power(priv, false);
+}
+
+/****************************************************************************
+ * Name: hts221_set_oversampling
+ *
+ * Description:
+ *   Set the number of internal samples averaged for one output: 2 to 256
+ *   for temperature, 4 to 512 for humidity, powers of two.  Called with
+ *   the lock held.
+ *
+ ****************************************************************************/
+
+static int hts221_set_oversampling(FAR struct hts221_sensor_s *sensor,
+                                   unsigned long samples)
+{
+  FAR struct hts221_dev_s *priv = sensor->dev;
+  unsigned long base;
+  uint8_t code;
+
+  base = sensor->lower.type == SENSOR_TYPE_AMBIENT_TEMPERATURE ? 2 : 4;
+
+  for (code = 0; code < HTS221_AVG_CODES; code++)
+    {
+      if (samples == (base << code))
+        {
+          break;
+        }
+    }
+
+  if (code == HTS221_AVG_CODES)
+    {
+      return -EINVAL;
+    }
+
+  if (sensor->lower.type == SENSOR_TYPE_AMBIENT_TEMPERATURE)
+    {
+      priv->avgt = code;
+    }
+  else
+    {
+      priv->avgh = code;
+    }
+
+  return hts221_modify_reg(priv, HTS221_AV_CONF, HTS221_AV_CONF_MASK,
+                           (priv->avgh << HTS221_AV_CONF_AVGH_SHIFT) |
+                           (priv->avgt << HTS221_AV_CONF_AVGT_SHIFT));
+}
+
+/****************************************************************************
+ * Name: hts221_activate
+ ****************************************************************************/
+
+static int hts221_activate(FAR struct sensor_lowerhalf_s *lower,
+                           FAR struct file *filep, bool enable)
+{
+  FAR struct hts221_sensor_s *sensor =
+      container_of(lower, FAR struct hts221_sensor_s, lower);
+  FAR struct hts221_dev_s *priv = sensor->dev;
+  int ret = OK;
+
+  nxmutex_lock(&priv->lock);
+
+  sensor->enabled = enable;
+
+  if (enable && !priv->running)
+    {
+      ret = hts221_start(priv);
+    }
+  else if (!enable && priv->running &&
+           !priv->temp.enabled && !priv->hum.enabled)
+    {
+      hts221_stop(priv);
+    }
+
+  nxmutex_unlock(&priv->lock);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: hts221_set_interval
+ *
+ * Description:
+ *   Without the data-ready interrupt the part is polled in one-shot mode
+ *   every interval.  With it the interval selects the continuous output
+ *   data rate: 12.5 Hz, 7 Hz or 1 Hz.
+ *
+ ****************************************************************************/
+
+static int hts221_set_interval(FAR struct sensor_lowerhalf_s *lower,
+                               FAR struct file *filep,
+                               FAR uint32_t *period_us)
+{
+  FAR struct hts221_sensor_s *sensor =
+      container_of(lower, FAR struct hts221_sensor_s, lower);
+  FAR struct hts221_dev_s *priv = sensor->dev;
+  uint8_t odr = HTS221_ODR_ONESHOT;
+  int ret = OK;
+
+  if (priv->config != NULL && priv->config->irq_attach != NULL)
+    {
+      if (*period_us <= HTS221_PERIOD_12_5HZ)
+        {
+          odr = HTS221_ODR_12_5HZ;
+          *period_us = HTS221_PERIOD_12_5HZ;
+        }
+      else if (*period_us <= HTS221_PERIOD_7HZ)
+        {
+          odr = HTS221_ODR_7HZ;
+          *period_us = HTS221_PERIOD_7HZ;
+        }
+      else
+        {
+          odr = HTS221_ODR_1HZ;
+        }
+    }
+
+  nxmutex_lock(&priv->lock);
+
+  priv->interval = *period_us;
+
+  if (odr != priv->odr)
+    {
+      priv->odr = odr;
+      if (priv->running)
+        {
+          hts221_stop(priv);
+          ret = hts221_start(priv);
+        }
+    }
+
+  nxmutex_unlock(&priv->lock);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: hts221_selftest
+ *
+ * Description:
+ *   Check that the part answers with its device ID.
+ *
+ ****************************************************************************/
+
+static int hts221_selftest(FAR struct sensor_lowerhalf_s *lower,
+                           FAR struct file *filep, unsigned long arg)
+{
+  FAR struct hts221_sensor_s *sensor =
+      container_of(lower, FAR struct hts221_sensor_s, lower);
+  FAR struct hts221_dev_s *priv = sensor->dev;
+  uint8_t id = 0;
+  int ret;
+
+  nxmutex_lock(&priv->lock);
+  ret = hts221_read_reg(priv, HTS221_WHO_AM_I, &id);
+  nxmutex_unlock(&priv->lock);
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  return id == HTS221_DEVID ? OK : -ENODEV;
+}
+
+/****************************************************************************
+ * Name: hts221_get_info
+ ****************************************************************************/
+
+static int hts221_get_info(FAR struct sensor_lowerhalf_s *lower,
+                           FAR struct file *filep,
+                           FAR struct sensor_device_info_s *info)
+{
+  memset(info, 0, sizeof(*info));
+
+  info->version   = 0;
+  info->power     = sensor_data_ftof(0.002f);     /* 2 uA at 1 Hz */
+  info->min_delay = HTS221_PERIOD_12_5HZ;
+  info->max_delay = HTS221_PERIOD_1HZ;
+  strlcpy(info->name, "HTS221", sizeof(info->name));
+  strlcpy(info->vendor, "STMicroelectronics", sizeof(info->vendor));
+
+  if (lower->type == SENSOR_TYPE_AMBIENT_TEMPERATURE)
+    {
+      info->max_range  = sensor_data_itof(120);
+      info->resolution = sensor_data_ftof(0.016f); /* 64 LSB / degC */
+    }
+  else
+    {
+      info->max_range  = sensor_data_itof(100);
+      info->resolution = sensor_data_ftof(0.004f); /* 256 LSB / %rH */
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_control
+ *
+ * Description:
+ *   SNIOC_OVERSAMPLING - number of averaged samples for this topic
+ *
+ ****************************************************************************/
+
+static int hts221_control(FAR struct sensor_lowerhalf_s *lower,
+                          FAR struct file *filep, int cmd,
+                          unsigned long arg)
+{
+  FAR struct hts221_sensor_s *sensor =
+      container_of(lower, FAR struct hts221_sensor_s, lower);
+  FAR struct hts221_dev_s *priv = sensor->dev;
+  int ret;
+
+  nxmutex_lock(&priv->lock);
+
+  switch (cmd)
+    {
+      case SNIOC_OVERSAMPLING:
+        ret = hts221_set_oversampling(sensor, arg);
+        break;
+
+      default:
+        ret = -ENOTTY;
+        break;
+    }
+
+  nxmutex_unlock(&priv->lock);
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: hts221_register_uorb
+ *
+ * Description:
+ *   Register the HTS221 humidity and temperature sensor as UORB devices.
+ *
+ * Input Parameters:
+ *   devno  - The device number, used to build the device path.
+ *   i2c    - The I2C bus driver instance.
+ *   addr   - The I2C address of the HTS221.
+ *   config - Board callbacks for the data-ready interrupt and power, or
+ *            NULL.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int hts221_register_uorb(int devno, FAR struct i2c_master_s *i2c,
+                         uint8_t addr, FAR hts221_config_t *config)
+{
+  FAR struct hts221_dev_s *priv;
+  uint8_t id;
+  int ret;
+
+  DEBUGASSERT(i2c != NULL);
+
+  priv = kmm_zalloc(sizeof(struct hts221_dev_s));
+  if (priv == NULL)
+    {
+      snerr("ERROR: Failed to allocate HTS221 instance\n");
+      return -ENOMEM;
+    }
+
+  priv->i2c      = i2c;
+  priv->addr     = addr;
+  priv->config   = config;
+  priv->avgt     = HTS221_AVGT_DEFAULT;
+  priv->avgh     = HTS221_AVGH_DEFAULT;
+  priv->odr      = HTS221_ODR_ONESHOT;
+  priv->interval = HTS221_PERIOD_1HZ;
+  nxmutex_init(&priv->lock);
+
+  ret = hts221_board_power(priv, true);
+  if (ret < 0)
+    {
+      snerr("ERROR: Failed to power on HTS221: %d\n", ret);
+      goto errout;
+    }
+
+  ret = hts221_read_reg(priv, HTS221_WHO_AM_I, &id);
+  if (ret < 0 || id != HTS221_DEVID)
+    {
+      snerr("ERROR: HTS221 not found: ret=%d id=0x%02x\n", ret, id);
+      ret = ret < 0 ? ret : -ENODEV;
+      goto errout_power;
+    }
+
+  ret = hts221_boot(priv);
+  if (ret < 0)
+    {
+      snerr("ERROR: Failed to boot HTS221: %d\n", ret);
+      goto errout_power;
+    }
+
+  ret = hts221_load_calibration(priv);
+  if (ret < 0)
+    {
+      snerr("ERROR: Failed to calibrate HTS221: %d\n", ret);
+      goto errout_power;
+    }
+
+  hts221_board_power(priv, false);
+
+  if (config != NULL && config->irq_attach != NULL)
+    {
+      if (config->irq_clear != NULL)
+        {
+          config->irq_clear(config);
+        }
+
+      ret = config->irq_attach(config, hts221_int_handler, priv);
+      if (ret < 0)
+        {
+          snerr("ERROR: Failed to attach HTS221 interrupt: %d\n", ret);
+          goto errout;
+        }
+
+      if (config->irq_enable != NULL)
+        {
+          config->irq_enable(config, false);
+        }
+    }
+
+  /* Register the temperature lower-half */
+
+  priv->temp.dev           = priv;
+  priv->temp.lower.ops     = &g_hts221_ops;
+  priv->temp.lower.type    = SENSOR_TYPE_AMBIENT_TEMPERATURE;
+  priv->temp.lower.nbuffer = 1;
+
+  ret = sensor_register(&priv->temp.lower, devno);
+  if (ret < 0)
+    {
+      snerr("ERROR: Failed to register HTS221 temperature: %d\n", ret);
+      goto errout;
+    }
+
+  /* Register the humidity lower-half */
+
+  priv->hum.dev           = priv;
+  priv->hum.lower.ops     = &g_hts221_ops;
+  priv->hum.lower.type    = SENSOR_TYPE_RELATIVE_HUMIDITY;
+  priv->hum.lower.nbuffer = 1;
+
+  ret = sensor_register(&priv->hum.lower, devno);
+  if (ret < 0)
+    {
+      snerr("ERROR: Failed to register HTS221 humidity: %d\n", ret);
+      sensor_unregister(&priv->temp.lower, devno);
+      goto errout;
+    }
+
+  sninfo("HTS221 registered\n");
+  return OK;
+
+errout_power:
+  hts221_board_power(priv, false);
+errout:
+  nxmutex_destroy(&priv->lock);
+  kmm_free(priv);
+  return ret;
+}
diff --git a/include/nuttx/sensors/hts221.h b/include/nuttx/sensors/hts221.h
index f06dfa668a4..5dbef91e6b6 100644
--- a/include/nuttx/sensors/hts221.h
+++ b/include/nuttx/sensors/hts221.h
@@ -27,14 +27,10 @@
  * Included Files
  ****************************************************************************/
 
-#include <nuttx/sensors/ioctl.h>
+#include <stdbool.h>
+#include <stdint.h>
 
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-#define HTS221_TEMPERATURE_PRECISION  100
-#define HTS221_HUMIDITY_PRECISION     10
+#include <nuttx/irq.h>
 
 /****************************************************************************
  * Public Types
@@ -42,108 +38,46 @@
 
 struct i2c_master_s; /* Forward reference */
 
-/* Number of temperature samples */
-
-typedef enum hts221_avrg_temp_e
-{
-  HTS221_AVGT2 = 0,
-  HTS221_AVGT4,
-  HTS221_AVGT8,
-  HTS221_AVGT16,              /* Default value */
-  HTS221_AVGT32,
-  HTS221_AVGT64,
-  HTS221_AVGT128,
-  HTS221_AVGT256
-} hts221_avrg_temp_t;
-
-/* Number of humidity samples */
-
-typedef enum hts221_avrg_humid_e
-{
-  HTS221_AVGH4 = 0,
-  HTS221_AVGH8,
-  HTS221_AVGH16,
-  HTS221_AVGH32,              /* Default value */
-  HTS221_AVGH64,
-  HTS221_AVGH128,
-  HTS221_AVGH256,
-  HTS221_AVGH512
-}hts221_avrg_humid_t;
-
-/* Output data rate configuration */
-
-typedef enum hts221_odr_e
-{
-  HTS221_ODR_ONESHOT = 0,
-  HTS221_ODR_1HZ,
-  HTS221_ODR_7HZ,
-  HTS221_ODR_12_5HZ
-} hts221_odr_t;
-
-/* Configuration structure */
-
-typedef struct hts221_settings_s
-{
-  hts221_avrg_temp_t temp_resol;      /* Temperature resolution. The more
-                                       * samples sensor takes, the more power
-                                       * it uses */
-  hts221_avrg_humid_t humid_resol;    /* Humidity resolution. The more
-                                       * samples sensor takes, the more power
-                                       * it uses */
-  hts221_odr_t odr;                   /* Output data rate */
-  bool is_bdu;                        /* If read operation is not faster than 
output
-                                       * operation, then this variable must be 
set to true */
-  bool is_data_rdy;                   /* Must be set to true, if interrupt 
needed.
-                                       * Default is 0, disabled */
-  bool is_high_edge;                  /* High or low interrupt signal from 
device.
-                                       * Default is high, 0 */
-  bool is_open_drain;                 /* Open drain or push-pull on data-ready 
pin.
-                                       * Default is push-pull, 0 */
-  bool is_boot;                       /* Refresh the content of the internal 
registers */
-} hts221_settings_t;
-
-/* Interrupt configuration data structure */
+/* Board interface: data-ready interrupt and power control.  All callbacks
+ * are optional.  Without irq_attach the driver polls the sensor.
+ */
 
 typedef struct hts221_config_s
 {
   int irq;
-  CODE int  (*irq_attach)(FAR struct hts221_config_s * state, xcpt_t isr,
+  CODE int  (*irq_attach)(FAR struct hts221_config_s *state, xcpt_t isr,
                           FAR void *arg);
   CODE void (*irq_enable)(FAR const struct hts221_config_s *state,
                           bool enable);
   CODE void (*irq_clear)(FAR const struct hts221_config_s *state);
   CODE int  (*set_power)(FAR const struct hts221_config_s *state, bool on);
+  bool drdy_active_low;         /* Data-ready pin polarity */
+  bool drdy_open_drain;         /* Data-ready pin open drain, else push-pull */
 } hts221_config_t;
 
-/* Raw data structure */
-
-typedef struct hts221_raw_data_s
-{
-  uint8_t humid_low_bits;
-  uint8_t humid_high_bits;
-  uint8_t temp_low_bits;
-  uint8_t temp_high_bits;
-} hts221_raw_data_t;
-
-typedef struct hts221_conv_data_s
-{
-  int temperature;
-  unsigned int humidity;
-} hts221_conv_data_t;
-
-/* Status register data */
-
-typedef struct hts221_status_s
-{
-  bool is_humid_ready;
-  bool is_temp_ready;
-} hts221_status_t;
-
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
 
-int hts221_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
-                    uint8_t addr, hts221_config_t * config);
+/****************************************************************************
+ * Name: hts221_register_uorb
+ *
+ * Description:
+ *   Register the HTS221 as UORB devices: sensor_ambient_temp<devno> and
+ *   sensor_humi<devno>.
+ *
+ * Input Parameters:
+ *   devno  - The device number, used to build the device path.
+ *   i2c    - The I2C bus driver instance.
+ *   addr   - The I2C address of the HTS221.
+ *   config - Board interface, or NULL.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int hts221_register_uorb(int devno, FAR struct i2c_master_s *i2c,
+                         uint8_t addr, FAR hts221_config_t *config);
 
 #endif /* __INCLUDE_NUTTX_SENSORS_HTS221_H */

Reply via email to