Pete Johanson
4 years ago
10 changed files with 542 additions and 0 deletions
@ -0,0 +1,17 @@ |
|||||||
|
description: | |
||||||
|
Sensor driver for the Alps en11 rotary encoder |
||||||
|
|
||||||
|
compatible: "alps,en11" |
||||||
|
|
||||||
|
properties: |
||||||
|
label: |
||||||
|
type: string |
||||||
|
required: true |
||||||
|
a-gpios: |
||||||
|
type: phandle-array |
||||||
|
required: true |
||||||
|
description: A pin for the encoder |
||||||
|
b-gpios: |
||||||
|
type: phandle-array |
||||||
|
required: true |
||||||
|
description: A pin for the encoder |
@ -0,0 +1,110 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Peter Johanson |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
#define DT_DRV_COMPAT alps_en11 |
||||||
|
|
||||||
|
#include <device.h> |
||||||
|
#include <drivers/gpio.h> |
||||||
|
#include <sys/util.h> |
||||||
|
#include <kernel.h> |
||||||
|
#include <drivers/sensor.h> |
||||||
|
#include <sys/__assert.h> |
||||||
|
#include <logging/log.h> |
||||||
|
|
||||||
|
#include "en11.h" |
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(EN11, CONFIG_SENSOR_LOG_LEVEL); |
||||||
|
|
||||||
|
static int en11_sample_fetch(struct device *dev, enum sensor_channel chan) |
||||||
|
{ |
||||||
|
struct en11_data *drv_data = dev->driver_data; |
||||||
|
u16_t val; |
||||||
|
|
||||||
|
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP); |
||||||
|
|
||||||
|
// if (en11_reg_read(drv_data, EN11_REG_TOBJ, &val) < 0) {
|
||||||
|
// return -EIO;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (val & EN11_DATA_INVALID_BIT) {
|
||||||
|
// return -EIO;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// drv_data->sample = arithmetic_shift_right((s16_t)val, 2);
|
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static int en11_channel_get(struct device *dev, |
||||||
|
enum sensor_channel chan, |
||||||
|
struct sensor_value *val) |
||||||
|
{ |
||||||
|
struct en11_data *drv_data = dev->driver_data; |
||||||
|
// s32_t uval;
|
||||||
|
|
||||||
|
// if (chan != SENSOR_CHAN_AMBIENT_TEMP) {
|
||||||
|
// return -ENOTSUP;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// uval = (s32_t)drv_data->sample * EN11_TEMP_SCALE;
|
||||||
|
// val->val1 = uval / 1000000;
|
||||||
|
// val->val2 = uval % 1000000;
|
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
static const struct sensor_driver_api en11_driver_api = { |
||||||
|
#ifdef CONFIG_EN11_TRIGGER |
||||||
|
.trigger_set = en11_trigger_set, |
||||||
|
#endif |
||||||
|
.sample_fetch = en11_sample_fetch, |
||||||
|
.channel_get = en11_channel_get, |
||||||
|
}; |
||||||
|
|
||||||
|
int en11_init(struct device *dev) |
||||||
|
{ |
||||||
|
struct en11_data *drv_data = dev->driver_data; |
||||||
|
const struct en11_config *drv_cfg = dev->config_info; |
||||||
|
|
||||||
|
LOG_DBG(""); |
||||||
|
|
||||||
|
drv_data->a = device_get_binding(drv_cfg->a_label); |
||||||
|
if (drv_data->a == NULL) { |
||||||
|
LOG_ERR("Failed to get pointer to A GPIO device"); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
drv_data->b = device_get_binding(drv_cfg->b_label); |
||||||
|
if (drv_data->b == NULL) { |
||||||
|
LOG_ERR("Failed to get pointer to B GPIO device"); |
||||||
|
return -EINVAL; |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef CONFIG_EN11_TRIGGER |
||||||
|
if (en11_init_interrupt(dev) < 0) { |
||||||
|
LOG_DBG("Failed to initialize interrupt!"); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
struct en11_data en11_data; |
||||||
|
|
||||||
|
const struct en11_config en11_cfg = { |
||||||
|
.a_label = DT_INST_GPIO_LABEL(0, a_gpios), |
||||||
|
.a_pin = DT_INST_GPIO_PIN(0, a_gpios), |
||||||
|
.a_flags = DT_INST_GPIO_FLAGS(0, a_gpios), |
||||||
|
.b_label = DT_INST_GPIO_LABEL(0, b_gpios), |
||||||
|
.b_pin = DT_INST_GPIO_PIN(0, b_gpios), |
||||||
|
.b_flags = DT_INST_GPIO_FLAGS(0, b_gpios), |
||||||
|
}; |
||||||
|
|
||||||
|
DEVICE_AND_API_INIT(en11, DT_INST_LABEL(0), en11_init, |
||||||
|
&en11_data, |
||||||
|
&en11_cfg, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, |
||||||
|
&en11_driver_api); |
@ -0,0 +1,61 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Peter Johanson |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <device.h> |
||||||
|
#include <drivers/gpio.h> |
||||||
|
#include <sys/util.h> |
||||||
|
|
||||||
|
struct en11_config { |
||||||
|
const char *a_label; |
||||||
|
const u8_t a_pin; |
||||||
|
const u8_t a_flags; |
||||||
|
|
||||||
|
const char *b_label; |
||||||
|
const u8_t b_pin; |
||||||
|
const u8_t b_flags; |
||||||
|
}; |
||||||
|
|
||||||
|
enum en11_pin_state { |
||||||
|
EN11_A_PIN_STATE, |
||||||
|
EN11_B_PIN_STATE |
||||||
|
}; |
||||||
|
|
||||||
|
struct en11_data { |
||||||
|
struct device *a; |
||||||
|
struct device *b; |
||||||
|
u8_t ab_state; |
||||||
|
s16_t sample; |
||||||
|
|
||||||
|
#ifdef CONFIG_EN11_TRIGGER |
||||||
|
struct device *gpio; |
||||||
|
struct gpio_callback a_gpio_cb; |
||||||
|
struct gpio_callback b_gpio_cb; |
||||||
|
struct device *dev; |
||||||
|
|
||||||
|
sensor_trigger_handler_t handler; |
||||||
|
struct sensor_trigger trigger; |
||||||
|
|
||||||
|
#if defined(CONFIG_EN11_TRIGGER_OWN_THREAD) |
||||||
|
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_EN11_THREAD_STACK_SIZE); |
||||||
|
struct k_sem gpio_sem; |
||||||
|
struct k_thread thread; |
||||||
|
#elif defined(CONFIG_EN11_TRIGGER_GLOBAL_THREAD) |
||||||
|
struct k_work work; |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif /* CONFIG_EN11_TRIGGER */ |
||||||
|
}; |
||||||
|
|
||||||
|
#ifdef CONFIG_EN11_TRIGGER |
||||||
|
|
||||||
|
int en11_trigger_set(struct device *dev, |
||||||
|
const struct sensor_trigger *trig, |
||||||
|
sensor_trigger_handler_t handler); |
||||||
|
|
||||||
|
int en11_init_interrupt(struct device *dev); |
||||||
|
#endif |
@ -0,0 +1,210 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Intel Corporation |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
#define DT_DRV_COMPAT alps_en11 |
||||||
|
|
||||||
|
#include <device.h> |
||||||
|
#include <drivers/gpio.h> |
||||||
|
#include <sys/util.h> |
||||||
|
#include <kernel.h> |
||||||
|
#include <drivers/sensor.h> |
||||||
|
|
||||||
|
#include "en11.h" |
||||||
|
|
||||||
|
extern struct en11_data en11_driver; |
||||||
|
|
||||||
|
#include <logging/log.h> |
||||||
|
LOG_MODULE_DECLARE(EN11, CONFIG_SENSOR_LOG_LEVEL); |
||||||
|
|
||||||
|
static inline void setup_int(struct device *dev, |
||||||
|
bool enable) |
||||||
|
{ |
||||||
|
struct en11_data *data = dev->driver_data; |
||||||
|
const struct en11_config *cfg = dev->config_info; |
||||||
|
|
||||||
|
LOG_DBG("enabled %s", (enable ? "true" : "false")); |
||||||
|
|
||||||
|
if (gpio_pin_interrupt_configure(data->a, |
||||||
|
cfg->a_pin, |
||||||
|
enable |
||||||
|
? GPIO_INT_EDGE_BOTH |
||||||
|
: GPIO_INT_DISABLE)) { |
||||||
|
LOG_WRN("Unable to set A pin GPIO interrupt"); |
||||||
|
} |
||||||
|
|
||||||
|
if (gpio_pin_interrupt_configure(data->b, |
||||||
|
cfg->b_pin, |
||||||
|
enable |
||||||
|
? GPIO_INT_EDGE_BOTH |
||||||
|
: GPIO_INT_DISABLE)) { |
||||||
|
LOG_WRN("Unable to set A pin GPIO interrupt"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void en11_a_gpio_callback(struct device *dev, |
||||||
|
struct gpio_callback *cb, u32_t pins) |
||||||
|
{ |
||||||
|
struct en11_data *drv_data = |
||||||
|
CONTAINER_OF(cb, struct en11_data, a_gpio_cb); |
||||||
|
|
||||||
|
LOG_DBG(""); |
||||||
|
|
||||||
|
setup_int(drv_data->dev, false); |
||||||
|
|
||||||
|
#if defined(CONFIG_EN11_TRIGGER_OWN_THREAD) |
||||||
|
k_sem_give(&drv_data->gpio_sem); |
||||||
|
#elif defined(CONFIG_EN11_TRIGGER_GLOBAL_THREAD) |
||||||
|
k_work_submit(&drv_data->work); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
static void en11_b_gpio_callback(struct device *dev, |
||||||
|
struct gpio_callback *cb, u32_t pins) |
||||||
|
{ |
||||||
|
struct en11_data *drv_data = |
||||||
|
CONTAINER_OF(cb, struct en11_data, b_gpio_cb); |
||||||
|
|
||||||
|
LOG_DBG(""); |
||||||
|
|
||||||
|
setup_int(drv_data->dev, false); |
||||||
|
|
||||||
|
#if defined(CONFIG_EN11_TRIGGER_OWN_THREAD) |
||||||
|
k_sem_give(&drv_data->gpio_sem); |
||||||
|
#elif defined(CONFIG_EN11_TRIGGER_GLOBAL_THREAD) |
||||||
|
k_work_submit(&drv_data->work); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
static void en11_thread_cb(void *arg) |
||||||
|
{ |
||||||
|
struct device *dev = arg; |
||||||
|
struct en11_data *drv_data = dev->driver_data; |
||||||
|
const struct en11_config *cfg = dev->config_info; |
||||||
|
u16_t status; |
||||||
|
|
||||||
|
// gpio_pin_get(drv_data->a, cfg->a_pin)
|
||||||
|
|
||||||
|
// if (en11_reg_read(drv_data, EN11_REG_STATUS, &status) < 0) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (status & EN11_DATA_READY_INT_BIT &&
|
||||||
|
// drv_data->drdy_handler != NULL) {
|
||||||
|
// drv_data->drdy_handler(dev, &drv_data->drdy_trigger);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (status & EN11_TOBJ_TH_INT_BITS &&
|
||||||
|
// drv_data->th_handler != NULL) {
|
||||||
|
// drv_data->th_handler(dev, &drv_data->th_trigger);
|
||||||
|
// }
|
||||||
|
|
||||||
|
setup_int(dev, true); |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef CONFIG_EN11_TRIGGER_OWN_THREAD |
||||||
|
static void en11_thread(int dev_ptr, int unused) |
||||||
|
{ |
||||||
|
struct device *dev = INT_TO_POINTER(dev_ptr); |
||||||
|
struct en11_data *drv_data = dev->driver_data; |
||||||
|
|
||||||
|
ARG_UNUSED(unused); |
||||||
|
|
||||||
|
while (1) { |
||||||
|
k_sem_take(&drv_data->gpio_sem, K_FOREVER); |
||||||
|
en11_thread_cb(dev); |
||||||
|
} |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef CONFIG_EN11_TRIGGER_GLOBAL_THREAD |
||||||
|
static void en11_work_cb(struct k_work *work) |
||||||
|
{ |
||||||
|
struct en11_data *drv_data = |
||||||
|
CONTAINER_OF(work, struct en11_data, work); |
||||||
|
|
||||||
|
LOG_DBG(""); |
||||||
|
|
||||||
|
en11_thread_cb(drv_data->dev); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
int en11_trigger_set(struct device *dev, |
||||||
|
const struct sensor_trigger *trig, |
||||||
|
sensor_trigger_handler_t handler) |
||||||
|
{ |
||||||
|
struct en11_data *drv_data = dev->driver_data; |
||||||
|
|
||||||
|
setup_int(dev, false); |
||||||
|
|
||||||
|
drv_data->trigger = *trig; |
||||||
|
drv_data->handler = handler; |
||||||
|
|
||||||
|
setup_int(dev, true); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
int en11_init_interrupt(struct device *dev) |
||||||
|
{ |
||||||
|
struct en11_data *drv_data = dev->driver_data; |
||||||
|
const struct en11_config *drv_cfg = dev->config_info; |
||||||
|
|
||||||
|
/* setup gpio interrupt */ |
||||||
|
|
||||||
|
LOG_DBG("A: %s %d B: %s %d", drv_cfg->a_label, drv_cfg->a_pin, drv_cfg->b_label, drv_cfg->b_pin); |
||||||
|
|
||||||
|
gpio_pin_configure(drv_data->a, drv_cfg->a_pin, |
||||||
|
drv_cfg->a_flags |
||||||
|
| GPIO_INPUT); |
||||||
|
|
||||||
|
if (gpio_pin_set(drv_data->a, drv_cfg->a_pin, 1)) { |
||||||
|
LOG_DBG("Failed to set A active!"); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
|
||||||
|
gpio_init_callback(&drv_data->a_gpio_cb, |
||||||
|
en11_a_gpio_callback, |
||||||
|
BIT(drv_cfg->a_pin)); |
||||||
|
|
||||||
|
if (gpio_add_callback(drv_data->a, &drv_data->a_gpio_cb) < 0) { |
||||||
|
LOG_DBG("Failed to set A callback!"); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
|
||||||
|
gpio_pin_configure(drv_data->b, drv_cfg->b_pin, |
||||||
|
drv_cfg->b_flags |
||||||
|
| GPIO_INPUT); |
||||||
|
|
||||||
|
if (gpio_pin_set(drv_data->b, drv_cfg->b_pin, 1)) { |
||||||
|
LOG_DBG("Failed to set B active!"); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
|
||||||
|
gpio_init_callback(&drv_data->b_gpio_cb, |
||||||
|
en11_b_gpio_callback, |
||||||
|
BIT(drv_cfg->b_pin)); |
||||||
|
|
||||||
|
if (gpio_add_callback(drv_data->b, &drv_data->b_gpio_cb) < 0) { |
||||||
|
LOG_DBG("Failed to set B callback!"); |
||||||
|
return -EIO; |
||||||
|
} |
||||||
|
|
||||||
|
LOG_DBG("A Pin? %d, B Pin? %d", gpio_pin_get(drv_data->a, drv_cfg->a_pin), gpio_pin_get(drv_data->b, drv_cfg->b_pin)); |
||||||
|
|
||||||
|
#if defined(CONFIG_EN11_TRIGGER_OWN_THREAD) |
||||||
|
k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX); |
||||||
|
|
||||||
|
k_thread_create(&drv_data->thread, drv_data->thread_stack, |
||||||
|
CONFIG_EN11_THREAD_STACK_SIZE, |
||||||
|
(k_thread_entry_t)en11_thread, dev, |
||||||
|
0, NULL, K_PRIO_COOP(CONFIG_EN11_THREAD_PRIORITY), |
||||||
|
0, K_NO_WAIT); |
||||||
|
#elif defined(CONFIG_EN11_TRIGGER_GLOBAL_THREAD) |
||||||
|
drv_data->work.handler = en11_work_cb; |
||||||
|
#endif |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
# SPDX-License-Identifier: Apache-2.0 |
||||||
|
|
||||||
|
zephyr_library() |
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_EN11 en11.c) |
||||||
|
zephyr_library_sources_ifdef(CONFIG_EN11_TRIGGER en11_trigger.c) |
@ -0,0 +1,52 @@ |
|||||||
|
# EN11 incremental encoder sensor configuration options |
||||||
|
|
||||||
|
# Copyright (c) 2020 Peter Johanson |
||||||
|
# SPDX-License-Identifier: MIT |
||||||
|
|
||||||
|
menuconfig EN11 |
||||||
|
bool "EN11 Incremental Encoder Sensor" |
||||||
|
depends on GPIO |
||||||
|
help |
||||||
|
Enable driver for EN11 incremental encoder sensors. |
||||||
|
|
||||||
|
if EN11 |
||||||
|
|
||||||
|
choice |
||||||
|
prompt "Trigger mode" |
||||||
|
default EN11_TRIGGER_NONE |
||||||
|
help |
||||||
|
Specify the type of triggering to be used by the driver. |
||||||
|
|
||||||
|
config EN11_TRIGGER_NONE |
||||||
|
bool "No trigger" |
||||||
|
|
||||||
|
config EN11_TRIGGER_GLOBAL_THREAD |
||||||
|
bool "Use global thread" |
||||||
|
depends on GPIO |
||||||
|
select EN11_TRIGGER |
||||||
|
|
||||||
|
config EN11_TRIGGER_OWN_THREAD |
||||||
|
bool "Use own thread" |
||||||
|
depends on GPIO |
||||||
|
select EN11_TRIGGER |
||||||
|
|
||||||
|
endchoice |
||||||
|
|
||||||
|
config EN11_TRIGGER |
||||||
|
bool |
||||||
|
|
||||||
|
config EN11_THREAD_PRIORITY |
||||||
|
int "Thread priority" |
||||||
|
depends on EN11_TRIGGER_OWN_THREAD |
||||||
|
default 10 |
||||||
|
help |
||||||
|
Priority of thread used by the driver to handle interrupts. |
||||||
|
|
||||||
|
config EN11_THREAD_STACK_SIZE |
||||||
|
int "Thread stack size" |
||||||
|
depends on EN11_TRIGGER_OWN_THREAD |
||||||
|
default 1024 |
||||||
|
help |
||||||
|
Stack size of thread used by the driver to handle interrupts. |
||||||
|
|
||||||
|
endif # EN11 |
Loading…
Reference in new issue