]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
video: panel: add Sony L4F00430T01 panel driver
authorIon Agorria <ion@agorria.com>
Fri, 18 Apr 2025 23:48:59 +0000 (01:48 +0200)
committerSvyatoslav Ryhel <clamor95@gmail.com>
Fri, 1 Aug 2025 05:44:44 +0000 (08:44 +0300)
Sony L4F00430T01 LCD module is found in Samsung Galaxy R. The panel has a
WVGA resolution (480x800) and is setup over SPI, video data comes from RGB.

Signed-off-by: Ion Agorria <ion@agorria.com>
Reviewed-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/sony-l4f00430t01.c [new file with mode: 0644]

index dfe4b3b8a026419abe0a8bcbd5b9f9e4d3e0f17f..1e405e743ae3b120b60fd6338857ab5d4fab3f74 100644 (file)
@@ -691,6 +691,15 @@ config VIDEO_LCD_HITACHI_TX18D42VM
        lcd controller which needs to be initialized over SPI, once that is
        done they work like a regular LVDS panel.
 
+config VIDEO_LCD_SONY_L4F00430T01
+       tristate "Sony L4F00430T01 480x800 LCD panel support"
+       depends on PANEL
+       help
+         Say Y here if you want to enable support for Sony L4F00430T01
+         LCD module found in Samsung Galaxy R. The panel has a
+         WVGA resolution (480x800) and is setup over SPI, video
+         data comes from RGB.
+
 config VIDEO_LCD_SPI_CS
        string "SPI CS pin for LCD related config job"
        depends on VIDEO_LCD_SSD2828 || VIDEO_LCD_HITACHI_TX18D42VM
index ebe4a3961fc90cfe5f2fb03394825fd13736276d..2151353551d8f4bc7db1d055d45502755cd9cacb 100644 (file)
@@ -74,6 +74,7 @@ obj-$(CONFIG_VIDEO_LCD_SHARP_LQ079L1SX01) += sharp-lq079l1sx01.o
 obj-$(CONFIG_VIDEO_LCD_SHARP_LQ101R1SX01) += sharp-lq101r1sx01.o
 obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
 obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o
+obj-$(CONFIG_VIDEO_LCD_SONY_L4F00430T01) += sony-l4f00430t01.o
 obj-$(CONFIG_VIDEO_MCDE_SIMPLE) += mcde_simple.o
 obj-${CONFIG_VIDEO_MESON} += meson/
 obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o
diff --git a/drivers/video/sony-l4f00430t01.c b/drivers/video/sony-l4f00430t01.c
new file mode 100644 (file)
index 0000000..2303eb8
--- /dev/null
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2025 Ion Agorria <ion@agorria.com>
+ */
+
+#include <backlight.h>
+#include <dm.h>
+#include <panel.h>
+#include <log.h>
+#include <spi.h>
+#include <mipi_display.h>
+#include <linux/delay.h>
+#include <power/regulator.h>
+#include <asm/gpio.h>
+
+#define SONY_L4F00430T01_DCS_CMD       0
+#define SONY_L4F00430T01_DCS_DATA      1
+
+struct sony_l4f00430t01_priv {
+       struct udevice *vdd1v8;
+       struct udevice *vdd3v0;
+
+       struct udevice *backlight;
+
+       struct gpio_desc reset_gpio;
+};
+
+static struct display_timing default_timing = {
+       .pixelclock.typ         = 24000000,
+       .hactive.typ            = 480,
+       .hfront_porch.typ       = 10,
+       .hback_porch.typ        = 20,
+       .hsync_len.typ          = 10,
+       .vactive.typ            = 800,
+       .vfront_porch.typ       = 3,
+       .vback_porch.typ        = 4,
+       .vsync_len.typ          = 2,
+       .flags                  = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
+                                 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_NEGEDGE,
+};
+
+static int sony_l4f00430t01_write(struct udevice *dev, u8 cmd, const u8 *seq, int len)
+{
+       u8 data[2];
+       int i, ret;
+
+       data[0] = SONY_L4F00430T01_DCS_CMD;
+       data[1] = cmd;
+
+       ret = dm_spi_xfer(dev, 9, &data, NULL, SPI_XFER_ONCE);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < len; i++) {
+               data[0] = SONY_L4F00430T01_DCS_DATA;
+               data[1] = seq[i];
+
+               ret = dm_spi_xfer(dev, 9, &data, NULL, SPI_XFER_ONCE);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+#define sony_l4f00430t01_write_seq(dev, cmd, seq...) do {              \
+               static const u8 b[] = { seq };                          \
+               sony_l4f00430t01_write(dev, cmd, b, ARRAY_SIZE(b));     \
+       } while (0)
+
+static int sony_l4f00430t01_enable_backlight(struct udevice *dev)
+{
+       sony_l4f00430t01_write_seq(dev, MIPI_DCS_SET_ADDRESS_MODE, 0xd4);
+       mdelay(25);
+
+       sony_l4f00430t01_write_seq(dev, MIPI_DCS_EXIT_SLEEP_MODE);
+       mdelay(150);
+
+       sony_l4f00430t01_write_seq(dev, MIPI_DCS_SET_DISPLAY_ON);
+
+       return 0;
+}
+
+static int sony_l4f00430t01_set_backlight(struct udevice *dev, int percent)
+{
+       struct sony_l4f00430t01_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
+                                          "backlight", &priv->backlight);
+       if (ret) {
+               log_debug("%s: cannot get backlight: ret = %d\n",
+                         __func__, ret);
+               return ret;
+       }
+
+       ret = backlight_enable(priv->backlight);
+       if (ret)
+               return ret;
+
+       return backlight_set_brightness(priv->backlight, percent);
+}
+
+static int sony_l4f00430t01_get_display_timing(struct udevice *dev,
+                                              struct display_timing *timing)
+{
+       memcpy(timing, &default_timing, sizeof(*timing));
+       return 0;
+}
+
+static int sony_l4f00430t01_of_to_plat(struct udevice *dev)
+{
+       struct sony_l4f00430t01_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = device_get_supply_regulator(dev, "vdd1v8-supply", &priv->vdd1v8);
+       if (ret) {
+               log_debug("%s: cannot get vdd1v8-supply: ret = %d\n",
+                         __func__, ret);
+               return ret;
+       }
+
+       ret = device_get_supply_regulator(dev, "vdd3v0-supply", &priv->vdd3v0);
+       if (ret) {
+               log_debug("%s: cannot get vdd3v0-supply: ret = %d\n",
+                         __func__, ret);
+               return ret;
+       }
+
+       ret = gpio_request_by_name(dev, "reset-gpios", 0,
+                                  &priv->reset_gpio, GPIOD_IS_OUT);
+       if (ret) {
+               log_debug("%s: cannot decode reset-gpios (%d)\n",
+                         __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sony_l4f00430t01_hw_init(struct udevice *dev)
+{
+       struct sony_l4f00430t01_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+       if (ret) {
+               log_debug("%s: error entering reset (%d)\n", __func__, ret);
+               return ret;
+       }
+
+       ret = regulator_set_enable_if_allowed(priv->vdd1v8, 1);
+       if (ret) {
+               log_debug("%s: enabling vdd1v8-supply failed (%d)\n",
+                         __func__, ret);
+               return ret;
+       }
+
+       ret = regulator_set_enable_if_allowed(priv->vdd3v0, 1);
+       if (ret) {
+               log_debug("%s: enabling vdd3v0-supply failed (%d)\n",
+                         __func__, ret);
+               return ret;
+       }
+       mdelay(15);
+
+       ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+       if (ret) {
+               log_debug("%s: error exiting reset (%d)\n", __func__, ret);
+               return ret;
+       }
+       mdelay(100);
+
+       return 0;
+}
+
+static int sony_l4f00430t01_probe(struct udevice *dev)
+{
+       struct spi_slave *slave = dev_get_parent_priv(dev);
+       int ret;
+
+       ret = spi_claim_bus(slave);
+       if (ret) {
+               log_err("SPI bus allocation failed (%d)\n", ret);
+               return ret;
+       }
+
+       return sony_l4f00430t01_hw_init(dev);
+}
+
+static const struct panel_ops sony_l4f00430t01_ops = {
+       .enable_backlight       = sony_l4f00430t01_enable_backlight,
+       .set_backlight          = sony_l4f00430t01_set_backlight,
+       .get_display_timing     = sony_l4f00430t01_get_display_timing,
+};
+
+static const struct udevice_id sony_l4f00430t01_ids[] = {
+       { .compatible = "sony,l4f00430t01" },
+       { }
+};
+
+U_BOOT_DRIVER(sony_l4f00430t01) = {
+       .name           = "sony_l4f00430t01",
+       .id             = UCLASS_PANEL,
+       .of_match       = sony_l4f00430t01_ids,
+       .ops            = &sony_l4f00430t01_ops,
+       .of_to_plat     = sony_l4f00430t01_of_to_plat,
+       .probe          = sony_l4f00430t01_probe,
+       .priv_auto      = sizeof(struct sony_l4f00430t01_priv),
+};