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; }