forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinput_cst816s.c
277 lines (231 loc) · 8.07 KB
/
input_cst816s.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/*
* Copyright (c) 2021 Qingsong Gou <gouqs@hotmail.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT hynitron_cst816s
#include <zephyr/sys/byteorder.h>
#include <zephyr/input/input.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(cst816s, CONFIG_INPUT_LOG_LEVEL);
#define CST816S_CHIP_ID 0xB4
#define CST816S_REG_DATA 0x00
#define CST816S_REG_GESTURE_ID 0x01
#define CST816S_REG_FINGER_NUM 0x02
#define CST816S_REG_XPOS_H 0x03
#define CST816S_REG_XPOS_L 0x04
#define CST816S_REG_YPOS_H 0x05
#define CST816S_REG_YPOS_L 0x06
#define CST816S_REG_BPC0H 0xB0
#define CST816S_REG_BPC0L 0xB1
#define CST816S_REG_BPC1H 0xB2
#define CST816S_REG_BPC1L 0xB3
#define CST816S_REG_POWER_MODE 0xA5
#define CST816S_REG_CHIP_ID 0xA7
#define CST816S_REG_PROJ_ID 0xA8
#define CST816S_REG_FW_VERSION 0xA9
#define CST816S_REG_MOTION_MASK 0xEC
#define CST816S_REG_IRQ_PULSE_WIDTH 0xED
#define CST816S_REG_NOR_SCAN_PER 0xEE
#define CST816S_REG_MOTION_S1_ANGLE 0xEF
#define CST816S_REG_LP_SCAN_RAW1H 0xF0
#define CST816S_REG_LP_SCAN_RAW1L 0xF1
#define CST816S_REG_LP_SCAN_RAW2H 0xF2
#define CST816S_REG_LP_SCAN_RAW2L 0xF3
#define CST816S_REG_LP_AUTO_WAKEUP_TIME 0xF4
#define CST816S_REG_LP_SCAN_TH 0xF5
#define CST816S_REG_LP_SCAN_WIN 0xF6
#define CST816S_REG_LP_SCAN_FREQ 0xF7
#define CST816S_REG_LP_SCAN_I_DAC 0xF8
#define CST816S_REG_AUTOSLEEP_TIME 0xF9
#define CST816S_REG_IRQ_CTL 0xFA
#define CST816S_REG_DEBOUNCE_TIME 0xFB
#define CST816S_REG_LONG_PRESS_TIME 0xFC
#define CST816S_REG_IOCTL 0xFD
#define CST816S_REG_DIS_AUTO_SLEEP 0xFE
#define CST816S_MOTION_EN_CON_LR BIT(2)
#define CST816S_MOTION_EN_CON_UR BIT(1)
#define CST816S_MOTION_EN_DCLICK BIT(0)
#define CST816S_IRQ_EN_TEST BIT(7)
#define CST816S_IRQ_EN_TOUCH BIT(6)
#define CST816S_IRQ_EN_CHANGE BIT(5)
#define CST816S_IRQ_EN_MOTION BIT(4)
#define CST816S_IRQ_ONCE_WLP BIT(0)
#define CST816S_IOCTL_SOFT_RTS BIT(2)
#define CST816S_IOCTL_IIC_OD BIT(1)
#define CST816S_IOCTL_EN_1V8 BIT(0)
#define CST816S_POWER_MODE_SLEEP (0x03)
#define CST816S_POWER_MODE_EXPERIMENTAL (0x05)
#define CST816S_EVENT_BITS_POS (0x06)
#define CST816S_RESET_DELAY (5) /* in ms */
#define CST816S_WAIT_DELAY (50) /* in ms */
#define EVENT_PRESS_DOWN 0x00U
#define EVENT_LIFT_UP 0x01U
#define EVENT_CONTACT 0x02U
#define EVENT_NONE 0x03U
/** cst816s configuration (DT). */
struct cst816s_config {
struct i2c_dt_spec i2c;
const struct gpio_dt_spec rst_gpio;
#ifdef CONFIG_INPUT_CST816S_INTERRUPT
const struct gpio_dt_spec int_gpio;
#endif
};
/** cst816s data. */
struct cst816s_data {
/** Device pointer. */
const struct device *dev;
/** Work queue (for deferred read). */
struct k_work work;
#ifdef CONFIG_INPUT_CST816S_INTERRUPT
/** Interrupt GPIO callback. */
struct gpio_callback int_gpio_cb;
#else
/** Timer (polling mode). */
struct k_timer timer;
#endif
};
static int cst816s_process(const struct device *dev)
{
const struct cst816s_config *cfg = dev->config;
int r;
uint8_t event;
uint16_t row, col;
bool pressed;
uint16_t x;
uint16_t y;
r = i2c_burst_read_dt(&cfg->i2c, CST816S_REG_XPOS_H, (uint8_t *)&x, sizeof(x));
if (r < 0) {
LOG_ERR("Could not read x data");
return r;
}
r = i2c_burst_read_dt(&cfg->i2c, CST816S_REG_YPOS_H, (uint8_t *)&y, sizeof(y));
if (r < 0) {
LOG_ERR("Could not read y data");
return r;
}
col = sys_be16_to_cpu(x) & 0x0fff;
row = sys_be16_to_cpu(y) & 0x0fff;
event = (x & 0xff) >> CST816S_EVENT_BITS_POS;
pressed = (event == EVENT_PRESS_DOWN) || (event == EVENT_CONTACT);
LOG_DBG("event: %d, row: %d, col: %d", event, row, col);
if (pressed) {
input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER);
input_report_abs(dev, INPUT_ABS_Y, row, false, K_FOREVER);
input_report_key(dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER);
} else {
input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER);
}
return r;
}
static void cst816s_work_handler(struct k_work *work)
{
struct cst816s_data *data = CONTAINER_OF(work, struct cst816s_data, work);
cst816s_process(data->dev);
}
#ifdef CONFIG_INPUT_CST816S_INTERRUPT
static void cst816s_isr_handler(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
struct cst816s_data *data = CONTAINER_OF(cb, struct cst816s_data, int_gpio_cb);
k_work_submit(&data->work);
}
#else
static void cst816s_timer_handler(struct k_timer *timer)
{
struct cst816s_data *data = CONTAINER_OF(timer, struct cst816s_data, timer);
k_work_submit(&data->work);
}
#endif
static void cst816s_chip_reset(const struct device *dev)
{
const struct cst816s_config *config = dev->config;
int ret;
if (device_is_ready(config->rst_gpio.port)) {
ret = gpio_pin_configure_dt(&config->rst_gpio, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Could not configure reset GPIO pin");
return;
}
gpio_pin_set_dt(&config->rst_gpio, 1);
k_msleep(CST816S_RESET_DELAY);
gpio_pin_set_dt(&config->rst_gpio, 0);
k_msleep(CST816S_WAIT_DELAY);
}
}
static int cst816s_chip_init(const struct device *dev)
{
const struct cst816s_config *cfg = dev->config;
int ret = 0;
uint8_t chip_id = 0;
cst816s_chip_reset(dev);
if (!device_is_ready(cfg->i2c.bus)) {
LOG_ERR("I2C bus %s not ready", cfg->i2c.bus->name);
return -ENODEV;
}
ret = i2c_reg_read_byte_dt(&cfg->i2c, CST816S_REG_CHIP_ID, &chip_id);
if (ret < 0) {
LOG_ERR("failed reading chip id");
return ret;
}
if (chip_id != CST816S_CHIP_ID) {
LOG_ERR("CST816S wrong chip id: returned 0x%x", chip_id);
return -ENODEV;
}
ret = i2c_reg_update_byte_dt(&cfg->i2c, CST816S_REG_IRQ_CTL,
CST816S_IRQ_EN_TOUCH | CST816S_IRQ_EN_CHANGE,
CST816S_IRQ_EN_TOUCH | CST816S_IRQ_EN_CHANGE);
if (ret < 0) {
LOG_ERR("Could not enable irq");
return ret;
}
return ret;
}
static int cst816s_init(const struct device *dev)
{
struct cst816s_data *data = dev->data;
data->dev = dev;
k_work_init(&data->work, cst816s_work_handler);
#ifdef CONFIG_INPUT_CST816S_INTERRUPT
const struct cst816s_config *config = dev->config;
int ret;
if (!device_is_ready(config->int_gpio.port)) {
LOG_ERR("GPIO port %s not ready", config->int_gpio.port->name);
return -ENODEV;
}
ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
if (ret < 0) {
LOG_ERR("Could not configure interrupt GPIO pin");
return ret;
}
ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
if (ret < 0) {
LOG_ERR("Could not configure interrupt GPIO interrupt.");
return ret;
}
gpio_init_callback(&data->int_gpio_cb, cst816s_isr_handler, BIT(config->int_gpio.pin));
ret = gpio_add_callback(config->int_gpio.port, &data->int_gpio_cb);
if (ret < 0) {
LOG_ERR("Could not set gpio callback");
return ret;
}
#else
k_timer_init(&data->timer, cst816s_timer_handler, NULL);
k_timer_start(&data->timer, K_MSEC(CONFIG_INPUT_CST816S_PERIOD),
K_MSEC(CONFIG_INPUT_CST816S_PERIOD));
#endif
return cst816s_chip_init(dev);
}
#define CST816S_DEFINE(index) \
static const struct cst816s_config cst816s_config_##index = { \
.i2c = I2C_DT_SPEC_INST_GET(index), \
COND_CODE_1(CONFIG_INPUT_CST816S_INTERRUPT, \
(.int_gpio = GPIO_DT_SPEC_INST_GET(index, irq_gpios),), ()) \
.rst_gpio = GPIO_DT_SPEC_INST_GET_OR(index, rst_gpios, {}), \
}; \
static struct cst816s_data cst816s_data_##index; \
DEVICE_DT_INST_DEFINE(index, cst816s_init, NULL, &cst816s_data_##index, \
&cst816s_config_##index, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \
NULL);
DT_INST_FOREACH_STATUS_OKAY(CST816S_DEFINE)