1 /*
2 * Copyright 2022 Google LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file File that collects common data and configs for RS1718S chip. The file
9 * doesn't provide any API itself. The feature-specific API should be provided
10 * in separated files e.g. GPIO API.
11 *
12 * This file is placed in drivers/gpio directory, because GPIO is only one
13 * supported feature at the moment. It can be move to tcpc dir in the future.
14 */
15
16 #define DT_DRV_COMPAT richtek_rt1718s
17
18 #include "gpio_rt1718s.h"
19
20 #include <zephyr/device.h>
21 #include <zephyr/drivers/gpio.h>
22 #include <zephyr/kernel.h>
23 #include <zephyr/logging/log.h>
24 #include <zephyr/sys/util_macro.h>
25 LOG_MODULE_REGISTER(gpio_rt1718s, CONFIG_GPIO_LOG_LEVEL);
26
rt1718s_alert_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)27 static void rt1718s_alert_callback(const struct device *dev, struct gpio_callback *cb,
28 uint32_t pins)
29 {
30 ARG_UNUSED(pins);
31 struct rt1718s_data *data = CONTAINER_OF(cb, struct rt1718s_data, gpio_cb);
32
33 k_work_submit(&data->alert_worker);
34 }
35
rt1718s_alert_worker(struct k_work * work)36 static void rt1718s_alert_worker(struct k_work *work)
37 {
38 struct rt1718s_data *const data = CONTAINER_OF(work, struct rt1718s_data, alert_worker);
39 const struct device *const dev = data->dev;
40 const struct rt1718s_config *const config = dev->config;
41 uint16_t alert, mask;
42
43 do {
44 /* Read alert and mask */
45 k_sem_take(&data->lock_tcpci, K_FOREVER);
46 if (rt1718s_reg_burst_read(dev, RT1718S_REG_ALERT, (uint8_t *)&alert,
47 sizeof(alert)) ||
48 rt1718s_reg_burst_read(dev, RT1718S_REG_ALERT_MASK, (uint8_t *)&mask,
49 sizeof(mask))) {
50 k_sem_give(&data->lock_tcpci);
51 LOG_ERR("i2c access failed");
52 continue;
53 }
54
55 /* Content of the alert and alert mask registers are
56 * defined by the TCPCI specification - "A masked
57 * register will still indicate in the ALERT register,
58 * but shall not set the Alert# pin low"
59 */
60 alert &= mask;
61 if (alert) {
62 /* Clear all alert bits that causes the interrupt */
63 if (rt1718s_reg_burst_write(dev, RT1718S_REG_ALERT, (uint8_t *)&alert,
64 sizeof(alert))) {
65 k_sem_give(&data->lock_tcpci);
66 LOG_ERR("i2c access failed");
67 continue;
68 }
69 }
70 k_sem_give(&data->lock_tcpci);
71
72 /* There are a few sources of the vendor
73 * defined alert for the RT1718S, but handle
74 * only GPIO at the moment.
75 */
76 if (alert & RT1718S_REG_ALERT_VENDOR_DEFINED_ALERT) {
77 rt1718s_gpio_alert_handler(dev);
78 }
79 /* While the interrupt signal is still active, we have more work to do. */
80 } while (gpio_pin_get_dt(&config->irq_gpio));
81 }
82
rt1718s_init(const struct device * dev)83 static int rt1718s_init(const struct device *dev)
84 {
85 const struct rt1718s_config *const config = dev->config;
86 struct rt1718s_data *data = dev->data;
87 int ret;
88
89 /* Check I2C is ready */
90 if (!device_is_ready(config->i2c_dev.bus)) {
91 LOG_ERR("%s device not ready", config->i2c_dev.bus->name);
92 return -ENODEV;
93 }
94
95 k_sem_init(&data->lock_tcpci, 1, 1);
96
97 if (IS_ENABLED(CONFIG_GPIO_RT1718S_INTERRUPT)) {
98 if (!device_is_ready(config->irq_gpio.port)) {
99 LOG_ERR("%s device not ready", config->irq_gpio.port->name);
100 return -ENODEV;
101 }
102
103 /* Set the interrupt pin for handling the alert */
104 k_work_init(&data->alert_worker, rt1718s_alert_worker);
105
106 gpio_pin_configure_dt(&config->irq_gpio, GPIO_INPUT);
107
108 gpio_init_callback(&data->gpio_cb, rt1718s_alert_callback,
109 BIT(config->irq_gpio.pin));
110
111 ret = gpio_add_callback(config->irq_gpio.port, &data->gpio_cb);
112 if (ret < 0) {
113 return ret;
114 }
115
116 gpio_pin_interrupt_configure_dt(&config->irq_gpio, GPIO_INT_EDGE_TO_ACTIVE);
117 }
118
119 return 0;
120 }
121
122 #define CHECK_PORT_DEVICE(node_id) \
123 COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(richtek_rt1718s_gpio_port), DEVICE_DT_GET(node_id), \
124 ())
125
126 #define IRQ_GPIO(inst) \
127 COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
128 (.irq_gpio = GPIO_DT_SPEC_INST_GET(inst, irq_gpios)), ())
129
130 #define GET_PORT_DEVICE(inst) DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, CHECK_PORT_DEVICE)
131
132 #define GPIO_RT1718S_DEVICE_INSTANCE(inst) \
133 static const struct rt1718s_config rt1718s_cfg_##inst = { \
134 .i2c_dev = I2C_DT_SPEC_INST_GET(inst), \
135 .gpio_port_dev = GET_PORT_DEVICE(inst), \
136 IRQ_GPIO(inst) \
137 }; \
138 static struct rt1718s_data rt1718s_data_##inst = { \
139 .dev = DEVICE_DT_INST_GET(inst), \
140 }; \
141 DEVICE_DT_INST_DEFINE(inst, rt1718s_init, NULL, &rt1718s_data_##inst, &rt1718s_cfg_##inst, \
142 POST_KERNEL, CONFIG_RT1718S_INIT_PRIORITY, NULL);
143
144 DT_INST_FOREACH_STATUS_OKAY(GPIO_RT1718S_DEVICE_INSTANCE)
145