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:
parent
0a4708cd2b
commit
fad78a2c07
12 changed files with 399 additions and 0 deletions
|
@ -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";
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
5
drivers/sensor/ite_tach_it8xxx2/CMakeLists.txt
Normal file
5
drivers/sensor/ite_tach_it8xxx2/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(tach_ite_it8xxx2.c)
|
12
drivers/sensor/ite_tach_it8xxx2/Kconfig
Normal file
12
drivers/sensor/ite_tach_it8xxx2/Kconfig
Normal 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.
|
255
drivers/sensor/ite_tach_it8xxx2/tach_ite_it8xxx2.c
Normal file
255
drivers/sensor/ite_tach_it8xxx2/tach_ite_it8xxx2.c
Normal 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)
|
40
dts/bindings/tach/ite,it8xxx2-tach.yaml
Normal file
40
dts/bindings/tach/ite,it8xxx2-tach.yaml
Normal 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
|
|
@ -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>;
|
||||
|
|
|
@ -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";
|
||||
|
|
20
include/dt-bindings/sensor/it8xxx2_tach.h
Normal file
20
include/dt-bindings/sensor/it8xxx2_tach.h
Normal 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_ */
|
|
@ -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)
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue