drivers: sensor: Add Atmel SAM QDEC (TC) Driver

Tested on Atmel SMART SAM E70 Xplained board

Origin: Original

Signed-off-by: Piotr Mienkowski <piotr.mienkowski@gmail.com>
This commit is contained in:
Piotr Mienkowski 2021-03-13 22:24:58 +01:00 committed by Carles Cufí
commit f5163e2ce2
5 changed files with 164 additions and 0 deletions

View file

@ -63,6 +63,7 @@ add_subdirectory_ifdef(CONFIG_MS5837 ms5837)
add_subdirectory_ifdef(CONFIG_OPT3001 opt3001)
add_subdirectory_ifdef(CONFIG_PMS7003 pms7003)
add_subdirectory_ifdef(CONFIG_QDEC_NRFX qdec_nrfx)
add_subdirectory_ifdef(CONFIG_QDEC_SAM qdec_sam)
add_subdirectory_ifdef(CONFIG_TEMP_NRF5 nrf5)
add_subdirectory_ifdef(CONFIG_SHT3XD sht3xd)
add_subdirectory_ifdef(CONFIG_SI7006 si7006)

View file

@ -168,6 +168,8 @@ source "drivers/sensor/pms7003/Kconfig"
source "drivers/sensor/qdec_nrfx/Kconfig"
source "drivers/sensor/qdec_sam/Kconfig"
source "drivers/sensor/sht3xd/Kconfig"
source "drivers/sensor/si7006/Kconfig"

View file

@ -0,0 +1,7 @@
# Copyright (c) 2021, Piotr Mienkowski
#
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources(qdec_sam.c)

View file

@ -0,0 +1,12 @@
# Atmel SAM MCU family Quadrature Decoder (TC) driver configuration options
#
# Copyright (c) 2021, Piotr Mienkowski
# SPDX-License-Identifier: Apache-2.0
#
config QDEC_SAM
bool "Atmel SAM QDEC driver"
depends on SOC_FAMILY_SAM
default n
help
Atmel SAM MCU family Quadrature Decoder (TC) driver.

View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2021, Piotr Mienkowski
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT atmel_sam_tc
/** @file
* @brief Atmel SAM MCU family Quadrature Decoder (QDEC/TC) driver.
*/
#include <errno.h>
#include <sys/__assert.h>
#include <sys/util.h>
#include <device.h>
#include <init.h>
#include <soc.h>
#include <drivers/sensor.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(qdec_sam, CONFIG_SENSOR_LOG_LEVEL);
/* Device constant configuration parameters */
struct qdec_sam_dev_cfg {
Tc *regs;
const struct soc_gpio_pin *pin_list;
uint8_t pin_list_size;
uint8_t periph_id[TCCHANNEL_NUMBER];
};
/* Device run time data */
struct qdec_sam_dev_data {
uint16_t position;
};
#define DEV_NAME(dev) ((dev)->name)
#define DEV_CFG(dev) \
((const struct qdec_sam_dev_cfg *const)(dev)->config)
#define DEV_DATA(dev) \
((struct qdec_sam_dev_data *const)(dev)->data)
static int qdec_sam_fetch(const struct device *dev, enum sensor_channel chan)
{
const struct qdec_sam_dev_cfg *const dev_cfg = DEV_CFG(dev);
struct qdec_sam_dev_data *const dev_data = DEV_DATA(dev);
Tc *const tc = dev_cfg->regs;
TcChannel *tc_ch0 = &tc->TC_CHANNEL[0];
/* Read position register content */
dev_data->position = tc_ch0->TC_CV;
return 0;
}
static int qdec_sam_get(const struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
struct qdec_sam_dev_data *const dev_data = DEV_DATA(dev);
if (chan == SENSOR_CHAN_ROTATION) {
val->val1 = dev_data->position;
val->val2 = 0;
} else {
return -ENOTSUP;
}
return 0;
}
static void qdec_sam_start(Tc *const tc)
{
TcChannel *tc_ch0 = &tc->TC_CHANNEL[0];
/* Enable Channel 0 Clock and reset counter*/
tc_ch0->TC_CCR = TC_CCR_CLKEN
| TC_CCR_SWTRG;
}
static void qdec_sam_configure(const struct device *dev)
{
const struct qdec_sam_dev_cfg *const dev_cfg = DEV_CFG(dev);
Tc *const tc = dev_cfg->regs;
TcChannel *tc_ch0 = &tc->TC_CHANNEL[0];
/* Clock, Trigger Edge, Trigger and Mode Selection */
tc_ch0->TC_CMR = TC_CMR_TCCLKS_XC0
| TC_CMR_ETRGEDG_RISING
| TC_CMR_ABETRG;
/* Enable QDEC in Position Mode*/
tc->TC_BMR = TC_BMR_QDEN
| TC_BMR_POSEN
| TC_BMR_EDGPHA
| TC_BMR_MAXFILT(1);
qdec_sam_start(tc);
}
static int qdec_sam_initialize(const struct device *dev)
{
__ASSERT_NO_MSG(dev != NULL);
const struct qdec_sam_dev_cfg *const dev_cfg = DEV_CFG(dev);
/* Connect pins to the peripheral */
soc_gpio_list_configure(dev_cfg->pin_list, dev_cfg->pin_list_size);
for (int i = 0; i < ARRAY_SIZE(dev_cfg->periph_id); i++) {
/* Enable module's clock */
soc_pmc_peripheral_enable(dev_cfg->periph_id[i]);
}
qdec_sam_configure(dev);
LOG_INF("Device %s initialized", DEV_NAME(dev));
return 0;
}
static const struct sensor_driver_api qdec_sam_driver_api = {
.sample_fetch = qdec_sam_fetch,
.channel_get = qdec_sam_get,
};
#define QDEC_SAM_INIT(n) \
static const struct soc_gpio_pin pins_tc##n[] = ATMEL_SAM_DT_PINS(n); \
\
static const struct qdec_sam_dev_cfg qdec##n##_sam_config = { \
.regs = (Tc *)DT_INST_REG_ADDR(n), \
.pin_list = pins_tc##n, \
.pin_list_size = ARRAY_SIZE(pins_tc##n), \
.periph_id = DT_INST_PROP(n, peripheral_id), \
}; \
\
static struct qdec_sam_dev_data qdec##n##_sam_data; \
\
DEVICE_DT_INST_DEFINE(n, qdec_sam_initialize, device_pm_control_nop, \
&qdec##n##_sam_data, &qdec##n##_sam_config, \
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
&qdec_sam_driver_api);
DT_INST_FOREACH_STATUS_OKAY(QDEC_SAM_INIT)