ITE drivers/sensor: add tachometer driver for it8xxx2_evb

Add tachometer driver for it8xxx2_evb.

Signed-off-by: Ruibin Chang <Ruibin.Chang@ite.com.tw>
This commit is contained in:
Ruibin Chang 2021-10-19 18:33:38 +08:00 committed by Anas Nashif
commit fad78a2c07
12 changed files with 399 additions and 0 deletions

View file

@ -66,6 +66,7 @@
&ite_uart2_wrapper {
status = "okay";
};
/* pwm for test */
&pwm0 {
status = "okay";
prescaler-cx = <PWM_PRESCALER_C6>;
@ -75,11 +76,18 @@
*/
pwm-output-frequency = <324>;
};
/* pwm for fan */
&pwm7 {
status = "okay";
prescaler-cx = <PWM_PRESCALER_C4>;
pwm-output-frequency = <30000>;
};
/* fan tachometer sensor */
&tach0 {
status = "okay";
channel = <IT8XXX2_TACH_CHANNEL_A>;
pulses-per-round = <2>;
};
&kscan0 {
status = "okay";
};

View file

@ -98,6 +98,7 @@ add_subdirectory_ifdef(CONFIG_TACH_XEC mchp_tach_xec)
add_subdirectory_ifdef(CONFIG_ITDS wsen_itds)
add_subdirectory_ifdef(CONFIG_MCUX_ACMP mcux_acmp)
add_subdirectory_ifdef(CONFIG_TACH_NPCX nuvoton_tach_npcx)
add_subdirectory_ifdef(CONFIG_TACH_IT8XXX2 ite_tach_it8xxx2)
if(CONFIG_USERSPACE OR CONFIG_SENSOR_SHELL OR CONFIG_SENSOR_SHELL_BATTERY)
# The above if() is needed or else CMake would complain about

View file

@ -232,4 +232,6 @@ source "drivers/sensor/mcux_acmp/Kconfig"
source "drivers/sensor/nuvoton_tach_npcx/Kconfig"
source "drivers/sensor/ite_tach_it8xxx2/Kconfig"
endif # SENSOR

View file

@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources(tach_ite_it8xxx2.c)

View file

@ -0,0 +1,12 @@
# ITE tachometer sensor configuration options
# Copyright (c) 2021 ITE Technology Corporation.
# SPDX-License-Identifier: Apache-2.0
config TACH_IT8XXX2
bool "ITE it8xxx2 Tachometer sensor"
depends on SOC_IT8XXX2
help
Enable the ITE it8xxx2 tachometer sensor,
it8xxx2 supports two 16-bit tachometer sensor, each sensor has two
input channel and we can select one input from two channel.

View file

@ -0,0 +1,255 @@
/*
* Copyright (c) 2021 ITE Technology Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ite_it8xxx2_tach
/**
* @file
* @brief ITE it8xxx2 tachometer sensor module driver
*
* This file contains a driver for the tachometer sensor module which contains
* two independent counters (F1TL/MRR and F2TL/MRR). The content of the
* Tachometer Reading Register is still update based on the sampling counter
* that samples the tachometer input (T0A, T0B, T1A or T1B pins).
* The following is block diagram of this module:
*
* Sample Rate = TACH_FREQ / 128
* |
* | Tachometer 0 | T0A (GPD6)
* | | | +-----------+ |
* | +-----+-----+ | | _ _ |<--+
* |------>| F1TL/MRR |<-+-| | |_| |_ |<--+
* | +-----------+ +-----------+ |
* | capture pulses T0B (GPJ2)
* | in sample rate
* | period
* +-----------+ |
* Crystal-->| Prescaler |--->| Tachometer 1 T1A (GPD7)
* 32.768k +-----------+ | | +-----------+ |
* | +-----+-----+ | _ _ |<--+
* |------>| F2TL/MRR |<-+-| | |_| |_ |<--+
* | +-----------+ +-----------+ |
* | capture pulses T1B (GPJ3)
* | in one second
* | period
* |
*
* Based on the counter value, we can compute the current RPM of external signal
* from encoders.
*/
#include <device.h>
#include <drivers/pinmux.h>
#include <drivers/sensor.h>
#include <dt-bindings/sensor/it8xxx2_tach.h>
#include <errno.h>
#include <soc.h>
#include <soc_dt.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(tach_ite_it8xxx2, CONFIG_SENSOR_LOG_LEVEL);
/*
* NOTE: The PWM output maximum is 324Hz in EC LPM, so if we need fan to work
* then don't let EC enter LPM.
*/
#define TACH_FREQ EC_FREQ
/* Device config */
struct tach_alt_cfg {
/* Pinmux control device structure */
const struct device *pinctrls;
/* GPIO pin */
uint8_t pin;
/* Alternate function */
uint8_t alt_fun;
};
struct tach_it8xxx2_config {
/* Fan x tachometer LSB reading register */
uintptr_t reg_fxtlrr;
/* Fan x tachometer MSB reading register */
uintptr_t reg_fxtmrr;
/* Tachometer switch control register */
uintptr_t reg_tswctlr;
/* Tachometer data valid bit of tswctlr register */
int dvs_bit;
/* Tachometer data valid status bit of tswctlr register */
int chsel_bit;
/* Tachometer alternate configuration list */
const struct tach_alt_cfg *alt_list;
/* Select channel of tachometer */
int channel;
/* Number of pulses per round of tachometer's input */
int pulses_per_round;
};
/* Driver data */
struct tach_it8xxx2_data {
/* Captured counts of tachometer */
uint32_t capture;
};
static bool tach_ch_is_valid(const struct device *dev, int tach_ch)
{
const struct tach_it8xxx2_config *const config = dev->config;
volatile uint8_t *reg_tswctlr = (uint8_t *)config->reg_tswctlr;
int dvs_bit = config->dvs_bit;
int chsel_bit = config->chsel_bit;
int mask = (dvs_bit | chsel_bit);
bool valid = false;
switch (tach_ch) {
case IT8XXX2_TACH_CHANNEL_A:
if ((*reg_tswctlr & mask) == dvs_bit) {
valid = true;
}
break;
case IT8XXX2_TACH_CHANNEL_B:
if ((*reg_tswctlr & mask) == mask) {
valid = true;
}
break;
default:
break;
}
return valid;
}
static int tach_it8xxx2_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
const struct tach_it8xxx2_config *const config = dev->config;
volatile uint8_t *reg_fxtlrr = (uint8_t *)config->reg_fxtlrr;
volatile uint8_t *reg_fxtmrr = (uint8_t *)config->reg_fxtmrr;
volatile uint8_t *reg_tswctlr = (uint8_t *)config->reg_tswctlr;
int tach_ch = config->channel;
struct tach_it8xxx2_data *const data = dev->data;
if ((chan != SENSOR_CHAN_RPM) && (chan != SENSOR_CHAN_ALL)) {
return -ENOTSUP;
}
if (tach_ch_is_valid(dev, tach_ch)) {
/* If channel data of tachometer is valid, then save it */
data->capture = ((*reg_fxtmrr) << 8) | (*reg_fxtlrr);
/* Clear tachometer data valid status */
*reg_tswctlr |= config->dvs_bit;
} else {
/* If channel data of tachometer isn't valid, then clear it */
data->capture = 0;
}
return 0;
}
static int tach_it8xxx2_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
const struct tach_it8xxx2_config *const config = dev->config;
int tachx = ((config->dvs_bit) == IT8XXX2_PWM_T0DVS) ? 0 : 1;
int p = config->pulses_per_round;
struct tach_it8xxx2_data *const data = dev->data;
if (chan != SENSOR_CHAN_RPM) {
LOG_ERR("Sensor chan %d, only support SENSOR_CHAN_RPM", chan);
return -ENOTSUP;
}
/* Transform count unit to RPM */
if (data->capture > 0) {
if (tachx == 0) {
/*
* Fan Speed (RPM) = 60 / (1/fs * {F1TMRR, F1TLRR} * P)
* - P denotes the numbers of pulses per round
* - {F1TMRR, F1TLRR} = 0000h denotes Fan Speed is zero
* - The sampling rate (fs) is TACH_FREQ / 128
*/
val->val1 = (60 * TACH_FREQ / 128 / p / (data->capture));
} else {
/*
* Fan Speed (RPM) = {F2TMRR, F2TLRR} * 60 / P
* - P denotes the numbers of pulses per round
* - {F2TMRR, F2TLRR} = 0000h denotes Fan Speed is zero
*/
val->val1 = ((data->capture) * 120 / (p * 2));
}
} else {
val->val1 = 0U;
}
val->val2 = 0U;
return 0;
}
static int tach_it8xxx2_init(const struct device *dev)
{
const struct tach_it8xxx2_config *const config = dev->config;
volatile uint8_t *reg_tswctlr = (uint8_t *)config->reg_tswctlr;
int tach_ch = config->channel;
if (tach_ch > IT8XXX2_TACH_CHANNEL_B) {
LOG_ERR("Tach channel %d, only support 0 or 1", tach_ch);
return -EINVAL;
}
/* Select pin to alternate mode for tachometer */
pinmux_pin_set(config->alt_list[tach_ch].pinctrls,
config->alt_list[tach_ch].pin,
config->alt_list[tach_ch].alt_fun);
if (tach_ch == IT8XXX2_TACH_CHANNEL_A) {
/* Select IT8XXX2_TACH_CHANNEL_A output to tachometer */
*reg_tswctlr &= ~(config->chsel_bit);
/* Clear tachometer data valid status */
*reg_tswctlr |= config->dvs_bit;
} else {
/* Select IT8XXX2_TACH_CHANNEL_B output to tachometer */
*reg_tswctlr |= config->chsel_bit;
/* Clear tachometer data valid status */
*reg_tswctlr |= config->dvs_bit;
}
/* Tachometer sensor already start */
return 0;
}
static const struct sensor_driver_api tach_it8xxx2_driver_api = {
.sample_fetch = tach_it8xxx2_sample_fetch,
.channel_get = tach_it8xxx2_channel_get,
};
#define TACH_IT8XXX2_INIT(inst) \
static const struct tach_alt_cfg \
tach_alt_##inst[DT_INST_NUM_PINCTRLS_BY_IDX(inst, 0)] = \
IT8XXX2_DT_ALT_ITEMS_LIST(inst); \
\
static const struct tach_it8xxx2_config tach_it8xxx2_cfg_##inst = { \
.reg_fxtlrr = DT_INST_REG_ADDR_BY_IDX(inst, 0), \
.reg_fxtmrr = DT_INST_REG_ADDR_BY_IDX(inst, 1), \
.reg_tswctlr = DT_INST_REG_ADDR_BY_IDX(inst, 2), \
.dvs_bit = DT_INST_PROP(inst, dvs_bit), \
.chsel_bit = DT_INST_PROP(inst, chsel_bit), \
.alt_list = tach_alt_##inst, \
.channel = DT_INST_PROP(inst, channel), \
.pulses_per_round = DT_INST_PROP(inst, pulses_per_round), \
}; \
\
static struct tach_it8xxx2_data tach_it8xxx2_data_##inst; \
\
DEVICE_DT_INST_DEFINE(inst, \
tach_it8xxx2_init, \
NULL, \
&tach_it8xxx2_data_##inst, \
&tach_it8xxx2_cfg_##inst, \
POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&tach_it8xxx2_driver_api);
DT_INST_FOREACH_STATUS_OKAY(TACH_IT8XXX2_INIT)

View file

@ -0,0 +1,40 @@
# Copyright (c) 2021 ITE Technology Corporation.
# SPDX-License-Identifier: Apache-2.0
description: ITE, it8xxx2 Tachometer node
compatible: "ite,it8xxx2-tach"
include: tach.yaml
properties:
reg:
required: true
dvs-bit:
type: int
required: true
description: tachometer data valid bit of tswctlr register
chsel-bit:
type: int
required: true
description: tachometer data valid status bit of tswctlr register
pinctrl-0:
type: phandles
required: true
description: configuration of tachometer pinmux controller
channel:
type: int
required: true
enum:
- 0
- 1
description: 0 = TACH_CHANNEL_A, 1 = TACH_CHANNEL_B
pulses-per-round:
type: int
required: true
description: number of pulses per round of tachometer's input

View file

@ -62,6 +62,20 @@
pinctrls = <&pinmuxa 7 IT8XXX2_PINMUX_FUNC_1>;
};
/* Tachometer alternate function */
pinctrl_tach0a: tach0a {
pinctrls = <&pinmuxd 6 IT8XXX2_PINMUX_FUNC_1>;
};
pinctrl_tach0b: tach0b {
pinctrls = <&pinmuxj 2 IT8XXX2_PINMUX_FUNC_3>;
};
pinctrl_tach1a: tach1a {
pinctrls = <&pinmuxd 7 IT8XXX2_PINMUX_FUNC_1>;
};
pinctrl_tach1b: tach1b {
pinctrls = <&pinmuxj 3 IT8XXX2_PINMUX_FUNC_3>;
};
/* I2C alternate function */
pinctrl_i2c_clk0: i2c_clk0 {
pinctrls = <&pinmuxb 3 IT8XXX2_PINMUX_FUNC_1>;

View file

@ -6,11 +6,13 @@
*/
#include <mem.h>
#include <dt-bindings/dt-util.h>
#include <dt-bindings/interrupt-controller/ite-intc.h>
#include <dt-bindings/i2c/i2c.h>
#include <dt-bindings/pinctrl/it8xxx2-pinctrl.h>
#include <dt-bindings/pwm/pwm.h>
#include <dt-bindings/pwm/it8xxx2_pwm.h>
#include <dt-bindings/sensor/it8xxx2_tach.h>
#include "it8xxx2-alts-map.dtsi"
/ {
@ -850,6 +852,30 @@
pinctrl-0 = <&pinctrl_pwm7>; /* GPA7 */
#pwm-cells = <2>;
};
tach0: tach@f0181e {
compatible = "ite,it8xxx2-tach";
reg = <0x00f0181e 1 /* F1TLRR */
0x00f0181f 1 /* F1TMRR */
0x00f01848 1>; /* TSWCTLR */
dvs-bit = <BIT(3)>;
chsel-bit = <BIT(2)>;
label = "TACH_0";
status = "disabled";
pinctrl-0 = <&pinctrl_tach0a /* GPD6 */
&pinctrl_tach0b>; /* GPJ2 */
};
tach1: tach@f01820 {
compatible = "ite,it8xxx2-tach";
reg = <0x00f01820 1 /* F2TLRR */
0x00f01821 1 /* F2TMRR */
0x00f01848 1>; /* TSWCTLR */
dvs-bit = <BIT(1)>;
chsel-bit = <BIT(0)>;
label = "TACH_1";
status = "disabled";
pinctrl-0 = <&pinctrl_tach1a /* GPD7 */
&pinctrl_tach1b>; /* GPJ3 */
};
gctrl: general-control@f02000 {
compatible = "ite,it8xxx2-gctrl";

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2021 ITE Technology Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_ITE_TACH_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_ITE_TACH_H_
/**
* @name Tachometer channels
* @{
*/
/** Tachometer channel A */
#define IT8XXX2_TACH_CHANNEL_A 0
/** Tachometer channel B */
#define IT8XXX2_TACH_CHANNEL_B 1
/** @} */
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_ITE_TACH_H_ */

View file

@ -44,6 +44,13 @@
#define REG_BASE_ADDR EC_REG_BASE_ADDR
#endif
/* Common definition */
/*
* EC clock frequency (PWM and tachometer driver need it to reply
* to api or calculate RPM)
*/
#define EC_FREQ MHZ(8)
/**
* (10XXh) Shared Memory Flash Interface Bridge (SMFI)
*/
@ -640,6 +647,11 @@ struct pwm_it8xxx2_regs {
/* PWM register fields */
/* 0x023: PWM Clock Control */
#define IT8XXX2_PWM_PCCE BIT(1)
/* 0x048: Tachometer Switch Control */
#define IT8XXX2_PWM_T0DVS BIT(3)
#define IT8XXX2_PWM_T0CHSEL BIT(2)
#define IT8XXX2_PWM_T1DVS BIT(1)
#define IT8XXX2_PWM_T1CHSEL BIT(0)
/**
*

View file

@ -72,6 +72,10 @@ config PWM_ITE_IT8XXX2
default y
depends on PWM
config TACH_IT8XXX2
default y
depends on SENSOR
if ITE_IT8XXX2_INTC
config NUM_IRQS
default 185