From b30f5e146dd2d57d3ffaf55b1fa3aa4456b7a6e9 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Wed, 18 Aug 2021 13:55:44 +0200 Subject: [PATCH] drivers/sensors: add an upper half 3-phase Hall effect sensor driver --- drivers/sensors/Kconfig | 4 + drivers/sensors/Make.defs | 6 + drivers/sensors/hall3ph.c | 356 ++++++++++++++++++++++++++++++++ include/nuttx/sensors/hall3ph.h | 138 +++++++++++++ include/nuttx/sensors/ioctl.h | 4 + 5 files changed, 508 insertions(+) create mode 100644 drivers/sensors/hall3ph.c create mode 100644 include/nuttx/sensors/hall3ph.h diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index a6ee116d8f..3aca00f403 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -927,6 +927,10 @@ config SENSORS_QENCODER bool "Qencoder" default n +config SENSORS_HALL3PHASE + bool "3-phase Hall effect sensor" + default n + config SENSORS_VEML6070 bool "Vishay VEML6070 UV-A Light Sensor support" default n diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index 6c52e22cb3..b9ade92c61 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -280,6 +280,12 @@ ifeq ($(CONFIG_SENSORS_QENCODER),y) CSRCS += qencoder.c endif +# 3-phase Hall effect sensor upper half + +ifeq ($(CONFIG_SENSORS_HALL3PHASE),y) + CSRCS += hall3ph.c +endif + # Vishay VEML6070 ifeq ($(CONFIG_SENSORS_VEML6070),y) diff --git a/drivers/sensors/hall3ph.c b/drivers/sensors/hall3ph.c new file mode 100644 index 0000000000..52cc973ba1 --- /dev/null +++ b/drivers/sensors/hall3ph.c @@ -0,0 +1,356 @@ +/**************************************************************************** + * drivers/sensors/hall3ph.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +/* This structure describes the state of the upper half driver */ + +struct hall3_upperhalf_s +{ + uint8_t crefs; + sem_t exclsem; + FAR struct hall3_lowerhalf_s *lower; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int hall3_open(FAR struct file *filep); +static int hall3_close(FAR struct file *filep); +static ssize_t hall3_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t hall3_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int hall3_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_hall3ops = +{ + hall3_open, /* open */ + hall3_close, /* close */ + hall3_read, /* read */ + hall3_write, /* write */ + NULL , /* seek */ + hall3_ioctl, /* ioctl */ + NULL /* poll */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hall3_open + * + * Description: + * This function is called whenever the hall device is opened. + * + ****************************************************************************/ + +static int hall3_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct hall3_upperhalf_s *upper = inode->i_private; + uint8_t tmp; + int ret; + + sninfo("crefs: %d\n", upper->crefs); + + /* Get exclusive access to the device structures */ + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + goto errout; + } + + /* Increment the count of references to the device. If this is the first + * time that the driver has been opened for this device, then initialize + * the device. + */ + + tmp = upper->crefs + 1; + if (tmp == 0) + { + /* More than 255 opens; uint8_t overflows to zero */ + + ret = -EMFILE; + goto errout_with_sem; + } + + /* Check if this is the first time that the driver has been opened. */ + + if (tmp == 1) + { + FAR struct hall3_lowerhalf_s *lower = upper->lower; + + /* Yes.. perform one time hardware initialization. */ + + DEBUGASSERT(lower->ops->setup != NULL); + sninfo("calling setup\n"); + + ret = lower->ops->setup(lower); + if (ret < 0) + { + goto errout_with_sem; + } + } + + /* Save the new open count on success */ + + upper->crefs = tmp; + ret = OK; + +errout_with_sem: + nxsem_post(&upper->exclsem); + +errout: + return ret; +} + +/**************************************************************************** + * Name: hall3_close + * + * Description: + * This function is called when the hall device is closed. + * + ****************************************************************************/ + +static int hall3_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct hall3_upperhalf_s *upper = inode->i_private; + int ret; + + sninfo("crefs: %d\n", upper->crefs); + + /* Get exclusive access to the device structures */ + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + goto errout; + } + + /* Decrement the references to the driver. If the reference count will + * decrement to 0, then uninitialize the driver. + */ + + if (upper->crefs > 1) + { + upper->crefs--; + } + else + { + FAR struct hall3_lowerhalf_s *lower = upper->lower; + + /* There are no more references to the port */ + + upper->crefs = 0; + + /* Disable the hall device */ + + DEBUGASSERT(lower->ops->shutdown != NULL); + sninfo("calling shutdown\n"); + + lower->ops->shutdown(lower); + } + + nxsem_post(&upper->exclsem); + ret = OK; + +errout: + return ret; +} + +/**************************************************************************** + * Name: hall3_read + * + * Description: + * A dummy read method. This is provided only to satisfy the VFS layer. + * + ****************************************************************************/ + +static ssize_t hall3_read(FAR struct file *filep, + FAR char *buffer, + size_t buflen) +{ + /* Return zero -- usually meaning end-of-file */ + + return 0; +} + +/**************************************************************************** + * Name: hall3_write + * + * Description: + * A dummy write method. This is provided only to satisfy the VFS layer. + * + ****************************************************************************/ + +static ssize_t hall3_write(FAR struct file *filep, + FAR const char *buffer, + size_t buflen) +{ + /* Return a failure */ + + return -EPERM; +} + +/**************************************************************************** + * Name: hall3_ioctl + * + * Description: + * The standard ioctl method. + * This is where ALL of the hall work is done. + * + ****************************************************************************/ + +static int hall3_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct hall3_upperhalf_s *upper; + FAR struct hall3_lowerhalf_s *lower; + int ret; + + sninfo("cmd: %d arg: %ld\n", cmd, arg); + upper = inode->i_private; + DEBUGASSERT(upper != NULL); + lower = upper->lower; + DEBUGASSERT(lower != NULL); + + /* Get exclusive access to the device structures */ + + ret = nxsem_wait(&upper->exclsem); + if (ret < 0) + { + return ret; + } + + /* Handle built-in ioctl commands */ + + switch (cmd) + { + /* SNIOC_GET_POSITION - Get the current position from the Hall sensor. + * Argument: uint8_t pointer to the location to return the position. + */ + + case SNIOC_GET_POSITION: + { + FAR uint8_t *ptr = (FAR uint8_t *)((uintptr_t)arg); + DEBUGASSERT(lower->ops->position != NULL && ptr); + ret = lower->ops->position(lower, ptr); + } + break; + + default: + { + ret = -ENOTTY; + } + break; + } + + nxsem_post(&upper->exclsem); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hall3_register + * + * Description: + * Register the 3-phase Hall effect sensor lower half device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/hall0" + * lower - An instance of the lower half interface + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. The following + * possible error values may be returned (most are returned by + * register_driver()): + * + * EINVAL - 'path' is invalid for this operation + * EEXIST - An inode already exists at 'path' + * ENOMEM - Failed to allocate in-memory resources for the operation + * + ****************************************************************************/ + +int hall3_register(FAR const char *devpath, + FAR struct hall3_lowerhalf_s *lower) +{ + FAR struct hall3_upperhalf_s *upper = NULL; + + /* Allocate the upper-half data structure */ + + upper = (FAR struct hall3_upperhalf_s *) + kmm_zalloc(sizeof(struct hall3_upperhalf_s)); + if (upper == NULL) + { + snerr("ERROR: Allocation failed\n"); + return -ENOMEM; + } + + /* Initialize the hall 3-phase sensor device structure + * (it was already zeroed by kmm_zalloc()) + */ + + nxsem_init(&upper->exclsem, 0, 1); + upper->lower = lower; + + /* Register the Hall effect sensor device */ + + sninfo("Registering %s\n", devpath); + return register_driver(devpath, &g_hall3ops, 0666, upper); +} diff --git a/include/nuttx/sensors/hall3ph.h b/include/nuttx/sensors/hall3ph.h new file mode 100644 index 0000000000..d4dc2ddfaa --- /dev/null +++ b/include/nuttx/sensors/hall3ph.h @@ -0,0 +1,138 @@ +/**************************************************************************** + * include/nuttx/sensors/hall3ph.h + * + * 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_SENSORS_HALL3PH_H +#define __INCLUDE_NUTTX_SENSORS_HALL3PH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* 120-degree Hall effect sensors positions */ + +enum hall3_120deg_position_e +{ + HALL3_120DEG_POS_1 = 0b001, + HALL3_120DEG_POS_2 = 0b011, + HALL3_120DEG_POS_3 = 0b010, + HALL3_120DEG_POS_4 = 0b110, + HALL3_120DEG_POS_5 = 0b100, + HALL3_120DEG_POS_6 = 0b101 +}; + +/* 60-degree Hall effect sensors postions */ + +enum hall3_60deg_position_e +{ + HALL3_60DEG_POS_1 = 0b000, + HALL3_60DEG_POS_2 = 0b001, + HALL3_60DEG_POS_3 = 0b101, + HALL3_60DEG_POS_4 = 0b111, + HALL3_60DEG_POS_5 = 0b110, + HALL3_60DEG_POS_6 = 0b010 +}; + +/* This structure provides the "lower-half" driver operations available to + * the "upper-half" driver. + */ + +struct hall3_lowerhalf_s; +struct hall3_ops_s +{ + /* Configure the 3-phase Hall effect sensor device */ + + CODE int (*setup)(FAR struct hall3_lowerhalf_s *lower); + + /* Disable the 3-phase Hall effect sensor device */ + + CODE int (*shutdown)(FAR struct hall3_lowerhalf_s *lower); + + /* Return the current 3-phase Hall effect sensor position */ + + CODE int (*position)(FAR struct hall3_lowerhalf_s *lower, + FAR uint8_t *pos); +}; + +/* This structure provides the publicly visible representation of the + * "lower-half" driver state structure. "lower half" drivers will have an + * internal structure definition that will be cast-compatible with this + * structure definitions. + */ + +struct hall3_lowerhalf_s +{ + FAR const struct hall3_ops_s *ops; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: hall3_register + * + * Description: + * Register the 3-phase Hall effect sensor lower half device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/hall0" + * lower - An instance of the lower half interface + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. The following + * possible error values may be returned (most are returned by + * register_driver()): + * + * EINVAL - 'path' is invalid for this operation + * EEXIST - An inode already exists at 'path' + * ENOMEM - Failed to allocate in-memory resources for the operation + * + ****************************************************************************/ + +int hall3_register(FAR const char *devpath, + FAR struct hall3_lowerhalf_s *lower); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_SENSORS_HALL3PH_H */ diff --git a/include/nuttx/sensors/ioctl.h b/include/nuttx/sensors/ioctl.h index a24e169c4a..8e1f8c3289 100644 --- a/include/nuttx/sensors/ioctl.h +++ b/include/nuttx/sensors/ioctl.h @@ -284,4 +284,8 @@ #define SNIOC_SET_BUFFER_NUMBER _SNIOC(0x0084) +/* IOCTL commands unique to the Hall effect sensor */ + +#define SNIOC_GET_POSITION _SNIOC(0x0085) + #endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */