// SPDX-License-Identifier: GPL-2.0+
/*
* DRM driver for the HX8357D LCD controller
*
* Copyright 2018 Broadcom
* Copyright 2018 David Lechner <david@lechnology.com>
* Copyright 2016 Noralf Trønnes
* Copyright (C) 2015 Adafruit Industries
* Copyright (C) 2013 Christian Vogelgsang
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/spi/spi.h>
#include <drm/clients/drm_client_setup.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_fbdev_dma.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_mipi_dbi.h>
#include <drm/drm_modeset_helper.h>
#include <video/mipi_display.h>
#define HX8357D_SETOSC 0 xb0
#define HX8357D_SETPOWER 0 xb1
#define HX8357D_SETRGB 0 xb3
#define HX8357D_SETCYC 0 xb3
#define HX8357D_SETCOM 0 xb6
#define HX8357D_SETEXTC 0 xb9
#define HX8357D_SETSTBA 0 xc0
#define HX8357D_SETPANEL 0 xcc
#define HX8357D_SETGAMMA 0 xe0
#define HX8357D_MADCTL_MY 0 x80
#define HX8357D_MADCTL_MX 0 x40
#define HX8357D_MADCTL_MV 0 x20
#define HX8357D_MADCTL_ML 0 x10
#define HX8357D_MADCTL_RGB 0 x00
#define HX8357D_MADCTL_BGR 0 x08
#define HX8357D_MADCTL_MH 0 x04
static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(pipe->crtc.dev);
struct mipi_dbi *dbi = &dbidev->dbi;
u8 addr_mode;
int ret, idx;
if (!drm_dev_enter(pipe->crtc.dev, &idx))
return ;
DRM_DEBUG_KMS("\n" );
ret = mipi_dbi_poweron_conditional_reset(dbidev);
if (ret < 0 )
goto out_exit;
if (ret == 1 )
goto out_enable;
/* setextc */
mipi_dbi_command(dbi, HX8357D_SETEXTC, 0 xFF, 0 x83, 0 x57);
msleep(150 );
/* setRGB which also enables SDO */
mipi_dbi_command(dbi, HX8357D_SETRGB, 0 x00, 0 x00, 0 x06, 0 x06);
/* -1.52V */
mipi_dbi_command(dbi, HX8357D_SETCOM, 0 x25);
/* Normal mode 70Hz, Idle mode 55 Hz */
mipi_dbi_command(dbi, HX8357D_SETOSC, 0 x68);
/* Set Panel - BGR, Gate direction swapped */
mipi_dbi_command(dbi, HX8357D_SETPANEL, 0 x05);
mipi_dbi_command(dbi, HX8357D_SETPOWER,
0 x00, /* Not deep standby */
0 x15, /* BT */
0 x1C, /* VSPR */
0 x1C, /* VSNR */
0 x83, /* AP */
0 xAA); /* FS */
mipi_dbi_command(dbi, HX8357D_SETSTBA,
0 x50, /* OPON normal */
0 x50, /* OPON idle */
0 x01, /* STBA */
0 x3C, /* STBA */
0 x1E, /* STBA */
0 x08); /* GEN */
mipi_dbi_command(dbi, HX8357D_SETCYC,
0 x02, /* NW 0x02 */
0 x40, /* RTN */
0 x00, /* DIV */
0 x2A, /* DUM */
0 x2A, /* DUM */
0 x0D, /* GDON */
0 x78); /* GDOFF */
mipi_dbi_command(dbi, HX8357D_SETGAMMA,
0 x02,
0 x0A,
0 x11,
0 x1d,
0 x23,
0 x35,
0 x41,
0 x4b,
0 x4b,
0 x42,
0 x3A,
0 x27,
0 x1B,
0 x08,
0 x09,
0 x03,
0 x02,
0 x0A,
0 x11,
0 x1d,
0 x23,
0 x35,
0 x41,
0 x4b,
0 x4b,
0 x42,
0 x3A,
0 x27,
0 x1B,
0 x08,
0 x09,
0 x03,
0 x00,
0 x01);
/* 16 bit */
mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT,
MIPI_DCS_PIXEL_FMT_16BIT);
/* TE off */
mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_ON, 0 x00);
/* tear line */
mipi_dbi_command(dbi, MIPI_DCS_SET_TEAR_SCANLINE, 0 x00, 0 x02);
/* Exit Sleep */
mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
msleep(150 );
/* display on */
mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
usleep_range(5000 , 7000 );
out_enable:
switch (dbidev->rotation) {
default :
addr_mode = HX8357D_MADCTL_MX | HX8357D_MADCTL_MY;
break ;
case 90 :
addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MY;
break ;
case 180 :
addr_mode = 0 ;
break ;
case 270 :
addr_mode = HX8357D_MADCTL_MV | HX8357D_MADCTL_MX;
break ;
}
mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
mipi_dbi_enable_flush(dbidev, crtc_state, plane_state);
out_exit:
drm_dev_exit(idx);
}
static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
DRM_MIPI_DBI_SIMPLE_DISPLAY_PIPE_FUNCS(yx240qv29_enable),
};
static const struct drm_display_mode yx350hv15_mode = {
DRM_SIMPLE_MODE(320 , 480 , 60 , 75 ),
};
DEFINE_DRM_GEM_DMA_FOPS(hx8357d_fops);
static const struct drm_driver hx8357d_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
.fops = &hx8357d_fops,
DRM_GEM_DMA_DRIVER_OPS_VMAP,
DRM_FBDEV_DMA_DRIVER_OPS,
.debugfs_init = mipi_dbi_debugfs_init,
.name = "hx8357d" ,
.desc = "HX8357D" ,
.major = 1 ,
.minor = 0 ,
};
static const struct of_device_id hx8357d_of_match[] = {
{ .compatible = "adafruit,yx350hv15" },
{ }
};
MODULE_DEVICE_TABLE(of, hx8357d_of_match);
static const struct spi_device_id hx8357d_id[] = {
{ "yx350hv15" , 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, hx8357d_id);
static int hx8357d_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct mipi_dbi_dev *dbidev;
struct drm_device *drm;
struct gpio_desc *dc;
u32 rotation = 0 ;
int ret;
dbidev = devm_drm_dev_alloc(dev, &hx8357d_driver,
struct mipi_dbi_dev, drm);
if (IS_ERR(dbidev))
return PTR_ERR(dbidev);
drm = &dbidev->drm;
dc = devm_gpiod_get(dev, "dc" , GPIOD_OUT_LOW);
if (IS_ERR(dc))
return dev_err_probe(dev, PTR_ERR(dc), "Failed to get GPIO 'dc'\n" );
dbidev->backlight = devm_of_find_backlight(dev);
if (IS_ERR(dbidev->backlight))
return PTR_ERR(dbidev->backlight);
device_property_read_u32(dev, "rotation" , &rotation);
ret = mipi_dbi_spi_init(spi, &dbidev->dbi, dc);
if (ret)
return ret;
ret = mipi_dbi_dev_init(dbidev, &hx8357d_pipe_funcs, &yx350hv15_mode, rotation);
if (ret)
return ret;
drm_mode_config_reset(drm);
ret = drm_dev_register(drm, 0 );
if (ret)
return ret;
spi_set_drvdata(spi, drm);
drm_client_setup(drm, NULL);
return 0 ;
}
static void hx8357d_remove(struct spi_device *spi)
{
struct drm_device *drm = spi_get_drvdata(spi);
drm_dev_unplug(drm);
drm_atomic_helper_shutdown(drm);
}
static void hx8357d_shutdown(struct spi_device *spi)
{
drm_atomic_helper_shutdown(spi_get_drvdata(spi));
}
static struct spi_driver hx8357d_spi_driver = {
.driver = {
.name = "hx8357d" ,
.of_match_table = hx8357d_of_match,
},
.id_table = hx8357d_id,
.probe = hx8357d_probe,
.remove = hx8357d_remove,
.shutdown = hx8357d_shutdown,
};
module_spi_driver(hx8357d_spi_driver);
MODULE_DESCRIPTION("HX8357D DRM driver" );
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>" );
MODULE_LICENSE("GPL" );
Messung V0.5 in Prozent C=96 H=93 G=94
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland