* [PATCH 1/2] hw/char: Add STM32F7 peripheral: USART
2022-11-30 4:12 [PATCH 0/2] Implement something Evgeny Ermakov
@ 2022-11-30 4:12 ` Evgeny Ermakov
2022-11-30 4:12 ` [PATCH 2/2] hw/input: Add FT5336 touch controller Evgeny Ermakov
2022-11-30 4:17 ` [PATCH 0/2] Implement something Evgeny Ermakov
2 siblings, 0 replies; 4+ messages in thread
From: Evgeny Ermakov @ 2022-11-30 4:12 UTC (permalink / raw)
To: qemu-devel; +Cc: Evgeny Ermakov
Signed-off-by: Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
---
include/hw/char/stm32f7xx_usart.h | 30 +++
hw/char/stm32f7xx_usart.c | 361 ++++++++++++++++++++++++++++++
hw/arm/Kconfig | 1 +
hw/char/Kconfig | 3 +
hw/char/meson.build | 1 +
hw/char/trace-events | 4 +
6 files changed, 400 insertions(+)
create mode 100644 include/hw/char/stm32f7xx_usart.h
create mode 100644 hw/char/stm32f7xx_usart.c
diff --git a/include/hw/char/stm32f7xx_usart.h b/include/hw/char/stm32f7xx_usart.h
new file mode 100644
index 0000000000..ec005be8d8
--- /dev/null
+++ b/include/hw/char/stm32f7xx_usart.h
@@ -0,0 +1,30 @@
+/*
+ * STM32F7XX Universal synchronous/asynchronous receiver transmitter (USART)
+ *
+ * Copyright (c) 2022 Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_CHAR_STM32F7XX_USART_H
+#define HW_CHAR_STM32F7XX_USART_H
+
+#include "hw/arm/stm32f.h"
+#include "chardev/char-fe.h"
+
+#define TYPE_STM32F7XX_USART "stm32f7xx-usart"
+OBJECT_DECLARE_SIMPLE_TYPE(STM32F7XXUSARTState, STM32F7XX_USART)
+
+#define STM32F7XX_USART_R_MAX 11
+
+struct STM32F7XXUSARTState {
+ /*< private >*/
+ STM32FPeripheralState parent_obj;
+
+ uint32_t regs[STM32F7XX_USART_R_MAX];
+
+ CharBackend chr;
+ qemu_irq irq;
+};
+
+#endif /* HW_CHAR_STM32F7XX_USART_H */
diff --git a/hw/char/stm32f7xx_usart.c b/hw/char/stm32f7xx_usart.c
new file mode 100644
index 0000000000..122781705a
--- /dev/null
+++ b/hw/char/stm32f7xx_usart.c
@@ -0,0 +1,361 @@
+/*
+ * STM32F7XX Universal synchronous/asynchronous receiver transmitter (USART)
+ *
+ * Reference documents:
+ * - Reference manual RM0385
+ * "STM32F75xxx and stm32f74xxx advanced Arm(R)-based 32-bit MCUs"
+ * - Reference manual RM0410
+ * "STM32F76xxx and STM32F77xxx advanced Arm(R)-based 32-bit MCUs"
+ *
+ * Copyright (c) 2022 Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/stm32f7xx_usart.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/registerfields.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "trace.h"
+
+#ifndef STM_USART_ERR_DEBUG
+#define STM_USART_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) \
+ do { \
+ if (STM_USART_ERR_DEBUG >= lvl) { \
+ qemu_log("%s: " fmt, __func__, ## args); \
+ } \
+ } while (0)
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+REG32(CR1, 0x00)
+ /* reserved: 31:29, 1 */
+ FIELD(CR1, M1, 28, 1)
+ FIELD(CR1, EOBIE, 27, 1)
+ FIELD(CR1, RTOIE, 26, 1)
+ FIELD(CR1, DEAT, 21, 5)
+ FIELD(CR1, DEDT, 16, 5)
+ FIELD(CR1, OVER8, 15, 1)
+ FIELD(CR1, CMIE, 14, 1)
+ FIELD(CR1, MME, 13, 1)
+ FIELD(CR1, M0, 12, 1)
+ FIELD(CR1, WAKE, 11, 1)
+ FIELD(CR1, PCE, 10, 1)
+ FIELD(CR1, PS, 9, 1)
+ FIELD(CR1, PEIE, 8, 1)
+ FIELD(CR1, TXEIE, 7, 1)
+ FIELD(CR1, TCIE, 6, 1)
+ FIELD(CR1, RXNEIE, 5, 1)
+ FIELD(CR1, IDLEIE, 4, 1)
+ FIELD(CR1, TE, 3, 1)
+ FIELD(CR1, RE, 2, 1)
+ FIELD(CR1, UE, 0, 1)
+REG32(CR2, 0x04)
+ /* reserved: 7, 3:0 */
+ FIELD(CR2, ADD, 24, 8)
+ FIELD(CR2, RTOEN, 23, 1)
+ FIELD(CR2, ABRMOD, 21, 2)
+ FIELD(CR2, ABREN, 20, 1)
+ FIELD(CR2, MSBFIRST, 19, 1)
+ FIELD(CR2, DATAINV, 18, 1)
+ FIELD(CR2, TXINV, 17, 1)
+ FIELD(CR2, RXINV, 16, 1)
+ FIELD(CR2, SWAP, 15, 1)
+ FIELD(CR2, LINEN, 14, 1)
+ FIELD(CR2, STOP, 12, 2)
+ FIELD(CR2, CLKEN, 11, 1)
+ FIELD(CR2, CPOL, 10, 1)
+ FIELD(CR2, CPHA, 9, 1)
+ FIELD(CR2, LBCL, 8, 1)
+ FIELD(CR2, LBDIE, 6, 1)
+ FIELD(CR2, LBDL, 5, 1)
+ FIELD(CR2, ADDM7, 4, 1)
+REG32(CR3, 0x08)
+ /* reserved: 31:25, 16 */
+ FIELD(CR3, TCBGTIE, 24, 1)
+ FIELD(CR3, UCESM, 23, 1)
+ FIELD(CR3, WUFIE, 22, 1)
+ FIELD(CR3, WUS, 20, 2)
+ FIELD(CR3, SCARCNT, 17, 3)
+ FIELD(CR3, DEP, 15, 1)
+ FIELD(CR3, DEM, 14, 1)
+ FIELD(CR3, DDRE, 13, 1)
+ FIELD(CR3, OVRDIS, 12, 1)
+ FIELD(CR3, ONEBIT, 11, 1)
+ FIELD(CR3, CTSIE, 10, 1)
+ FIELD(CR3, CTSE, 9, 1)
+ FIELD(CR3, RTSE, 8, 1)
+ FIELD(CR3, DMAT, 7, 1)
+ FIELD(CR3, DMAR, 6, 1)
+ FIELD(CR3, SCEN, 5, 1)
+ FIELD(CR3, NACK, 4, 1)
+ FIELD(CR3, HDSEL, 3, 1)
+ FIELD(CR3, IRLP, 2, 1)
+ FIELD(CR3, IREN, 1, 1)
+ FIELD(CR3, EIE, 0, 1)
+REG32(BRR, 0x0c)
+ /* reserved: 31:16 */
+ FIELD(BRR, BRR, 0, 15)
+REG32(GTPR, 0x10)
+ /* reserved: 31:16 */
+ FIELD(GTPR, GT, 8, 8)
+ FIELD(GTPR, PSC, 0, 8)
+REG32(RTOR, 0x14)
+ FIELD(RTOR, BLEN, 24, 8)
+ FIELD(RTOR, RTO, 0, 24)
+REG32(RQR, 0x18)
+ /* reserved: 31:5 */
+ FIELD(RQR, TXFRQ, 4, 1)
+ FIELD(RQR, RXFRQ, 3, 1)
+ FIELD(RQR, MMRQ, 2, 1)
+ FIELD(RQR, SBKRQ, 1, 1)
+ FIELD(RQR, ABRRQ, 0, 1)
+REG32(ISR, 0x1c)
+ /* reserved: 31:26, 24:23, 13 */
+ FIELD(ISR, TCBGT, 25, 1)
+ FIELD(ISR, REACK, 22, 1)
+ FIELD(ISR, TEACK, 21, 1)
+ FIELD(ISR, WUF, 20, 1)
+ FIELD(ISR, RWU, 19, 1)
+ FIELD(ISR, SBKF, 18, 1)
+ FIELD(ISR, CMF, 17, 1)
+ FIELD(ISR, BUSY, 16, 1)
+ FIELD(ISR, ABRF, 15, 1)
+ FIELD(ISR, ABRE, 14, 1)
+ FIELD(ISR, EOBF, 12, 1)
+ FIELD(ISR, RTOF, 11, 1)
+ FIELD(ISR, CTS, 10, 1)
+ FIELD(ISR, CTSIF, 9, 1)
+ FIELD(ISR, LBDF, 8, 1)
+ FIELD(ISR, TXE, 7, 1)
+ FIELD(ISR, TC, 6, 1)
+ FIELD(ISR, RXNE, 5, 1)
+ FIELD(ISR, IDLE, 4, 1)
+ FIELD(ISR, ORE, 3, 1)
+ FIELD(ISR, NF, 2, 1)
+ FIELD(ISR, FE, 1, 1)
+ FIELD(ISR, PE, 0, 1)
+REG32(ICR, 0x20)
+ /* reserved: 31:21, 19:18, 16:13, 10, 5 */
+ FIELD(ICR, WUCF, 20, 1)
+ FIELD(ICR, CMCF, 17, 1)
+ FIELD(ICR, EOBCF, 12, 1)
+ FIELD(ICR, RTOCF, 11, 1)
+ FIELD(ICR, CTSCF, 9, 1)
+ FIELD(ICR, LBDCF, 8, 1)
+ FIELD(ICR, TCBGTCF, 7, 1)
+ FIELD(ICR, TCCF, 6, 1)
+ FIELD(ICR, IDLECF, 4, 1)
+ FIELD(ICR, ORECF, 3, 1)
+ FIELD(ICR, NCF, 2, 1)
+ FIELD(ICR, FECF, 1, 1)
+ FIELD(ICR, PECF, 0, 1)
+REG32(RDR, 0x24)
+ /* reserved: 31:9 */
+ FIELD(RDR, RDR, 0, 9)
+REG32(TDR, 0x28)
+ /* reserved: 31:9 */
+ FIELD(TDR, TDR, 0, 9)
+
+
+static int stm32f7xx_usart_can_receive(void *opaque)
+{
+ /* STM32F7XXUSARTState *s = opaque; */
+
+ /* if (!(s->usart_sr & USART_SR_RXNE)) { */
+ /* return 1; */
+ /* } */
+
+ return 0;
+}
+
+static void stm32f7xx_usart_receive(void *opaque, const uint8_t *buf, int size)
+{
+#if 0
+ STM32F7XXUSARTState *s = opaque;
+
+ if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
+ /* USART not enabled - drop the chars */
+ DB_PRINT("Dropping the chars\n");
+ return;
+ }
+
+ s->usart_dr = *buf;
+ s->usart_sr |= USART_SR_RXNE;
+
+ if (s->usart_cr1 & USART_CR1_RXNEIE) {
+ qemu_set_irq(s->irq, 1);
+ }
+
+ DB_PRINT("Receiving: %c\n", s->usart_dr);
+#endif
+}
+
+static uint32_t stm32f7xx_usart_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32F7XXUSARTState *s = opaque;
+
+ trace_stm32f7xx_usart_read(addr);
+
+ switch (addr) {
+ case A_CR1:
+ return s->regs[R_CR1];
+ case A_CR2:
+ return s->regs[R_CR2];
+ case A_CR3:
+ return s->regs[R_CR3];
+ case A_BRR:
+ return s->regs[R_BRR];
+ case A_GTPR:
+ return s->regs[R_GTPR];
+ case A_RTOR:
+ return s->regs[R_RTOR];
+ case A_RQR:
+ return s->regs[R_RQR];
+ case A_ISR:
+ return s->regs[R_ISR];
+ case A_ICR:
+ return s->regs[R_ICR];
+ case A_RDR:
+ return s->regs[R_RDR];
+ case A_TDR:
+ return s->regs[R_TDR];
+ default:
+ STM32F_LOG_BAD_OFFSET();
+ break;
+ }
+
+ return 0;
+}
+
+static void stm32f7xx_usart_write(void *opaque, hwaddr addr,
+ uint32_t value, unsigned int size)
+{
+ STM32F7XXUSARTState *s = opaque;
+ /* unsigned char ch; */
+
+ trace_stm32f7xx_usart_write(addr, value);
+
+ switch (addr) {
+ case A_CR1:
+ s->regs[R_CR1] = value;
+ break;
+ case A_CR2:
+ s->regs[R_CR2] = value;
+ break;
+ case A_CR3:
+ s->regs[R_CR3] = value;
+ break;
+ case A_BRR:
+ s->regs[R_BRR] = value;
+ break;
+ case A_GTPR:
+ s->regs[R_GTPR] = value;
+ break;
+ case A_RTOR:
+ s->regs[R_RTOR] = value;
+ break;
+ case A_RQR:
+ s->regs[R_RQR] = value;
+ break;
+ case A_ISR:
+ s->regs[R_ISR] = value;
+ break;
+ case A_ICR:
+ s->regs[R_ICR] = value;
+ break;
+ case A_RDR:
+ s->regs[R_RDR] = value;
+ break;
+ case A_TDR:
+ if (value < 0xf000) {
+ uint8_t ch = value;
+ /* XXX this blocks entire thread. Rewrite to use
+ * qemu_chr_fe_write and background I/O callbacks */
+ qemu_chr_fe_write_all(&s->chr, &ch, 1);
+ /* XXX I/O are currently synchronous, making it impossible for
+ software to observe transient states where TXE or TC aren't
+ set. Unlike TXE however, which is read-only, software may
+ clear TC by writing 0 to the SR register, so set it again
+ on each write. */
+ /* s->usart_sr |= USART_SR_TC; */
+ }
+ break;
+ default:
+ STM32F_LOG_BAD_OFFSET();
+ break;
+ }
+}
+
+static void stm32f7xx_usart_reset_enter(Object *obj, ResetType type)
+{
+ STM32F7XXUSARTState *s = STM32F7XX_USART(obj);
+
+ memset(s->regs, 0, sizeof(s->regs));
+ s->regs[R_ISR] = 0x020000c0;
+}
+
+static void stm32f7xx_usart_reset_exit(Object *obj)
+{
+ STM32F7XXUSARTState *s = STM32F7XX_USART(obj);
+
+ qemu_set_irq(s->irq, 0);
+}
+
+static void stm32f7xx_usart_init(Object *obj)
+{
+ STM32F7XXUSARTState *s = STM32F7XX_USART(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+}
+
+static void stm32f7xx_usart_realize(DeviceState *dev, Error **errp)
+{
+ STM32F7XXUSARTState *s = STM32F7XX_USART(dev);
+
+ qemu_chr_fe_set_handlers(&s->chr, stm32f7xx_usart_can_receive,
+ stm32f7xx_usart_receive, NULL, NULL,
+ s, NULL, true);
+}
+
+static Property stm32f7xx_usart_properties[] = {
+ DEFINE_PROP_CHR("chardev", STM32F7XXUSARTState, chr),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void stm32f7xx_usart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ STM32FPeripheralClass *pc = STM32F_PERIPHERAL_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = stm32f7xx_usart_realize;
+ device_class_set_props(dc, stm32f7xx_usart_properties);
+ rc->phases.enter = stm32f7xx_usart_reset_enter;
+ rc->phases.exit = stm32f7xx_usart_reset_exit;
+ pc->mmio_size = 0x400;
+ pc->mmio_read = stm32f7xx_usart_read;
+ pc->mmio_write = stm32f7xx_usart_write;
+}
+
+static const TypeInfo stm32f7xx_usart_info = {
+ .name = TYPE_STM32F7XX_USART,
+ .parent = TYPE_STM32F_PERIPHERAL,
+ .instance_size = sizeof(STM32F7XXUSARTState),
+ .instance_init = stm32f7xx_usart_init,
+ .class_init = stm32f7xx_usart_class_init,
+};
+
+static void stm32f7xx_usart_register_types(void)
+{
+ type_register_static(&stm32f7xx_usart_info);
+}
+
+type_init(stm32f7xx_usart_register_types)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index c2f6e748b0..02dfbcb99a 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -376,6 +376,7 @@ config STM32F405_SOC
config STM32F7XX_SOC
bool
select STM32F
+ select STM32F7XX_USART
config XLNX_ZYNQMP_ARM
bool
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 6b6cf2fc1d..22b1cf8062 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -41,6 +41,9 @@ config VIRTIO_SERIAL
config STM32F2XX_USART
bool
+config STM32F7XX_USART
+ bool
+
config CMSDK_APB_UART
bool
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 7b594f51b8..6230750375 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -31,6 +31,7 @@ softmmu_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c'))
softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c'))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
+softmmu_ss.add(when: 'CONFIG_STM32F7XX_USART', if_true: files('stm32f7xx_usart.c'))
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 2ecb36232e..41fa3c0b46 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -105,3 +105,7 @@ cadence_uart_baudrate(unsigned baudrate) "baudrate %u"
# sh_serial.c
sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64
sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64
+
+# stm32f7xx_usart.c
+stm32f7xx_usart_read(uint64_t addr) " addr: 0x%02" PRIx64
+stm32f7xx_usart_write(uint64_t addr, uint64_t data) "addr: 0x%02" PRIx64 " val: 0x%" PRIx64
--
2.38.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] hw/input: Add FT5336 touch controller
2022-11-30 4:12 [PATCH 0/2] Implement something Evgeny Ermakov
2022-11-30 4:12 ` [PATCH 1/2] hw/char: Add STM32F7 peripheral: USART Evgeny Ermakov
@ 2022-11-30 4:12 ` Evgeny Ermakov
2022-11-30 4:17 ` [PATCH 0/2] Implement something Evgeny Ermakov
2 siblings, 0 replies; 4+ messages in thread
From: Evgeny Ermakov @ 2022-11-30 4:12 UTC (permalink / raw)
To: qemu-devel; +Cc: Evgeny Ermakov
Signed-off-by: Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
---
include/hw/input/ft5336.h | 14 ++
hw/input/ft5336.c | 357 ++++++++++++++++++++++++++++++++++++++
hw/input/Kconfig | 4 +
hw/input/meson.build | 2 +
4 files changed, 377 insertions(+)
create mode 100644 include/hw/input/ft5336.h
create mode 100644 hw/input/ft5336.c
diff --git a/include/hw/input/ft5336.h b/include/hw/input/ft5336.h
new file mode 100644
index 0000000000..7bef3f9efb
--- /dev/null
+++ b/include/hw/input/ft5336.h
@@ -0,0 +1,14 @@
+/*
+ * FT5336 touch controller
+ *
+ * Copyright (c) 2022 Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_INPUT_FT5336_H
+#define HW_INPUT_FT5336_H
+
+#define TYPE_FT5336 "ft5336"
+
+#endif
diff --git a/hw/input/ft5336.c b/hw/input/ft5336.c
new file mode 100644
index 0000000000..bacf79201a
--- /dev/null
+++ b/hw/input/ft5336.c
@@ -0,0 +1,357 @@
+/*
+ * FT5336 touch controller
+ *
+ * Copyright (c) 2022 Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/input/ft5336.h"
+#include "hw/i2c/i2c.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "qemu/module.h"
+#include "qemu/log.h"
+#include "qemu/timer.h"
+#include "ui/input.h"
+#include "qom/object.h"
+
+OBJECT_DECLARE_SIMPLE_TYPE(FT5336TouchState, FT5336)
+
+struct FT5336TouchState {
+ I2CSlave parent_obj;
+
+ uint8_t i2c_cycle;
+ uint8_t reg;
+
+ qemu_irq irq;
+
+ int32_t abs_x;
+ int32_t abs_y;
+ uint16_t touch_x;
+ uint16_t touch_y;
+ bool touch_press;
+
+ bool inte;
+};
+
+/* I2C Slave address of touchscreen FocalTech FT5336 */
+#define FT5336_I2C_SLAVE_ADDRESS 0x70
+
+/* Maximum border values of the touchscreen pad */
+#define FT5336_MAX_WIDTH ((uint16_t)480) /* Touchscreen pad max width */
+#define FT5336_MAX_HEIGHT ((uint16_t)272) /* Touchscreen pad max height */
+
+/* Max detectable simultaneous touches */
+#define FT5336_MAX_DETECTABLE_TOUCH 0x05
+
+
+enum {
+ FT5336_P_XH = 0x00,
+ FT5336_P_XL = 0x01,
+ FT5336_P_YH = 0x02,
+ FT5336_P_YL = 0x03,
+ /* Values Pn_XH and Pn_YH related */
+#define FT5336_TOUCH_EVT_FLAG_PRESS_DOWN 0x00
+#define FT5336_TOUCH_EVT_FLAG_LIFT_UP 0x01
+#define FT5336_TOUCH_EVT_FLAG_CONTACT 0x02
+#define FT5336_TOUCH_EVT_FLAG_NO_EVENT 0x03
+
+ FT5336_P_WEIGHT = 0x04,
+ /* Values Pn_WEIGHT related */
+#define FT5336_TOUCH_WEIGHT_MASK 0xFF
+#define FT5336_TOUCH_WEIGHT_SHIFT 0x00
+
+ FT5336_P_MISC = 0x05
+ /* Values related to FT5336_Pn_MISC_REG */
+#define FT5336_TOUCH_AREA_MASK (0x04 << 4))
+#define FT5336_TOUCH_AREA_SHIFT 0x04
+};
+
+enum {
+ FT5336_R_MODE = 0x00,
+#define FT5336_DEV_MODE_WORKING 0x00
+#define FT5336_DEV_MODE_FACTORY 0x04
+
+#define FT5336_DEV_MODE_MASK 0x07
+#define FT5336_DEV_MODE_SHIFT 0x04
+
+ FT5336_R_GEST_ID = 0x01,
+#define FT5336_GEST_ID_NO_GESTURE 0x00
+#define FT5336_GEST_ID_MOVE_UP 0x10
+#define FT5336_GEST_ID_MOVE_RIGHT 0x14
+#define FT5336_GEST_ID_MOVE_DOWN 0x18
+#define FT5336_GEST_ID_MOVE_LEFT 0x1C
+#define FT5336_GEST_ID_SINGLE_CLICK 0x20
+#define FT5336_GEST_ID_DOUBLE_CLICK 0x22
+#define FT5336_GEST_ID_ROTATE_CLOCKWISE 0x28
+#define FT5336_GEST_ID_ROTATE_C_CLOCKWISE 0x29
+#define FT5336_GEST_ID_ZOOM_IN 0x40
+#define FT5336_GEST_ID_ZOOM_OUT 0x49
+
+ FT5336_R_STAT = 0x02,
+#define FT5336_TD_STAT_MASK 0x0F
+#define FT5336_TD_STAT_SHIFT 0x00
+
+ FT5336_R_P1_BASE = 0x03,
+ FT5336_R_P2_BASE = 0x09,
+ FT5336_R_P3_BASE = 0x0f,
+ FT5336_R_P4_BASE = 0x15,
+ FT5336_R_P5_BASE = 0x1b,
+ FT5336_R_P6_BASE = 0x21,
+ FT5336_R_P7_BASE = 0x27,
+ FT5336_R_P8_BASE = 0x2d,
+ FT5336_R_P9_BASE = 0x33,
+ FT5336_R_P10_BASE = 0x39,
+
+#define FT5336_TOUCH_EVT_FLAG_SHIFT 0x06
+#define FT5336_TOUCH_EVT_FLAG_MASK (3 << FT5336_TOUCH_EVT_FLAG_SHIFT))
+
+#define FT5336_TOUCH_POS_MSB_MASK 0x0F
+#define FT5336_TOUCH_POS_MSB_SHIFT 0x00
+
+ /* Values Pn_XL and Pn_YL related */
+#define FT5336_TOUCH_POS_LSB_MASK 0xFF
+#define FT5336_TOUCH_POS_LSB_SHIFT 0x00
+
+ FT5336_R_TH_GROUP = 0x80,
+ /* Values FT5336_TH_GROUP_REG : threshold related */
+#define FT5336_THRESHOLD_MASK 0xFF
+#define FT5336_THRESHOLD_SHIFT 0x00
+
+ FT5336_R_TH_DIFF = 0x85,
+
+ FT5336_R_CTRL = 0x86,
+ /* Values related to FT5336_CTRL_REG */
+
+ /* Will keep the Active mode when there is no touching */
+#define FT5336_CTRL_KEEP_ACTIVE_MODE 0x00
+
+ /* Switching from Active mode to Monitor mode automatically when there is no touching */
+#define FT5336_CTRL_KEEP_AUTO_SWITCH_MONITOR_MODE 0x01
+ FT5336_R_TIMEENTERMONITOR = 0x87,
+ FT5336_R_PERIODACTIVE = 0x88,
+ FT5336_R_PERIODMONITOR = 0x89,
+ FT5336_R_RADIAN_VALUE = 0x91,
+ FT5336_R_OFFSET_LEFT_RIGHT = 0x92,
+ FT5336_R_OFFSET_UP_DOWN = 0x93,
+ FT5336_R_DISTANCE_LEFT = 0x94,
+ FT5336_R_DISTANCE_UP_DOWN = 0x95,
+ FT5336_R_DISTANCE_ZOOM = 0x96,
+
+ FT5336_R_LIB_VER_H = 0xa1,
+ FT5336_R_LIB_VER_L = 0xa2,
+ FT5336_R_CIPHER = 0xa3,
+
+ FT5336_R_GMODE = 0xa4,
+#define FT5336_G_MODE_INTERRUPT_MASK 0x03
+#define FT5336_G_MODE_INTERRUPT_SHIFT 0x00
+
+ /* Possible values of FT5336_GMODE_REG */
+#define FT5336_G_MODE_INTERRUPT_POLLING 0x00
+#define FT5336_G_MODE_INTERRUPT_TRIGGER 0x01
+
+ FT5336_R_PWR_MODE = 0xa5,
+ FT5336_R_FIRMID = 0xa6,
+
+ FT5336_R_CHIP_ID = 0xa8,
+ /* Possible values of FT5336_CHIP_ID_REG */
+#define FT5336_ID_VALUE 0x51
+
+ FT5336_R_RELEASE_CODE_ID = 0xaf,
+ /* Release code version */
+#define FT5336_RELEASE_CODE_ID_REG 0xAF
+
+ FT5336_R_STATE = 0xbc,
+};
+
+
+static uint8_t ft5336_touch_read(FT5336TouchState *s, int reg, int byte)
+{
+ switch (reg) {
+ case FT5336_R_CHIP_ID:
+ return FT5336_ID_VALUE;
+ case FT5336_R_STAT:
+ return s->touch_press ? 1 : 0;
+ case FT5336_R_P1_BASE:
+ switch (byte) {
+ case FT5336_P_XH: return extract16(s->touch_x, 8, 8);
+ case FT5336_P_XL: return extract16(s->touch_x, 0, 8);
+ case FT5336_P_YH: return extract16(s->touch_y, 8, 8);
+ case FT5336_P_YL: return extract16(s->touch_y, 0, 8);
+ default:
+ return 0;
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: unknown register %02x\n", __func__, reg);
+ return 0;
+ }
+}
+
+static void ft5336_touch_write(FT5336TouchState *s, int reg, int byte, uint8_t value)
+{
+ switch (reg) {
+ case FT5336_R_GMODE:
+ s->inte = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: unknown register %02x\n", __func__, reg);
+ break;
+ }
+}
+
+static int ft5336_i2c_event(I2CSlave *i2c, enum i2c_event event)
+{
+ FT5336TouchState *s = FT5336(i2c);
+
+ switch (event) {
+ case I2C_START_RECV:
+ case I2C_START_SEND:
+ s->i2c_cycle = 0;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static uint8_t ft5336_i2c_recv(I2CSlave *i2c)
+{
+ FT5336TouchState *s = FT5336(i2c);
+
+ return ft5336_touch_read(s, s->reg, s->i2c_cycle++);
+}
+
+static int ft5336_i2c_send(I2CSlave *i2c, uint8_t data)
+{
+ FT5336TouchState *s = FT5336(i2c);
+
+ if (!s->i2c_cycle) {
+ s->reg = data;
+ } else {
+ ft5336_touch_write(s, s->reg, s->i2c_cycle - 1, data);
+ }
+ s->i2c_cycle++;
+
+ return 0;
+}
+
+static void ft5336_input_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
+{
+ FT5336TouchState *s = FT5336(dev);
+ InputBtnEvent *btn = NULL;
+ InputMoveEvent *move = NULL;
+
+ switch (evt->type) {
+ case INPUT_EVENT_KIND_BTN:
+ btn = evt->u.btn.data;
+ s->touch_press = btn->down;
+ break;
+ case INPUT_EVENT_KIND_ABS:
+ move = evt->u.rel.data;
+ if (move->axis == INPUT_AXIS_X) {
+ s->abs_x = move->value;
+ } else if (move->axis == INPUT_AXIS_Y) {
+ s->abs_y = move->value;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void ft5336_input_sync(DeviceState *dev)
+{
+ FT5336TouchState *s = FT5336(dev);;
+
+ s->touch_x = qemu_input_scale_axis(s->abs_x,
+ INPUT_EVENT_ABS_MIN,
+ INPUT_EVENT_ABS_MAX, 0, 1777);
+ s->touch_y = qemu_input_scale_axis(s->abs_y,
+ INPUT_EVENT_ABS_MIN,
+ INPUT_EVENT_ABS_MAX, 0, 1023);
+
+ if (s->touch_press) {
+ if (s->inte) {
+ qemu_irq_pulse(s->irq);
+ }
+ }
+}
+
+static QemuInputHandler ft5336_input_handler = {
+ .name = "QEMU FT5336-driven Touchscreen",
+ .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
+ .event = ft5336_input_event,
+ .sync = ft5336_input_sync
+};
+
+static void ft5336_touch_reset_enter(Object *obj, ResetType type)
+{
+ FT5336TouchState *s = FT5336(obj);
+
+ s->inte = false;
+}
+
+static void ft5336_realize(DeviceState *dev, Error **errp)
+{
+ FT5336TouchState *s = FT5336(dev);
+ qdev_init_gpio_out(dev, &s->irq, 1);
+
+ qemu_input_handler_register((DeviceState *) s, &ft5336_input_handler);
+}
+
+static int ft5336_touch_post_load(void *opaque, int version_id)
+{
+ /* FT5336TouchState *s = opaque; */
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_ft5336_touch = {
+ .name = TYPE_FT5336,
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .post_load = ft5336_touch_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_I2C_SLAVE(parent_obj, FT5336TouchState),
+ VMSTATE_UINT8(i2c_cycle, FT5336TouchState),
+ VMSTATE_UINT8(reg, FT5336TouchState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void ft5336_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = ft5336_realize;
+ dc->vmsd = &vmstate_ft5336_touch;
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+ rc->phases.enter = ft5336_touch_reset_enter;
+
+ sc->event = ft5336_i2c_event;
+ sc->recv = ft5336_i2c_recv;
+ sc->send = ft5336_i2c_send;
+}
+
+static const TypeInfo ft5336_info = {
+ .name = TYPE_FT5336,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(FT5336TouchState),
+ .class_init = ft5336_class_init
+};
+
+static void ft5336_register_types(void)
+{
+ type_register_static(&ft5336_info);
+}
+
+type_init(ft5336_register_types)
diff --git a/hw/input/Kconfig b/hw/input/Kconfig
index 55865bb386..73a6f67216 100644
--- a/hw/input/Kconfig
+++ b/hw/input/Kconfig
@@ -46,3 +46,7 @@ config TSC210X
config LASIPS2
select PS2
+
+config FT5336
+ bool
+ depends on I2C
diff --git a/hw/input/meson.build b/hw/input/meson.build
index 8deb011d4a..c892ecbeb7 100644
--- a/hw/input/meson.build
+++ b/hw/input/meson.build
@@ -16,3 +16,5 @@ softmmu_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_keypad.c'))
softmmu_ss.add(when: 'CONFIG_TSC210X', if_true: files('tsc210x.c'))
softmmu_ss.add(when: 'CONFIG_LASIPS2', if_true: files('lasips2.c'))
+
+softmmu_ss.add(when: 'CONFIG_FT5336', if_true: files('ft5336.c'))
--
2.38.1
^ permalink raw reply related [flat|nested] 4+ messages in thread