From 89ac35cc550700840e92ea4cffd40b7c5e052f00 Mon Sep 17 00:00:00 2001 From: Jorge Guzman Date: Mon, 31 Aug 2026 01:23:30 -0300 Subject: [PATCH] boards/esp32p4-tab5: add the ILI9881C and GT911 hardware variant The Tab5 ships in two hardware variants and the board supported only one of them. The earlier units carry an ILI9881C panel and a GT911 touch controller, the later ones a ST7121/ST7123 panel and a ST7123 touch controller, and the two always come as a pair. On an earlier unit the panel stays lit but black, and the touch bring-up fails with "failed to register ST7123: -5". Add the ILI9881C initialization table, taken from the Espressif BSP, along with the display timings it needs, which differ from the ST7123 ones in the DPI clock (60 MHz instead of 70 MHz) and in every porch. The panel identification lives on command page 1 and is read and logged during bring-up, so the boot log says which panel answered. Add the GT911 to the touch controller choice. These units have a pull-up to 3V3 on the touch interrupt line that keeps the controller from scanning, so the line is driven low instead of being used as an interrupt, and contacts are picked up when the device is read. The controller identification is logged the same way. Split esp32p4_touch.c into one file per controller, which is how the panels are already handled, and document both variants together with the I2C scan that tells which one is fitted. The defaults are unchanged, so an existing configuration still selects the ST7121 panel and the ST7123 touch controller. Signed-off-by: Jorge Guzman --- .../esp32p4/boards/esp32p4-tab5/index.rst | 47 +- boards/risc-v/esp32p4/esp32p4-tab5/Kconfig | 42 +- .../esp32p4/esp32p4-tab5/include/board.h | 27 +- .../esp32p4/esp32p4-tab5/src/CMakeLists.txt | 8 +- .../risc-v/esp32p4/esp32p4-tab5/src/Make.defs | 8 +- .../esp32p4-tab5/src/esp32p4_display.c | 5 +- .../esp32p4-tab5/src/esp32p4_lcd_ili9881c.c | 493 ++++++++++++++++++ .../esp32p4-tab5/src/esp32p4_lcd_ili9881c.h | 81 +++ .../esp32p4-tab5/src/esp32p4_touch_gt911.c | 232 +++++++++ ...esp32p4_touch.c => esp32p4_touch_st7123.c} | 3 +- 10 files changed, 930 insertions(+), 16 deletions(-) create mode 100644 boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c create mode 100644 boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h create mode 100644 boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c rename boards/risc-v/esp32p4/esp32p4-tab5/src/{esp32p4_touch.c => esp32p4_touch_st7123.c} (98%) diff --git a/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst b/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst index 8a78b2fa0a1..60710556b7d 100644 --- a/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst +++ b/Documentation/platforms/risc-v/esp32p4/boards/esp32p4-tab5/index.rst @@ -140,6 +140,45 @@ The Tab5 ships with ESP32-P4 **revision v1.0**. The ``nsh`` defconfig sets ``CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y`` accordingly. A harmless boot warning is printed because the upstream default targets rev >= 3.0. +Display panel and touch controller +================================== + +The Tab5 ships in two hardware variants, and they always come as a pair: + +======================= ============================ ========================== +Variant Panel Touch controller +======================= ============================ ========================== +Earlier units ILI9881C GT911 (I2C ``0x14``) +Later units ST7121 / ST7123 ST7123 (I2C ``0x55``) +======================= ============================ ========================== + +The panels need different initialization tables and different display +timings, so the wrong selection leaves the panel lit but black, and the wrong +touch selection fails the bring-up with:: + + ERROR: failed to register ST7123: -5 + +Identify the board by scanning I2C0 with the ``nsh`` configuration. The +address that answers tells which variant is fitted, and therefore which +panel to select as well:: + + nsh> i2c dev -b 0 0x03 0x77 + +Select the panel with ``ESP32P4_TAB5_LCD_ST7121`` (the default), +``ESP32P4_TAB5_LCD_ST7123`` or ``ESP32P4_TAB5_LCD_ILI9881C``, and the touch +controller with ``ESP32P4_TAB5_TOUCH_ST7123`` (the default) or +``ESP32P4_TAB5_TOUCH_GT911``, both under the board menu. + +Both panels report their identification at boot, which confirms the +selection. The ILI9881C answers ``98 81`` in the first two ID registers:: + + ili9881c: panel ID 98 81 5c + gt911: product "911" (39 31 31 00) fw 1060 + +On the GT911 units the touch interrupt line has a pull-up to 3V3 that keeps +the controller from scanning, so the board drives it low instead of using it +as an interrupt. Contacts are picked up when the device is read. + Configurations ============== @@ -165,7 +204,6 @@ lvgl_demo --------- LVGL demo configuration with touch support. -Requires the ST7123 touch controller version. .. note:: This configuration redirects the console to UART0 instead of the USB Serial/JTAG port @@ -181,11 +219,12 @@ lvgl_term --------- LVGL terminal configuration with touch support. -Requires the ST7123 touch controller version. .. note:: - This configuration redirects the console to UART0 instead of the USB Serial/JTAG port - and sets a custom entry point to open LVGL terminal on screen. + This configuration starts the LVGL terminal on the panel as its entry + point, and it runs its own NSH on a pseudo-terminal. The console is kept + on the USB Serial/JTAG port (exposed as ``ttyACM`` on the host), which + carries the system log. .. code-block:: console diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/Kconfig b/boards/risc-v/esp32p4/esp32p4-tab5/Kconfig index 44a9ed1c838..87c4df21537 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/Kconfig +++ b/boards/risc-v/esp32p4/esp32p4-tab5/Kconfig @@ -96,15 +96,53 @@ config ESP32P4_TAB5_LCD_ST7123 ---help--- Use the ST7123 initialization table and display timings. +config ESP32P4_TAB5_LCD_ILI9881C + bool "ILI9881C" + ---help--- + Use the ILI9881C initialization table and display timings. This is + the panel fitted to the earlier Tab5 units, the ones that also carry + the GT911 touch controller. + endchoice config ESP32P4_TAB5_TOUCHSCREEN bool "Touch Screen Controller" default n select INPUT - select INPUT_ST7123 select ESP32P4_TAB5_HMI_POWER ---help--- - Initialize the ST7123 touch screen controller. + Initialize the touch screen controller. + +if ESP32P4_TAB5_TOUCHSCREEN + +choice + prompt "Touch screen controller" + default ESP32P4_TAB5_TOUCH_ST7123 + +config ESP32P4_TAB5_TOUCH_ST7123 + bool "ST7123" + select INPUT_ST7123 + ---help--- + Sitronix ST7123, fitted to the Tab5 units that ship with the + ST7121/ST7123 panel. Answers on I2C address 0x55. + +config ESP32P4_TAB5_TOUCH_GT911 + bool "GT911" + select INPUT_GT9XX + ---help--- + Goodix GT911, fitted to the earlier Tab5 units. + +endchoice + +config ESP32P4_TAB5_TOUCH_GT911_ADDR + hex "GT911 I2C address" + depends on ESP32P4_TAB5_TOUCH_GT911 + default 0x14 + ---help--- + The GT911 latches its I2C address from the INT pin while it is + held in reset: either 0x14 or 0x5d. Scan the bus with + "i2c dev -b 0 0x03 0x77" if unsure. + +endif # ESP32P4_TAB5_TOUCHSCREEN endif # ARCH_BOARD_ESP32P4_TAB5 diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/include/board.h b/boards/risc-v/esp32p4/esp32p4-tab5/include/board.h index 9758200e99f..75b2d9c740c 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/include/board.h +++ b/boards/risc-v/esp32p4/esp32p4-tab5/include/board.h @@ -63,27 +63,42 @@ * * Enable /dev/fb0 with CONFIG_ESP32P4_TAB5_LCD (see configs/lcd), which * selects power + MIPI host + VIDEO_FB. Select the matching panel with - * CONFIG_ESP32P4_TAB5_LCD_ST7121 or CONFIG_ESP32P4_TAB5_LCD_ST7123. + * CONFIG_ESP32P4_TAB5_LCD_ST7121, CONFIG_ESP32P4_TAB5_LCD_ST7123 or + * CONFIG_ESP32P4_TAB5_LCD_ILI9881C (board version 1, paired with GT911). */ #define TAB5_GPIO_LCD_BL_EN 22 /* Backlight enable -> ME2212 boost EN */ #define TAB5_MIPI_DSI_H_RES 720 #define TAB5_MIPI_DSI_V_RES 1280 -#define TAB5_MIPI_DSI_DPI_CLK_MHZ 70 -#define TAB5_MIPI_DSI_HSYNC_PULSE_WIDTH 2 -#define TAB5_MIPI_DSI_HSYNC_BACK_PORCH 40 -#define TAB5_MIPI_DSI_HSYNC_FRONT_PORCH 40 #define TAB5_MIPI_DSI_LANES 2 -#ifdef CONFIG_ESP32P4_TAB5_LCD_ST7123 +#if defined(CONFIG_ESP32P4_TAB5_LCD_ILI9881C) +# define TAB5_LCD_PANEL_NAME "ILI9881C" +# define TAB5_MIPI_DSI_DPI_CLK_MHZ 60 +# define TAB5_MIPI_DSI_HSYNC_PULSE_WIDTH 40 +# define TAB5_MIPI_DSI_HSYNC_BACK_PORCH 140 +# define TAB5_MIPI_DSI_HSYNC_FRONT_PORCH 40 +# define TAB5_MIPI_DSI_VSYNC_PULSE_WIDTH 4 +# define TAB5_MIPI_DSI_VSYNC_BACK_PORCH 20 +# define TAB5_MIPI_DSI_VSYNC_FRONT_PORCH 20 +# define TAB5_MIPI_DSI_LANE_BITRATE_MBPS 1000 +#elif defined(CONFIG_ESP32P4_TAB5_LCD_ST7123) # define TAB5_LCD_PANEL_NAME "ST7123" +# define TAB5_MIPI_DSI_DPI_CLK_MHZ 70 +# define TAB5_MIPI_DSI_HSYNC_PULSE_WIDTH 2 +# define TAB5_MIPI_DSI_HSYNC_BACK_PORCH 40 +# define TAB5_MIPI_DSI_HSYNC_FRONT_PORCH 40 # define TAB5_MIPI_DSI_VSYNC_PULSE_WIDTH 2 # define TAB5_MIPI_DSI_VSYNC_BACK_PORCH 8 # define TAB5_MIPI_DSI_VSYNC_FRONT_PORCH 220 # define TAB5_MIPI_DSI_LANE_BITRATE_MBPS 1000 #else # define TAB5_LCD_PANEL_NAME "ST7121" +# define TAB5_MIPI_DSI_DPI_CLK_MHZ 70 +# define TAB5_MIPI_DSI_HSYNC_PULSE_WIDTH 2 +# define TAB5_MIPI_DSI_HSYNC_BACK_PORCH 40 +# define TAB5_MIPI_DSI_HSYNC_FRONT_PORCH 40 # define TAB5_MIPI_DSI_VSYNC_PULSE_WIDTH 20 # define TAB5_MIPI_DSI_VSYNC_BACK_PORCH 24 # define TAB5_MIPI_DSI_VSYNC_FRONT_PORCH 200 diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt b/boards/risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt index 7635e1315ed..4504f73ec9f 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt +++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/CMakeLists.txt @@ -36,11 +36,17 @@ if(CONFIG_ESP32P4_TAB5_LCD) list(APPEND SRCS esp32p4_lcd_st7121.c) elseif(CONFIG_ESP32P4_TAB5_LCD_ST7123) list(APPEND SRCS esp32p4_lcd_st7123.c) + elseif(CONFIG_ESP32P4_TAB5_LCD_ILI9881C) + list(APPEND SRCS esp32p4_lcd_ili9881c.c) endif() endif() if(CONFIG_ESP32P4_TAB5_TOUCHSCREEN) - list(APPEND SRCS esp32p4_touch.c) + if(CONFIG_ESP32P4_TAB5_TOUCH_ST7123) + list(APPEND SRCS esp32p4_touch_st7123.c) + elseif(CONFIG_ESP32P4_TAB5_TOUCH_GT911) + list(APPEND SRCS esp32p4_touch_gt911.c) + endif() endif() if(CONFIG_BOARDCTL) diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs b/boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs index b1537ba3531..5d5e02d3842 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs +++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/Make.defs @@ -42,11 +42,17 @@ ifeq ($(CONFIG_ESP32P4_TAB5_LCD),y) CSRCS += esp32p4_lcd_st7121.c else ifeq ($(CONFIG_ESP32P4_TAB5_LCD_ST7123),y) CSRCS += esp32p4_lcd_st7123.c + else ifeq ($(CONFIG_ESP32P4_TAB5_LCD_ILI9881C),y) + CSRCS += esp32p4_lcd_ili9881c.c endif endif ifeq ($(CONFIG_ESP32P4_TAB5_TOUCHSCREEN),y) - CSRCS += esp32p4_touch.c + ifeq ($(CONFIG_ESP32P4_TAB5_TOUCH_ST7123),y) + CSRCS += esp32p4_touch_st7123.c + else ifeq ($(CONFIG_ESP32P4_TAB5_TOUCH_GT911),y) + CSRCS += esp32p4_touch_gt911.c + endif endif ifeq ($(CONFIG_BOARDCTL),y) diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_display.c b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_display.c index 7225b722d06..0f4d104cf27 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_display.c +++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_display.c @@ -54,7 +54,10 @@ #include "esp32p4-tab5.h" -#ifdef CONFIG_ESP32P4_TAB5_LCD_ST7123 +#if defined(CONFIG_ESP32P4_TAB5_LCD_ILI9881C) +# include "esp32p4_lcd_ili9881c.h" +# define tab5_panel_initialize tab5_ili9881c_initialize +#elif defined(CONFIG_ESP32P4_TAB5_LCD_ST7123) # include "esp32p4_lcd_st7123.h" # define tab5_panel_initialize tab5_st7123_initialize #else diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c new file mode 100644 index 00000000000..bf94bdd2369 --- /dev/null +++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c @@ -0,0 +1,493 @@ +/**************************************************************************** + * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* ILI9881C panel bring-up for M5Stack Tab5, fitted to the units that also + * carry the GT911 touch controller. Init table sourced from + * https://github.com/espressif/esp-bsp under + * bsp/m5stack_tab5/priv_include/disp_init_data.h. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "esp32p4-tab5.h" +#include "esp32p4_lcd_ili9881c.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ILI9881C_NAME "ili9881c" + +/* Command page selection: 0xff 0x98 0x81 */ + +#define ILI9881C_CMD_PAGE 0xff +#define ILI9881C_PAGE_BYTE0 0x98 +#define ILI9881C_PAGE_BYTE1 0x81 +#define ILI9881C_PAGE0 0x00 +#define ILI9881C_PAGE1 0x01 + +/* On command page 1, registers 0x00..0x02 hold the panel identification */ + +#define ILI9881C_REG_ID1 0x00 +#define ILI9881C_ID1_ILITEK 0x98 +#define ILI9881C_ID2_ILITEK 0x81 + +/* Time the panel needs after leaving sleep mode */ + +#define ILI9881C_SLEEP_OUT_MS 120 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Vendor initialization table, as a flat byte stream: DCS command, payload + * length, payload. It walks the panel through its command pages, so the + * order matters, and ends back on page 0 with display on (0x29). + */ + +static const uint8_t g_ili9881c_init[] = +{ + 0xff, 3, 0x98, 0x81, 0x01, + 0xb7, 1, 0x03, + 0xff, 3, 0x98, 0x81, 0x03, + 0x01, 1, 0x00, + 0x02, 1, 0x00, + 0x03, 1, 0x73, + 0x04, 1, 0x00, + 0x05, 1, 0x00, + 0x06, 1, 0x08, + 0x07, 1, 0x00, + 0x08, 1, 0x00, + 0x09, 1, 0x1b, + 0x0a, 1, 0x01, + 0x0b, 1, 0x01, + 0x0c, 1, 0x0d, + 0x0d, 1, 0x01, + 0x0e, 1, 0x01, + 0x0f, 1, 0x26, + 0x10, 1, 0x26, + 0x11, 1, 0x00, + 0x12, 1, 0x00, + 0x13, 1, 0x02, + 0x14, 1, 0x00, + 0x15, 1, 0x00, + 0x16, 1, 0x00, + 0x17, 1, 0x00, + 0x18, 1, 0x00, + 0x19, 1, 0x00, + 0x1a, 1, 0x00, + 0x1b, 1, 0x00, + 0x1c, 1, 0x00, + 0x1d, 1, 0x00, + 0x1e, 1, 0x40, + 0x1f, 1, 0x00, + 0x20, 1, 0x06, + 0x21, 1, 0x01, + 0x22, 1, 0x00, + 0x23, 1, 0x00, + 0x24, 1, 0x00, + 0x25, 1, 0x00, + 0x26, 1, 0x00, + 0x27, 1, 0x00, + 0x28, 1, 0x33, + 0x29, 1, 0x03, + 0x2a, 1, 0x00, + 0x2b, 1, 0x00, + 0x2c, 1, 0x00, + 0x2d, 1, 0x00, + 0x2e, 1, 0x00, + 0x2f, 1, 0x00, + 0x30, 1, 0x00, + 0x31, 1, 0x00, + 0x32, 1, 0x00, + 0x33, 1, 0x00, + 0x34, 1, 0x00, + 0x35, 1, 0x00, + 0x36, 1, 0x00, + 0x37, 1, 0x00, + 0x38, 1, 0x00, + 0x39, 1, 0x00, + 0x3a, 1, 0x00, + 0x3b, 1, 0x00, + 0x3c, 1, 0x00, + 0x3d, 1, 0x00, + 0x3e, 1, 0x00, + 0x3f, 1, 0x00, + 0x40, 1, 0x00, + 0x41, 1, 0x00, + 0x42, 1, 0x00, + 0x43, 1, 0x00, + 0x44, 1, 0x00, + 0x50, 1, 0x01, + 0x51, 1, 0x23, + 0x52, 1, 0x45, + 0x53, 1, 0x67, + 0x54, 1, 0x89, + 0x55, 1, 0xab, + 0x56, 1, 0x01, + 0x57, 1, 0x23, + 0x58, 1, 0x45, + 0x59, 1, 0x67, + 0x5a, 1, 0x89, + 0x5b, 1, 0xab, + 0x5c, 1, 0xcd, + 0x5d, 1, 0xef, + 0x5e, 1, 0x11, + 0x5f, 1, 0x02, + 0x60, 1, 0x00, + 0x61, 1, 0x07, + 0x62, 1, 0x06, + 0x63, 1, 0x0e, + 0x64, 1, 0x0f, + 0x65, 1, 0x0c, + 0x66, 1, 0x0d, + 0x67, 1, 0x02, + 0x68, 1, 0x02, + 0x69, 1, 0x02, + 0x6a, 1, 0x02, + 0x6b, 1, 0x02, + 0x6c, 1, 0x02, + 0x6d, 1, 0x02, + 0x6e, 1, 0x02, + 0x6f, 1, 0x02, + 0x70, 1, 0x02, + 0x71, 1, 0x02, + 0x72, 1, 0x02, + 0x73, 1, 0x05, + 0x74, 1, 0x01, + 0x75, 1, 0x02, + 0x76, 1, 0x00, + 0x77, 1, 0x07, + 0x78, 1, 0x06, + 0x79, 1, 0x0e, + 0x7a, 1, 0x0f, + 0x7b, 1, 0x0c, + 0x7c, 1, 0x0d, + 0x7d, 1, 0x02, + 0x7e, 1, 0x02, + 0x7f, 1, 0x02, + 0x80, 1, 0x02, + 0x81, 1, 0x02, + 0x82, 1, 0x02, + 0x83, 1, 0x02, + 0x84, 1, 0x02, + 0x85, 1, 0x02, + 0x86, 1, 0x02, + 0x87, 1, 0x02, + 0x88, 1, 0x02, + 0x89, 1, 0x05, + 0x8a, 1, 0x01, + 0xff, 3, 0x98, 0x81, 0x04, + 0x38, 1, 0x01, + 0x39, 1, 0x00, + 0x6c, 1, 0x15, + 0x6e, 1, 0x1a, + 0x6f, 1, 0x25, + 0x3a, 1, 0xa4, + 0x8d, 1, 0x20, + 0x87, 1, 0xba, + 0x3b, 1, 0x98, + 0xff, 3, 0x98, 0x81, 0x01, + 0x22, 1, 0x0a, + 0x31, 1, 0x00, + 0x50, 1, 0x6b, + 0x51, 1, 0x66, + 0x53, 1, 0x73, + 0x55, 1, 0x8b, + 0x60, 1, 0x1b, + 0x61, 1, 0x01, + 0x62, 1, 0x0c, + 0x63, 1, 0x00, + 0xa0, 1, 0x00, + 0xa1, 1, 0x15, + 0xa2, 1, 0x1f, + 0xa3, 1, 0x13, + 0xa4, 1, 0x11, + 0xa5, 1, 0x21, + 0xa6, 1, 0x17, + 0xa7, 1, 0x1b, + 0xa8, 1, 0x6b, + 0xa9, 1, 0x1e, + 0xaa, 1, 0x2b, + 0xab, 1, 0x5d, + 0xac, 1, 0x19, + 0xad, 1, 0x14, + 0xae, 1, 0x4b, + 0xaf, 1, 0x1d, + 0xb0, 1, 0x27, + 0xb1, 1, 0x49, + 0xb2, 1, 0x5d, + 0xb3, 1, 0x39, + 0xc0, 1, 0x00, + 0xc1, 1, 0x01, + 0xc2, 1, 0x0c, + 0xc3, 1, 0x11, + 0xc4, 1, 0x15, + 0xc5, 1, 0x28, + 0xc6, 1, 0x1b, + 0xc7, 1, 0x1c, + 0xc8, 1, 0x62, + 0xc9, 1, 0x1c, + 0xca, 1, 0x29, + 0xcb, 1, 0x60, + 0xcc, 1, 0x16, + 0xcd, 1, 0x17, + 0xce, 1, 0x4a, + 0xcf, 1, 0x23, + 0xd0, 1, 0x24, + 0xd1, 1, 0x4f, + 0xd2, 1, 0x5f, + 0xd3, 1, 0x39, + 0xff, 3, 0x98, 0x81, 0x00, + 0x35, 0, + 0xfe, 0, + 0x29, 0, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ili9881c_select_page + * + * Description: + * Select one of the ILI9881C command pages. + * + * Input Parameters: + * device - The MIPI DSI device. + * page - The command page to select. + * + * Returned Value: + * Zero on success, a negated errno value on failure. + * + ****************************************************************************/ + +static int ili9881c_select_page(FAR struct mipi_dsi_device *device, + uint8_t page) +{ + const uint8_t sel[3] = + { + ILI9881C_PAGE_BYTE0, ILI9881C_PAGE_BYTE1, page + }; + + ssize_t n = mipi_dsi_dcs_write(device, ILI9881C_CMD_PAGE, sel, + sizeof(sel)); + + return n < 0 ? (int)n : OK; +} + +/**************************************************************************** + * Name: ili9881c_report_id + * + * Description: + * Read and log the panel identification from registers 0x00..0x02 of + * command page 1, which must already be selected. An Ilitek panel + * answers 0x98 0x81 in the first two. A failed read is not fatal. + * + * Input Parameters: + * device - The MIPI DSI device. + * + ****************************************************************************/ + +static void ili9881c_report_id(FAR struct mipi_dsi_device *device) +{ + uint8_t id[3] = + { + 0, 0, 0 + }; + + ssize_t n; + int i; + + for (i = 0; i < 3; i++) + { + n = mipi_dsi_dcs_read(device, ILI9881C_REG_ID1 + i, &id[i], 1); + if (n < 0) + { + syslog(LOG_WARNING, "ili9881c: ID read %d failed: %d\n", + i, (int)n); + return; + } + } + + syslog(LOG_INFO, "ili9881c: panel ID %02x %02x %02x%s\n", + id[0], id[1], id[2], + (id[0] == ILI9881C_ID1_ILITEK && id[1] == ILI9881C_ID2_ILITEK) ? + "" : " (unexpected: not an Ilitek panel?)"); +} + +/**************************************************************************** + * Name: ili9881c_send_init + * + * Description: + * Send the vendor initialization table. + * + * Input Parameters: + * device - The MIPI DSI device. + * + * Returned Value: + * Zero on success, a negated errno value on failure. + * + ****************************************************************************/ + +static int ili9881c_send_init(FAR struct mipi_dsi_device *device) +{ + size_t i = 0; + uint8_t cmd; + uint8_t len; + ssize_t n; + + while (i + 1 < nitems(g_ili9881c_init)) + { + cmd = g_ili9881c_init[i]; + len = g_ili9881c_init[i + 1]; + i += 2; + + n = mipi_dsi_dcs_write(device, cmd, + len > 0 ? &g_ili9881c_init[i] : NULL, len); + if (n < 0) + { + syslog(LOG_ERR, "ili9881c: cmd %02x failed: %d\n", + cmd, (int)n); + return (int)n; + } + + i += len; + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tab5_ili9881c_initialize + * + * Description: + * Register the ILI9881C as a mipi_dsi_device, attach it to the Espressif + * host, report the panel identification and send the vendor DCS + * initialization table. Does not start video. + * + * Input Parameters: + * host - Registered MIPI-DSI host (esp_mipi_dsi_host_get()) + * + * Returned Value: + * Pointer to the registered device on success; NULL on failure. + * + ****************************************************************************/ + +FAR struct mipi_dsi_device *tab5_ili9881c_initialize( + FAR struct mipi_dsi_host *host) +{ + FAR struct mipi_dsi_device *device; + const uint8_t colmod = MIPI_DCS_PIXEL_FMT_16BIT; + const uint8_t madctl = 0x00; + int ret; + + if (host == NULL) + { + return NULL; + } + + device = mipi_dsi_device_register(host, ILI9881C_NAME, 0); + if (device == NULL) + { + syslog(LOG_ERR, "ERROR: mipi_dsi_device_register failed\n"); + return NULL; + } + + device->lanes = TAB5_MIPI_DSI_LANES; + device->format = MIPI_DSI_FMT_RGB565; + device->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + device->hs_rate = TAB5_MIPI_DSI_LANE_BITRATE_MBPS * 1000000UL; + device->lp_rate = 0; + + ret = mipi_dsi_attach(device); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: attach failed: %d\n", ret); + return NULL; + } + + /* The identification registers live on command page 1 */ + + ret = ili9881c_select_page(device, ILI9881C_PAGE1); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: page 1 select failed: %d\n", ret); + return NULL; + } + + ili9881c_report_id(device); + + ret = ili9881c_select_page(device, ILI9881C_PAGE0); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: page 0 select failed: %d\n", ret); + return NULL; + } + + ret = mipi_dsi_dcs_exit_sleep_mode(device); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: exit sleep mode failed: %d\n", ret); + return NULL; + } + + up_mdelay(ILI9881C_SLEEP_OUT_MS); + + if (mipi_dsi_dcs_write(device, MIPI_DCS_SET_ADDRESS_MODE, &madctl, 1) < 0 + || mipi_dsi_dcs_write(device, MIPI_DCS_SET_PIXEL_FORMAT, + &colmod, 1) < 0) + { + syslog(LOG_ERR, "ERROR: address/pixel format setup failed\n"); + return NULL; + } + + ret = ili9881c_send_init(device); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: DCS init failed: %d\n", ret); + return NULL; + } + + return device; +} diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h new file mode 100644 index 00000000000..7dd4c54e1cb --- /dev/null +++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h @@ -0,0 +1,81 @@ +/**************************************************************************** + * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_lcd_ili9881c.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* ST7121 panel bring-up for M5Stack Tab5. + * + * Init init table sourced from https://github.com/espressif/esp-iot-solution + * under components/display/lcd/esp_lcd_st7121/esp_lcd_st7121.c. + */ +#ifndef __BOARDS_RISCV_ESP32P4_ESP32P4_TAB5_SRC_ESP32P4_LCD_ILI9881C_H +#define __BOARDS_RISCV_ESP32P4_ESP32P4_TAB5_SRC_ESP32P4_LCD_ILI9881C_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: tab5_ili9881c_initialize + * + * Description: + * Register the ILI9881C as a mipi_dsi_device, attach to the Espressif + * host, report the panel identification and send the M5Stack Tab5 + * ILI9881C vendor DCS initialization table. Does not start video; board + * code starts it afterwards. + * + * Input Parameters: + * host - Registered MIPI-DSI host (esp_mipi_dsi_host_get()) + * + * Returned Value: + * Pointer to the registered device on success; NULL on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32P4_TAB5_LCD_ILI9881C +FAR struct mipi_dsi_device *tab5_ili9881c_initialize( + FAR struct mipi_dsi_host *host); +#endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_RISCV_ESP32P4_ESP32P4_TAB5_SRC_ESP32P4_LCD_ILI9881C_H */ diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c new file mode 100644 index 00000000000..f2a0f5df6b6 --- /dev/null +++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c @@ -0,0 +1,232 @@ +/**************************************************************************** + * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_gt911.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include "espressif/esp_gpio.h" +#include "espressif/esp_i2c.h" + +#include "esp32p4-tab5.h" + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int board_gt911_attach(FAR const struct gt9xx_board_s *state, + xcpt_t isr, FAR void *arg); +static void board_gt911_enable(FAR const struct gt9xx_board_s *state, + bool enable); +static int board_gt911_power(FAR const struct gt9xx_board_s *state, bool on); +static void board_gt911_report_id(FAR struct i2c_master_s *i2c); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct gt9xx_board_s g_gt911_config = +{ + .irq_attach = board_gt911_attach, + .irq_enable = board_gt911_enable, + .set_power = board_gt911_power, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_gt911_attach + * + * Description: + * Drive TAB5_GPIO_TP_INT low. These units have a pull-up to 3V3 on the + * touch interrupt line that stops the GT911 from scanning, so the pin is + * held low and no interrupt is used; contacts are picked up on read. + * + * Input Parameters: + * state - Pointer to the GT9XX board configuration structure. + * isr - The interrupt service routine (unused). + * arg - The argument for the interrupt service routine (unused). + * + * Returned Value: + * Zero on success. + * + ****************************************************************************/ + +static int board_gt911_attach(FAR const struct gt9xx_board_s *state, + xcpt_t isr, FAR void *arg) +{ + UNUSED(state); + UNUSED(isr); + UNUSED(arg); + + esp_configgpio(TAB5_GPIO_TP_INT, OUTPUT_FUNCTION_2); + esp_gpiowrite(TAB5_GPIO_TP_INT, false); + + return OK; +} + +/**************************************************************************** + * Name: board_gt911_enable + * + * Description: + * No interrupt is used on this board (see board_gt911_attach). + * + * Input Parameters: + * state - Pointer to the GT9XX board configuration structure. + * enable - True to enable the interrupt, false to disable it. + * + ****************************************************************************/ + +static void board_gt911_enable(FAR const struct gt9xx_board_s *state, + bool enable) +{ + UNUSED(state); + UNUSED(enable); +} + +/**************************************************************************** + * Name: board_gt911_power + * + * Description: + * Nothing to do: the rails and the reset line are driven earlier, by + * tab5_hmi_power_init(). + * + * Input Parameters: + * state - Pointer to the GT9XX board configuration structure. + * on - True to power on, false to power off. + * + * Returned Value: + * Zero on success. + * + ****************************************************************************/ + +static int board_gt911_power(FAR const struct gt9xx_board_s *state, bool on) +{ + UNUSED(state); + UNUSED(on); + + return OK; +} + +/**************************************************************************** + * Name: board_gt911_report_id + * + * Description: + * Read and log the controller identification: product ID (ASCII, "911" + * for the GT911), firmware version and maximum coordinates, from + * register 0x8140. A failed read is logged but is not fatal. + * + * Input Parameters: + * i2c - The I2C bus the controller is attached to. + * + ****************************************************************************/ + +static void board_gt911_report_id(FAR struct i2c_master_s *i2c) +{ + struct i2c_config_s config; + uint8_t reg[2]; + uint8_t buf[10]; + char product[5]; + int ret; + + config.frequency = CONFIG_INPUT_GT9XX_I2C_FREQUENCY; + config.address = CONFIG_ESP32P4_TAB5_TOUCH_GT911_ADDR; + config.addrlen = 7; + + /* 0x8140: product ID (4) + firmware version (2) + x max (2) + y max (2) */ + + reg[0] = 0x81; + reg[1] = 0x40; + + ret = i2c_writeread(i2c, &config, reg, sizeof(reg), buf, sizeof(buf)); + if (ret < 0) + { + syslog(LOG_WARNING, "gt911: ID read failed: %d\n", ret); + return; + } + + memcpy(product, buf, 4); + product[4] = '\0'; + + syslog(LOG_INFO, + "gt911: product \"%s\" (%02x %02x %02x %02x) fw %02x%02x " + "res %dx%d\n", + product, buf[0], buf[1], buf[2], buf[3], buf[5], buf[4], + buf[6] | (buf[7] << 8), buf[8] | (buf[9] << 8)); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: tab5_touchscreen_init + * + * Description: + * Initialize the touch screen controller. + * + * Returned Value: + * Zero on success, -1 on failure. + * + ****************************************************************************/ + +int tab5_touchscreen_init(void) +{ + FAR struct i2c_master_s *i2c; + int ret; + + i2c = esp_i2cbus_initialize(ESPRESSIF_I2C0); + if (i2c == NULL) + { + syslog(LOG_ERR, "ERROR: failed to get I2C0 bus\n"); + return -ENODEV; + } + + board_gt911_report_id(i2c); + + ret = gt9xx_register("/dev/input0", i2c, + CONFIG_ESP32P4_TAB5_TOUCH_GT911_ADDR, + &g_gt911_config); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: failed to register GT911: %d\n", ret); + return ret; + } + + syslog(LOG_INFO, "GT911 touchscreen controller initialized!\n"); + + return OK; +} diff --git a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch.c b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_st7123.c similarity index 98% rename from boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch.c rename to boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_st7123.c index 0de9e51e22f..c62022bd3fe 100644 --- a/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch.c +++ b/boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_st7123.c @@ -1,5 +1,5 @@ /**************************************************************************** - * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch.c + * boards/risc-v/esp32p4/esp32p4-tab5/src/esp32p4_touch_st7123.c * * SPDX-License-Identifier: Apache-2.0 * @@ -134,5 +134,6 @@ int tab5_touchscreen_init(void) } syslog(LOG_INFO, "ST7123 touchscreen controller initialized!\n"); + return OK; }