/* * Copyright (c) 2017 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief TP Keyboard driver for Actions SoC */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include LOG_MODULE_REGISTER(quad_decoder, CONFIG_SYS_LOG_INPUT_DEV_LEVEL); #define DT_DRV_COMPAT actions_qd /* qd en reg */ #define QD_EN_ZRDIE (0x1 << 8) #define QD_EN_ZFDIE (0x1 << 7) #define QD_EN_YRDIE (0x1 << 6) #define QD_EN_YFDIE (0x1 << 5) #define QD_EN_XRDIE (0x1 << 4) #define QD_EN_XFDIE (0x1 << 3) #define QD_EN_QDZE (0x1 << 2) #define QD_EN_QDYE (0x1 << 1) #define QD_EN_QDXE (0x1 << 0) /* qd ctl reg */ #define QD_CTL_DT(X) (X << 9) #define QD_CTL_DT_MASK QD_CTL_DT(0X7) #define QD_CTL_ZCM(X) (X << 7) #define QD_CTL_YCM(X) (X << 5) #define QD_CTL_XCM(X) (X << 3) #define QD_CTL_ZCDC (1 << 2) #define QD_CTL_YCDC (1 << 1) #define QD_CTL_XCDC (1 << 0) /* qd state reg */ #define QD_STATE_ZRDIP (1 << 8) #define QD_STATE_ZFDIP (1 << 7) #define QD_STATE_YRDIP (1 << 6) #define QD_STATE_YFDIP (1 << 5) #define QD_STATE_XRDIP (1 << 4) #define QD_STATE_XFDIP (1 << 3) #define QD_STATE_CLEAR_PENDING (QD_STATE_ZRDIP | QD_STATE_ZFDIP | QD_STATE_YRDIP | QD_STATE_YFDIP | QD_STATE_XRDIP | QD_STATE_XFDIP) #define QD_STATE_ZTER (1 << 2) #define QD_STATE_YTER (1 << 1) #define QD_STATE_XTER (1 << 0) struct quad_decoder_acts_controller { volatile uint32_t qd_en; volatile uint32_t qd_ctl; volatile uint32_t qd_state; volatile uint32_t x_forward_counter; volatile uint32_t x_reverse_counter; volatile uint32_t y_forward_counter; volatile uint32_t y_reverse_counter; volatile uint32_t z_forward_counter; volatile uint32_t z_reverse_counter; }; struct acts_quad_decoder_data { input_notify_t notify; struct k_delayed_work timer; const struct device *this_dev; uint32_t timestamp; uint16_t prev_x_forward; uint16_t prev_x_reserve; uint16_t prev_y_forward; uint16_t prev_y_reserve; uint16_t prev_z_forward; uint16_t prev_z_reserve; }; struct acts_quad_decoder_config { struct mxkeypad_acts_controller *base; void (*irq_config_func)(void); uint8_t clock_id; uint8_t reset_id; uint8_t pinmux_size; uint32_t poll_total_ms; uint16_t poll_interval_ms; const struct acts_pin_config *pinmux; }; static struct acts_quad_decoder_data quad_decoder_acts_ddata; static const struct acts_pin_config pins_quad_decoder[] = {FOREACH_PIN_MFP(0)}; static void quad_decoder_acts_irq_config(void); static void quad_decoder_acts_disable(struct device *dev); static const struct acts_quad_decoder_config quad_decoder_acts_cdata = { .base = (struct quad_decoder_acts_controller *)DT_INST_REG_ADDR(0), .irq_config_func = quad_decoder_acts_irq_config, .pinmux = pins_quad_decoder, .pinmux_size = ARRAY_SIZE(pins_quad_decoder), .clock_id = DT_INST_PROP(0, clkid), .reset_id = DT_INST_PROP(0, rstid), .poll_interval_ms = DT_INST_PROP(0, poll_interval_ms), .poll_total_ms = DT_INST_PROP(0, poll_total_ms), }; static void quad_decoder_acts_irq_disable(struct quad_decoder_acts_controller *qd) { if(DT_INST_PROP(0, x_direct)) qd->qd_en = qd->qd_en&(~(QD_EN_XRDIE | QD_EN_XFDIE)); if(DT_INST_PROP(0, y_direct)) qd->qd_en = qd->qd_en&(~(QD_EN_YRDIE | QD_EN_YFDIE)); if(DT_INST_PROP(0, z_direct)) qd->qd_en = qd->qd_en&(~(QD_EN_ZRDIE | QD_EN_ZFDIE)); return; } static void quad_decoder_acts_irq_enable(struct quad_decoder_acts_controller *qd) { if(DT_INST_PROP(0, x_direct)) qd->qd_en |= QD_EN_XRDIE | QD_EN_XFDIE; if(DT_INST_PROP(0, y_direct)) qd->qd_en |= QD_EN_YRDIE | QD_EN_YFDIE; if(DT_INST_PROP(0, z_direct)) qd->qd_en |= QD_EN_ZRDIE | QD_EN_ZFDIE; return; } static void quad_decoder_acts_isr(void *arg) { struct device *dev = (struct device *)arg; struct acts_quad_decoder_data *data = dev->data; const struct acts_quad_decoder_config *cfg = dev->config; struct quad_decoder_acts_controller *qd = cfg->base; quad_decoder_acts_irq_enable(qd); qd->qd_state |= QD_STATE_CLEAR_PENDING; data->timestamp = k_uptime_get_32(); k_delayed_work_submit(&data->timer, K_NO_WAIT);//K_MSEC(cfg->poll_interval_ms)); } static void quad_decoder_acts_report_key(struct acts_quad_decoder_data *data, int key_code, int value) { struct input_value val; if (data->notify) { val.keypad.type = EV_KEY; val.keypad.code = key_code; val.keypad.value = value; LOG_DBG("report key_code %d value %d", key_code, value); data->notify(NULL, &val); } } static void quad_decoder_acts_set_clk(const struct acts_quad_decoder_config *cfg, uint32_t freq_hz) { #if 1 clk_set_rate(cfg->clock_id, freq_hz); k_busy_wait(100); #endif } static void quad_decoder_acts_poll(struct k_work *work) { struct acts_quad_decoder_data *data = CONTAINER_OF(work, struct acts_quad_decoder_data, timer); const struct device *dev = data->this_dev; const struct acts_quad_decoder_config *cfg = dev->config; struct quad_decoder_acts_controller *qd = cfg->base; uint8_t time_update; signed long int decoder_value; time_update = 0; if(data->prev_x_forward != qd->x_forward_counter) {//x_f decoder_value = qd->x_forward_counter - data->prev_x_forward; decoder_value = (decoder_value > 0) ? decoder_value : (decoder_value + 65535); quad_decoder_acts_report_key(data, 1, decoder_value); data->prev_x_forward = qd->x_forward_counter; time_update = 1; } if(data->prev_x_reserve != qd->x_reverse_counter) {//x_r decoder_value = qd->x_reverse_counter - data->prev_x_reserve; decoder_value = (decoder_value > 0) ? decoder_value : (decoder_value + 65535); quad_decoder_acts_report_key(data, 2, decoder_value); data->prev_x_reserve = qd->x_reverse_counter; time_update = 1; } if(data->prev_y_forward != qd->y_forward_counter) {//y_f decoder_value = qd->y_forward_counter - data->prev_y_forward; decoder_value = (decoder_value > 0) ? decoder_value : (decoder_value + 65535); quad_decoder_acts_report_key(data, 3, decoder_value); data->prev_y_forward = qd->y_forward_counter; time_update = 1; } if(data->prev_y_reserve != qd->y_reverse_counter) {//y_r decoder_value = qd->y_reverse_counter - data->prev_y_reserve; decoder_value = (decoder_value > 0) ? decoder_value : (decoder_value + 65535); quad_decoder_acts_report_key(data, 4, decoder_value); data->prev_y_reserve = qd->y_reverse_counter; time_update = 1; } if(data->prev_z_forward != qd->z_forward_counter) {//z_f decoder_value = qd->z_forward_counter - data->prev_z_forward; decoder_value = (decoder_value > 0) ? decoder_value : (decoder_value + 65535); quad_decoder_acts_report_key(data, 5, decoder_value); data->prev_z_forward = qd->z_forward_counter; time_update = 1; } if(data->prev_z_reserve != qd->z_reverse_counter) {//z_r decoder_value = qd->z_reverse_counter - data->prev_z_reserve; decoder_value = (decoder_value > 0) ? decoder_value : (decoder_value + 65535); quad_decoder_acts_report_key(data, 6, decoder_value); data->prev_z_reserve = qd->z_reverse_counter; time_update = 1; } if(time_update) data->timestamp = k_uptime_get_32(); out: if ((k_uptime_get_32() - data->timestamp) > cfg->poll_total_ms) { quad_decoder_acts_irq_enable(qd); } else { k_delayed_work_submit(&data->timer, K_MSEC(cfg->poll_interval_ms)); } } static void quad_decoder_acts_enable(struct device *dev) { const struct acts_quad_decoder_config *cfg = dev->config; struct quad_decoder_acts_controller *qd = cfg->base; LOG_DBG("enable quad_decoder"); if(DT_INST_PROP(0, x_direct)) { qd->qd_en |= (qd->qd_en & (~QD_EN_QDXE)) | QD_EN_QDXE; qd->qd_en |= QD_EN_XRDIE | QD_EN_XFDIE; qd->x_forward_counter = 0; qd->x_reverse_counter = 0; } if(DT_INST_PROP(0, y_direct)) { qd->qd_en |= (qd->qd_en & (~QD_EN_QDYE)) | QD_EN_QDYE; qd->qd_en |= QD_EN_YRDIE | QD_EN_YFDIE; qd->y_forward_counter = 0; qd->y_reverse_counter = 0; } if(DT_INST_PROP(0, z_direct)) { qd->qd_en |= (qd->qd_en & (~QD_EN_QDZE)) | QD_EN_QDZE; qd->qd_en |= QD_EN_ZRDIE | QD_EN_ZFDIE; qd->z_forward_counter = 0; qd->z_reverse_counter = 0; } qd->qd_ctl = (qd->qd_ctl & (~ QD_CTL_DT_MASK)) | QD_CTL_DT(2);//DT3 } static void quad_decoder_acts_disable(struct device *dev) { const struct acts_quad_decoder_config *cfg = dev->config; struct quad_decoder_acts_controller *qd = cfg->base; LOG_DBG("disable quad_decoder"); qd->qd_en = 0; qd->qd_ctl = (qd->qd_ctl & (~ QD_CTL_DT_MASK)) | QD_CTL_DT(0);//DT1 } static void quad_decoder_acts_inquiry(struct device *dev, struct input_value *val) { LOG_DBG("inquiry quad_decoder"); } static void quad_decoder_acts_register_notify(struct device *dev, input_notify_t notify) { LOG_DBG("register notify 0x%x", (uint32_t)notify); struct acts_quad_decoder_data *quad_decoder = dev->data; quad_decoder->notify = notify; } static void quad_decoder_acts_unregister_notify(struct device *dev, input_notify_t notify) { LOG_DBG("unregister notify 0x%x", (uint32_t)notify); struct acts_quad_decoder_data *quad_decoder = dev->data; quad_decoder->notify = NULL; } const struct input_dev_driver_api quad_decoder_acts_driver_api = { .enable = quad_decoder_acts_enable, .disable = quad_decoder_acts_disable, .inquiry = quad_decoder_acts_inquiry, .register_notify = quad_decoder_acts_register_notify, .unregister_notify = quad_decoder_acts_unregister_notify, }; static void notify(struct device *dev, struct input_value *val) { printk("the key change: key[%d]:%d\n", val->keypad.code, val->keypad.value); } static void qd_test(const struct device *dev) { //sys_write32(0x18, 0x40068200); //*((REG32)(DEBUGOE)) = 0x3ff4f0; //sys_write32(0x30480, 0x40068208); quad_decoder_acts_register_notify(dev, notify); quad_decoder_acts_enable(dev); while(1); } static int quad_decoder_acts_init(const struct device *dev) { struct acts_quad_decoder_data *data = dev->data; const struct acts_quad_decoder_config *cfg = dev->config; const struct acts_pin_config *pinconf = cfg->pinmux; struct quad_decoder_acts_controller *qd = cfg->base; acts_pinmux_setup_pins(cfg->pinmux, cfg->pinmux_size); quad_decoder_acts_set_clk(cfg, 4000); /* enable QD controller clock */ acts_clock_peripheral_enable(cfg->clock_id); /* reset QD controller */ acts_reset_peripheral(cfg->reset_id); data->this_dev = dev; qd->qd_en = 0; data->prev_x_forward = qd->x_forward_counter; data->prev_x_reserve = qd->x_reverse_counter; data->prev_y_forward = qd->y_forward_counter; data->prev_y_reserve = qd->y_reverse_counter; data->prev_z_forward = qd->z_forward_counter; data->prev_z_reserve = qd->z_reverse_counter; qd->qd_ctl = QD_CTL_DT(0);//debounce config if(DT_INST_PROP(0, x_direct)) { qd->qd_ctl |= QD_CTL_XCDC;//init x direct qd->qd_ctl |= QD_CTL_XCM(2);// (0:0x1 mode, 1:0x2 mode, 2 : 0x4 mode) } if(DT_INST_PROP(0, y_direct)) { qd->qd_ctl |= QD_CTL_YCDC;//init y direct qd->qd_ctl |= QD_CTL_YCM(0);// (0:0x1 mode, 1:0x2 mode, 2 : 0x4 mode) } if(DT_INST_PROP(0, z_direct)) { qd->qd_ctl |= QD_CTL_ZCDC;//init z direct qd->qd_ctl |= QD_CTL_ZCM(0);// (0:0x1 mode, 1:0x2 mode, 2 : 0x4 mode) } cfg->irq_config_func(); k_delayed_work_init(&data->timer, quad_decoder_acts_poll); // qd_test(dev); return 0; } #if DT_NODE_HAS_STATUS(DT_DRV_INST(0), okay) DEVICE_DEFINE(quad_decoder, DT_INST_LABEL(0), quad_decoder_acts_init, NULL, &quad_decoder_acts_ddata, &quad_decoder_acts_cdata, POST_KERNEL, 60, &quad_decoder_acts_driver_api); static void quad_decoder_acts_irq_config(void) { IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), quad_decoder_acts_isr, DEVICE_GET(quad_decoder), 0); irq_enable(DT_INST_IRQN(0)); } #endif // DT_NODE_HAS_STATUS