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