blob: d7493109e472282d741bcd8a4f1c2f226ee9f697 [file] [log] [blame]
/*
* Copyright (c) 2024 ENE Technology Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ene_kb1200_tach
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/sensor.h>
#include <reg/tacho.h>
/* Device config */
struct tach_kb1200_config {
/* tachometer controller base address */
struct tacho_regs *tacho;
/* number of pulses (holes) per round of tachometer's input (encoder) */
int pulses_per_round;
/* sampling clock timing of tachometer (us) */
int sample_time_us;
const struct pinctrl_dev_config *pcfg;
};
/* Driver data */
struct tach_kb1200_data {
/* Captured counts of tachometer */
uint32_t capture;
};
/* TACH local functions */
static int tach_kb1200_configure(const struct device *dev)
{
const struct tach_kb1200_config *const config = dev->config;
uint8_t sample_us = 0;
/* Configure clock module and its frequency of tachometer */
switch (config->sample_time_us) {
case 2:
sample_us = TACHO_MONITOR_CLK_2US;
break;
case 8:
sample_us = TACHO_MONITOR_CLK_8US;
break;
case 16:
sample_us = TACHO_MONITOR_CLK_16US;
break;
case 64:
sample_us = TACHO_MONITOR_CLK_64US;
break;
default:
return -ENOTSUP;
}
config->tacho->TACHOCFG = (sample_us << 4) | TACHO_FUNCTION_ENABLE;
return 0;
}
/* TACH api functions */
int tach_kb1200_sample_fetch(const struct device *dev, enum sensor_channel chan)
{
ARG_UNUSED(chan);
struct tach_kb1200_data *const data = dev->data;
const struct tach_kb1200_config *const config = dev->config;
/* Check tachometer timeout flag*/
if (config->tacho->TACHOPF & TACHO_TIMEOUT_EVENT) {
/* Clear timeout flags and update flag */
config->tacho->TACHOPF = (TACHO_TIMEOUT_EVENT | TACHO_UPDATE_EVENT);
data->capture = 0;
return 0;
}
/* Check tachometer update flag is set */
if (config->tacho->TACHOPF & TACHO_UPDATE_EVENT) {
/* Clear pending flags */
config->tacho->TACHOPF = TACHO_UPDATE_EVENT;
/* Save captured count */
data->capture = config->tacho->TACHOCV & TACHO_CNT_MAX_VALUE;
}
return 0;
}
static int tach_kb1200_channel_get(const struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
struct tach_kb1200_data *const data = dev->data;
const struct tach_kb1200_config *const config = dev->config;
if (chan != SENSOR_CHAN_RPM) {
return -ENOTSUP;
}
if (data->capture > 0) {
/*
* RPM = (60000000/t) / n
* t: One Pulses length(us) = sample_time_us * cnt
* n: One Round pulses Number
*/
val->val1 = (60000000 / (config->sample_time_us * data->capture)) /
config->pulses_per_round;
} else {
val->val1 = 0U;
}
val->val2 = 0U;
return 0;
}
/* TACH driver registration */
static int tach_kb1200_init(const struct device *dev)
{
int ret;
const struct tach_kb1200_config *config = dev->config;
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret != 0) {
return ret;
}
tach_kb1200_configure(dev);
return 0;
}
static const struct sensor_driver_api tach_kb1200_driver_api = {
.sample_fetch = tach_kb1200_sample_fetch,
.channel_get = tach_kb1200_channel_get,
};
#define KB1200_TACH_INIT(inst) \
PINCTRL_DT_INST_DEFINE(inst); \
static const struct tach_kb1200_config tach_cfg_##inst = { \
.tacho = (struct tacho_regs *)DT_INST_REG_ADDR(inst), \
.pulses_per_round = DT_INST_PROP(inst, pulses_per_round), \
.sample_time_us = DT_INST_PROP(inst, sample_time_us), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
}; \
static struct tach_kb1200_data tach_data_##inst; \
SENSOR_DEVICE_DT_INST_DEFINE(inst, tach_kb1200_init, NULL, &tach_data_##inst, \
&tach_cfg_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
&tach_kb1200_driver_api);
DT_INST_FOREACH_STATUS_OKAY(KB1200_TACH_INIT)