Skip to content

Commit 4bf9e97

Browse files
committed
drivers: mfd: it8801: Initialize IT8801 multi-function device drivers
The IT8801 is an I/O expander that provides GPIO, PWM, Keyboard functions via the I2C bus. Signed-off-by: Tim Lin <[email protected]>
1 parent e90c58a commit 4bf9e97

File tree

6 files changed

+362
-0
lines changed

6 files changed

+362
-0
lines changed

drivers/mfd/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ zephyr_library_sources_ifdef(CONFIG_MFD_MAX31790 mfd_max31790.c)
1616
zephyr_library_sources_ifdef(CONFIG_NXP_LP_FLEXCOMM mfd_nxp_lp_flexcomm.c)
1717
zephyr_library_sources_ifdef(CONFIG_MFD_BD8LB600FS mfd_bd8lb600fs.c)
1818
zephyr_library_sources_ifdef(CONFIG_MFD_TLE9104 mfd_tle9104.c)
19+
zephyr_library_sources_ifdef(CONFIG_MFD_ITE_IT8801 mfd_ite_it8801.c)

drivers/mfd/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ source "drivers/mfd/Kconfig.npm1300"
2929
source "drivers/mfd/Kconfig.npm6001"
3030
source "drivers/mfd/Kconfig.lpflexcomm"
3131
source "drivers/mfd/Kconfig.tle9104"
32+
source "drivers/mfd/Kconfig.it8801"
3233

3334
endif # MFD

drivers/mfd/Kconfig.it8801

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2024 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config MFD_ITE_IT8801
5+
bool "ITE IT8801 ioexpander multi-function device driver"
6+
default y
7+
depends on DT_HAS_ITE_IT8801_MFD_ENABLED
8+
select I2C
9+
help
10+
Enable the ITE IT8801 ioexpander multi-function device driver.
11+
This ioexpander provides a GPIO/PWM/Keyboard function via I2C bus.

drivers/mfd/mfd_ite_it8801.c

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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_mfd
8+
9+
#include <zephyr/drivers/gpio.h>
10+
#include <zephyr/drivers/i2c.h>
11+
#include <zephyr/drivers/mfd/mfd_ite_it8801.h>
12+
13+
#include <zephyr/logging/log.h>
14+
LOG_MODULE_REGISTER(mfd_ite_it8801, CONFIG_MFD_LOG_LEVEL);
15+
16+
struct mfd_it8801_config {
17+
const struct i2c_dt_spec i2c_dev;
18+
/* Alert GPIO pin */
19+
const struct gpio_dt_spec irq_gpios;
20+
};
21+
22+
struct mfd_it8801_data {
23+
struct k_work gpio_isr_worker;
24+
/* Alert pin callback */
25+
struct gpio_callback gpio_cb;
26+
sys_slist_t callback_list;
27+
};
28+
29+
static int it8801_check_vendor_id(const struct device *dev)
30+
{
31+
const struct mfd_it8801_config *config = dev->config;
32+
int i, ret;
33+
uint8_t val;
34+
35+
/* Verify vendor ID registers(16-bits). */
36+
for (i = 0; i < ARRAY_SIZE(it8801_id_verify); i++) {
37+
ret = i2c_reg_read_byte_dt(&config->i2c_dev, it8801_id_verify[i].reg, &val);
38+
39+
if (ret != 0) {
40+
LOG_ERR("Failed to read vendoer ID (ret %d)", ret);
41+
return ret;
42+
}
43+
44+
if (val != it8801_id_verify[i].chip_id) {
45+
LOG_ERR("The IT8801 vendor ID is wrong. Index: %d, Expected ID: 0x%x,"
46+
"Read ID: 0x%x",
47+
i, it8801_id_verify[i].chip_id, val);
48+
return -ENODEV;
49+
}
50+
}
51+
52+
return 0;
53+
}
54+
55+
void it8801_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
56+
{
57+
ARG_UNUSED(pins);
58+
struct mfd_it8801_data *data = CONTAINER_OF(cb, struct mfd_it8801_data, gpio_cb);
59+
60+
k_work_submit(&data->gpio_isr_worker);
61+
}
62+
63+
void mfd_it8801_register_interrupt_callback(const struct device *mfd,
64+
struct it8801_mfd_callback *callback)
65+
{
66+
struct mfd_it8801_data *data = mfd->data;
67+
68+
sys_slist_append(&data->callback_list, &callback->node);
69+
}
70+
71+
static void it8801_gpio_alert_worker(struct k_work *work)
72+
{
73+
struct mfd_it8801_data *data = CONTAINER_OF(work, struct mfd_it8801_data, gpio_isr_worker);
74+
struct it8801_mfd_callback *cb_entry;
75+
76+
SYS_SLIST_FOR_EACH_CONTAINER(&data->callback_list, cb_entry, node) {
77+
cb_entry->cb(cb_entry->dev);
78+
}
79+
}
80+
81+
static int mfd_it8801_init(const struct device *dev)
82+
{
83+
const struct mfd_it8801_config *config = dev->config;
84+
struct mfd_it8801_data *data = dev->data;
85+
int ret;
86+
87+
if (!i2c_is_ready_dt(&config->i2c_dev)) {
88+
LOG_ERR("I2C bus %s is not ready", config->i2c_dev.bus->name);
89+
return -ENODEV;
90+
}
91+
92+
/* Verify Vendor ID registers. */
93+
ret = it8801_check_vendor_id(dev);
94+
if (ret) {
95+
LOG_ERR("Failed to read IT8801 vendor id %x", ret);
96+
return ret;
97+
}
98+
99+
k_work_init(&data->gpio_isr_worker, it8801_gpio_alert_worker);
100+
101+
sys_slist_init(&data->callback_list);
102+
103+
/* Alert response enable */
104+
ret = i2c_reg_write_byte_dt(&config->i2c_dev, IT8801_REG_SMBCR, IT8801_REG_MASK_ARE);
105+
if (ret != 0) {
106+
LOG_ERR("Failed to initialization setting (ret %d)", ret);
107+
return ret;
108+
}
109+
110+
gpio_pin_configure_dt(&config->irq_gpios, GPIO_INPUT);
111+
112+
/* Initialize GPIO interrupt callback */
113+
gpio_init_callback(&data->gpio_cb, it8801_gpio_callback, BIT(config->irq_gpios.pin));
114+
115+
ret = gpio_add_callback(config->irq_gpios.port, &data->gpio_cb);
116+
if (ret != 0) {
117+
LOG_ERR("Failed to add INT callback: %d", ret);
118+
return ret;
119+
}
120+
gpio_pin_interrupt_configure_dt(&config->irq_gpios, GPIO_INT_MODE_EDGE | GPIO_INT_TRIG_LOW);
121+
122+
return 0;
123+
}
124+
125+
#define MFD_IT8801_DEFINE(inst) \
126+
static struct mfd_it8801_data it8801_data_##inst; \
127+
static const struct mfd_it8801_config it8801_cfg_##inst = { \
128+
.i2c_dev = I2C_DT_SPEC_INST_GET(inst), \
129+
.irq_gpios = GPIO_DT_SPEC_INST_GET_OR(inst, irq_gpios, {0}), \
130+
}; \
131+
DEVICE_DT_INST_DEFINE(inst, mfd_it8801_init, NULL, &it8801_data_##inst, \
132+
&it8801_cfg_##inst, POST_KERNEL, CONFIG_MFD_INIT_PRIORITY, NULL);
133+
134+
DT_INST_FOREACH_STATUS_OKAY(MFD_IT8801_DEFINE)
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Copyright (c) 2024 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
ITE IT8801 ioexpander multi-function device drivers.
6+
This ioexpander provides a GPIO/PWM/Keyboard function via I2C bus.
7+
8+
An example configuration:
9+
10+
&i2c4 {
11+
status = "okay";
12+
clock-frequency = <I2C_BITRATE_STANDARD>;
13+
pinctrl-0 = <&i2c4_clk_gpe0_default
14+
&i2c4_data_gpe7_default>;
15+
pinctrl-names = "default";
16+
17+
it8801_mfd: it8801@38 {
18+
compatible = "ite,it8801-mfd";
19+
/*
20+
* SMBus address (7-bit without R/W)
21+
* SMB_ADDR pin is 0, SMBus address is 0x38
22+
* SMB_ADDR pin is 1, SMBus address is 0x39
23+
*/
24+
reg = <0x38>;
25+
irq-gpios = <&gpioa 1 0>; /* SMB_INT# */
26+
#address-cells = <1>;
27+
#size-cells = <1>;
28+
29+
ioex_it8801_port0: it8801_port@0 {
30+
compatible = "ite,it8801-gpio";
31+
reg = <0x00 1 /* GPIPSR */
32+
0x05 1 /* GPSOVR */
33+
0x0a 8 /* GPCR */
34+
0x32 1 /* GPISR */
35+
0x37 1>; /* GPIER */
36+
gpio-controller;
37+
#gpio-cells = <2>;
38+
ngpios = <8>;
39+
pin-mask = <0xdb>;
40+
};
41+
42+
ioex_it8801_port1: it8801_port@1 {
43+
compatible = "ite,it8801-gpio";
44+
reg = <0x01 1 /* GPIPSR */
45+
0x06 1 /* GPSOVR */
46+
0x12 8 /* GPCR */
47+
0x33 1 /* GPISR */
48+
0x38 1>; /* GPIER */
49+
gpio-controller;
50+
#gpio-cells = <2>;
51+
ngpios = <8>;
52+
pin-mask = <0x3f>;
53+
};
54+
55+
ioex_it8801_port2: it8801_port@2 {
56+
compatible = "ite,it8801-gpio";
57+
reg = <0x02 1 /* GPIPSR */
58+
0x07 1 /* GPSOVR */
59+
0x1a 8 /* GPCR */
60+
0x34 1 /* GPISR */
61+
0x39 1>; /* GPIER */
62+
gpio-controller;
63+
#gpio-cells = <2>;
64+
ngpios = <8>;
65+
pin-mask = <0x0f>;
66+
};
67+
68+
ioex_it8801_kbd: it8801_kbd@40 {
69+
compatible = "ite,it8801-kbd";
70+
reg = <0x40 1 /* KSOMCR */
71+
0x41 1 /* KSIDR */
72+
0x42 1 /* KSIEER */
73+
0x43 1>; /* KSIIER */
74+
kso-mapping = <0 1 20 3 4 5 6
75+
17 18 16 15 11 12>;
76+
mfdctrl = <&kso18_gp01_default
77+
&kso20_gp23_default>;
78+
row-size = <8>;
79+
col-size = <13>;
80+
81+
kscan_input: kscan-input {
82+
compatible = "zephyr,kscan-input";
83+
};
84+
};
85+
86+
ioex_it8801_pwm: it8801_pwm@90 {
87+
compatible = "ite,it8801-pwm";
88+
mfdctrl = <&pwm7_gp20_default>;
89+
reg = <0x90 1 /* PWMMCR */
90+
0x94 1>; /* PWMDCR */
91+
channel = <7>;
92+
#pwm-cells = <3>;
93+
};
94+
};
95+
};
96+
97+
compatible: "ite,it8801-mfd"
98+
99+
include: i2c-device.yaml
100+
101+
properties:
102+
reg:
103+
required: true
104+
105+
irq-gpios:
106+
type: phandle-array
107+
description: |
108+
An interrupt can be asserted on SMB_INT# pin to notify
109+
the host-side since an effective interrupt occurs.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright (c) 2024 ITE Corporation. All Rights Reserved.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_DRIVERS_MFD_ITE_IT8801_H_
8+
#define ZEPHYR_INCLUDE_DRIVERS_MFD_ITE_IT8801_H_
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
/*
15+
* IC clock and power management controller register fields
16+
*/
17+
/* 0xf9: Gather interrupt status register */
18+
#define IT8801_REG_GISR 0xf9
19+
#define IT8801_REG_MASK_GISR_GKSIIS BIT(6)
20+
/* 0xfb: Gather interrupt enable control register */
21+
#define IT8801_REG_GIECR 0xfb
22+
#define IT8801_REG_MASK_GKSIIE BIT(3)
23+
24+
/*
25+
* General control register fields
26+
*/
27+
#define IT8801_REG_LBVIDR 0xfe
28+
#define IT8801_REG_HBVIDR 0xff
29+
30+
struct it8801_vendor_id_t {
31+
uint8_t chip_id;
32+
uint8_t reg;
33+
};
34+
35+
static const struct it8801_vendor_id_t it8801_id_verify[] = {
36+
{0x12, IT8801_REG_HBVIDR},
37+
{0x83, IT8801_REG_LBVIDR},
38+
};
39+
40+
/*
41+
* SMbus interface register fields
42+
*/
43+
/* 0xfa: SMBus control register */
44+
#define IT8801_REG_SMBCR 0xfa
45+
#define IT8801_REG_MASK_ARE BIT(4)
46+
47+
/*
48+
* GPIO register fields
49+
*/
50+
#define IT8801_GPIOAFS_FUN1 0x0
51+
#define IT8801_GPIOAFS_FUN2 0x01
52+
#define IT8801_GPIOAFS_FUN3 0x02
53+
/* GPIO control register */
54+
/* GPIO direction */
55+
#define IT8801_GPIODIR BIT(5)
56+
/* GPIO input and output type */
57+
#define IT8801_GPIOIOT_OD BIT(4)
58+
#define IT8801_GPIOIOT_INT_FALL BIT(4)
59+
#define IT8801_GPIOIOT_INT_RISE BIT(3)
60+
/* GPIO polarity */
61+
#define IT8801_GPIOPOL BIT(2)
62+
/* GPIO pull-down enable */
63+
#define IT8801_GPIOPDE BIT(1)
64+
/* GPIO pull-up enable */
65+
#define IT8801_GPIOPUE BIT(0)
66+
67+
/*
68+
* Keyboard matrix scan controller register fields
69+
*/
70+
/* 0x40: Keyboard scan out mode control register */
71+
#define IT8801_REG_MASK_KSOSDIC BIT(7)
72+
#define IT8801_REG_MASK_KSE BIT(6)
73+
#define IT8801_REG_MASK_AKSOSC BIT(5)
74+
75+
/*
76+
* PWM register fields
77+
*/
78+
#define PWM_IT8801_FREQ 32895
79+
/* Control push-pull flag */
80+
#define PWM_IT8801_PUSH_PULL BIT(8)
81+
/* 0x5f: PWM output open-drain disable register */
82+
#define IT8801_REG_PWMODDSR 0x5f
83+
/* PWM mode control register */
84+
#define IT8801_PWMMCR_MCR_MASK GENMASK(1, 0)
85+
#define IT8801_PWMMCR_MCR_OFF 0
86+
#define IT8801_PWMMCR_MCR_BLINKING 1
87+
#define IT8801_PWMMCR_MCR_BREATHING 2
88+
#define IT8801_PWMMCR_MCR_ON 3
89+
90+
/* Define the IT8801 MFD interrupt callback function handler */
91+
typedef void (*it8801_callback_handler_t)(const struct device *dev);
92+
93+
struct it8801_mfd_callback {
94+
sys_snode_t node;
95+
it8801_callback_handler_t cb;
96+
const struct device *dev;
97+
};
98+
/* Register the interrupt of IT8801 MFD callback function */
99+
void mfd_it8801_register_interrupt_callback(const struct device *mfd,
100+
struct it8801_mfd_callback *callback);
101+
102+
#ifdef __cplusplus
103+
}
104+
#endif
105+
106+
#endif /* ZEPHYR_INCLUDE_DRIVERS_MFD_ITE_IT8801_H_ */

0 commit comments

Comments
 (0)