Skip to content

Commit 6224edc

Browse files
committed
drivers: pwm: it8801: Add I2C-based PWM device driver
Add I2C-based PWM device driver. Supports 7 open-drain/push-pull outputs. Signed-off-by: Tim Lin <[email protected]>
1 parent 6b79790 commit 6224edc

File tree

5 files changed

+228
-0
lines changed

5 files changed

+228
-0
lines changed

drivers/pwm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_NRFX pwm_nrfx.c)
1313
zephyr_library_sources_ifdef(CONFIG_PWM_MCUX_FTM pwm_mcux_ftm.c)
1414
zephyr_library_sources_ifdef(CONFIG_PWM_IMX pwm_imx.c)
1515
zephyr_library_sources_ifdef(CONFIG_PWM_ITE_IT8XXX2 pwm_ite_it8xxx2.c)
16+
zephyr_library_sources_ifdef(CONFIG_PWM_ITE_IT8801 pwm_ite_it8801.c)
1617
zephyr_library_sources_ifdef(CONFIG_PWM_LED_ESP32 pwm_led_esp32.c)
1718
zephyr_library_sources_ifdef(CONFIG_MCPWM_ESP32 pwm_mc_esp32.c)
1819
zephyr_library_sources_ifdef(CONFIG_PWM_SAM pwm_sam.c)

drivers/pwm/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ source "drivers/pwm/Kconfig.imx"
5050

5151
source "drivers/pwm/Kconfig.it8xxx2"
5252

53+
source "drivers/pwm/Kconfig.it8801"
54+
5355
source "drivers/pwm/Kconfig.esp32"
5456

5557
source "drivers/pwm/Kconfig.sam"

drivers/pwm/Kconfig.it8801

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright (c) 2024 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config PWM_ITE_IT8801
5+
bool "ITE IT8801 PWM device driver"
6+
default y
7+
depends on DT_HAS_ITE_IT8801_PWM_ENABLED
8+
select I2C
9+
select MFD
10+
help
11+
Enable driver for ITE IT8801 I2C-based PWM.
12+
Supports 7 open-drain/push-pull outputs.

drivers/pwm/pwm_ite_it8801.c

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* Copyright (c) 2024 ITE Corporation. All Rights Reserved.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ite_it8801_pwm
8+
9+
#include <zephyr/device.h>
10+
#include <zephyr/drivers/i2c.h>
11+
#include <zephyr/drivers/mfd/mfd_ite_it8801.h>
12+
#include <zephyr/drivers/pwm.h>
13+
14+
#include <zephyr/logging/log.h>
15+
LOG_MODULE_REGISTER(pwm_ite_it8801, CONFIG_PWM_LOG_LEVEL);
16+
17+
struct it8801_pwm_map {
18+
uint8_t pushpull_en;
19+
};
20+
const static struct it8801_pwm_map it8801_pwm_gpio_map[] = {
21+
[1] = {.pushpull_en = BIT(0)}, [2] = {.pushpull_en = BIT(1)}, [3] = {.pushpull_en = BIT(2)},
22+
[4] = {.pushpull_en = BIT(3)}, [7] = {.pushpull_en = BIT(4)}, [8] = {.pushpull_en = BIT(5)},
23+
[9] = {.pushpull_en = BIT(6)},
24+
};
25+
26+
struct it8801_mfd_pwm_altctrl_cfg {
27+
/* GPIO control device structure */
28+
const struct device *gpiocr;
29+
/* GPIO control pin */
30+
uint8_t pin;
31+
/* GPIO function select */
32+
uint8_t alt_func;
33+
};
34+
35+
struct pwm_it8801_config {
36+
/* IT8801 controller dev */
37+
const struct device *mfd;
38+
/* I2C device for the MFD parent */
39+
const struct i2c_dt_spec i2c_dev;
40+
/* PWM alternate configuration */
41+
const struct it8801_mfd_pwm_altctrl_cfg *altctrl;
42+
int mfdctrl_len;
43+
int channel;
44+
/* PWM mode control register */
45+
uint8_t reg_mcr;
46+
/* PWM duty cycle register */
47+
uint8_t reg_dcr;
48+
/* PWM prescale LSB register */
49+
uint8_t reg_prslr;
50+
/* PWM prescale MSB register */
51+
uint8_t reg_prsmr;
52+
};
53+
54+
static void pwm_enable(const struct device *dev, int enabled)
55+
{
56+
const struct pwm_it8801_config *config = dev->config;
57+
int ret;
58+
59+
if (enabled) {
60+
ret = i2c_reg_update_byte_dt(&config->i2c_dev, config->reg_mcr,
61+
IT8801_PWMMCR_MCR_MASK, IT8801_PWMMCR_MCR_BLINKING);
62+
} else {
63+
ret = i2c_reg_update_byte_dt(&config->i2c_dev, config->reg_mcr,
64+
IT8801_PWMMCR_MCR_MASK, 0);
65+
}
66+
if (ret != 0) {
67+
LOG_ERR("Failed to enable pwm (ret %d)", ret);
68+
return;
69+
}
70+
}
71+
72+
static int pwm_it8801_get_cycles_per_sec(const struct device *dev, uint32_t channel,
73+
uint64_t *cycles)
74+
{
75+
ARG_UNUSED(dev);
76+
ARG_UNUSED(channel);
77+
78+
*cycles = (uint64_t)PWM_IT8801_FREQ;
79+
80+
return 0;
81+
}
82+
83+
static int pwm_it8801_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_cycles,
84+
uint32_t pulse_cycles, pwm_flags_t flags)
85+
{
86+
ARG_UNUSED(channel);
87+
88+
const struct pwm_it8801_config *config = dev->config;
89+
int ch = config->channel, ret;
90+
uint8_t duty, mask;
91+
92+
/* Enable PWM output push-pull */
93+
if (flags & PWM_IT8801_PUSH_PULL) {
94+
mask = it8801_pwm_gpio_map[ch].pushpull_en;
95+
96+
ret = i2c_reg_update_byte_dt(&config->i2c_dev, IT8801_REG_PWMODDSR, mask, mask);
97+
if (ret != 0) {
98+
LOG_ERR("Failed to set push-pull (ret %d)", ret);
99+
return ret;
100+
}
101+
}
102+
103+
/* Set PWM channel duty cycle */
104+
if (pulse_cycles == 0) {
105+
duty = 0;
106+
} else {
107+
duty = pulse_cycles * 256 / period_cycles - 1;
108+
}
109+
LOG_DBG("IT8801 pwm duty cycles = %d", duty);
110+
111+
ret = i2c_reg_write_byte_dt(&config->i2c_dev, config->reg_dcr, duty);
112+
if (ret != 0) {
113+
LOG_ERR("Failed to set cycles (ret %d)", ret);
114+
return ret;
115+
}
116+
117+
/* PWM channel clock source not gating */
118+
pwm_enable(dev, 1);
119+
120+
return 0;
121+
}
122+
123+
static int pwm_it8801_init(const struct device *dev)
124+
{
125+
const struct pwm_it8801_config *config = dev->config;
126+
int ret;
127+
128+
/* Verify multi-function parent is ready */
129+
if (!device_is_ready(config->mfd)) {
130+
LOG_ERR("(pwm)%s is not ready", config->mfd->name);
131+
return -ENODEV;
132+
}
133+
134+
/* PWM channel clock source gating before configuring */
135+
pwm_enable(dev, 0);
136+
137+
for (int i = 0; i < config->mfdctrl_len; i++) {
138+
/* Switching the pin to PWM alternate function */
139+
ret = mfd_it8801_configure_pins(&config->i2c_dev, config->altctrl[i].gpiocr,
140+
config->altctrl[i].pin,
141+
config->altctrl[i].alt_func);
142+
if (ret != 0) {
143+
LOG_ERR("Failed to configure pins (ret %d)", ret);
144+
return ret;
145+
}
146+
}
147+
148+
return 0;
149+
}
150+
151+
static const struct pwm_driver_api pwm_it8801_api = {
152+
.set_cycles = pwm_it8801_set_cycles,
153+
.get_cycles_per_sec = pwm_it8801_get_cycles_per_sec,
154+
};
155+
156+
#define PWM_IT8801_INIT(inst) \
157+
static const struct it8801_mfd_pwm_altctrl_cfg \
158+
it8801_pwm_altctrl##inst[IT8801_DT_INST_MFDCTRL_LEN(inst)] = \
159+
IT8801_DT_MFD_ITEMS_LIST(inst); \
160+
static const struct pwm_it8801_config pwm_it8801_cfg_##inst = { \
161+
.mfd = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
162+
.i2c_dev = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \
163+
.altctrl = it8801_pwm_altctrl##inst, \
164+
.mfdctrl_len = IT8801_DT_INST_MFDCTRL_LEN(inst), \
165+
.channel = DT_INST_PROP(inst, channel), \
166+
.reg_mcr = DT_INST_REG_ADDR_BY_IDX(inst, 0), \
167+
.reg_dcr = DT_INST_REG_ADDR_BY_IDX(inst, 1), \
168+
.reg_prslr = DT_INST_REG_ADDR_BY_IDX(inst, 2), \
169+
.reg_prsmr = DT_INST_REG_ADDR_BY_IDX(inst, 3), \
170+
}; \
171+
DEVICE_DT_INST_DEFINE(inst, &pwm_it8801_init, NULL, NULL, &pwm_it8801_cfg_##inst, \
172+
POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, &pwm_it8801_api);
173+
174+
DT_INST_FOREACH_STATUS_OKAY(PWM_IT8801_INIT)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright (c) 2024 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ITE IT8801 I2C-based PWM device driver
5+
6+
compatible: "ite,it8801-pwm"
7+
8+
include: [base.yaml, pinctrl-device.yaml, pwm-controller.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
mfdctrl:
15+
type: phandle
16+
required: true
17+
description: |
18+
Switching the pin to PWM alternate function.
19+
20+
channel:
21+
type: int
22+
required: true
23+
enum:
24+
- 1
25+
- 2
26+
- 3
27+
- 4
28+
- 7
29+
- 8
30+
- 9
31+
description: |
32+
1 = PWM_CHANNEL_1, 2 = PWM_CHANNEL_2, 3 = PWM_CHANNEL_3,
33+
4 = PWM_CHANNEL_4, 7 = PWM_CHANNEL_7, 8 = PWM_CHANNEL_8,
34+
9 = PWM_CHANNEL_9
35+
36+
pwm-cells:
37+
- channel
38+
- period
39+
- flags

0 commit comments

Comments
 (0)