[2/3] drm: Add an hx8367d tinydrm driver.
diff mbox series

Message ID 20181024184313.2967-3-eric@anholt.net
State New
Headers show
Series
  • drm: tinydrm driver for adafruit PiTFT 3.5" touchscreen
Related show

Commit Message

Eric Anholt Oct. 24, 2018, 6:43 p.m. UTC
I want to sort out support for tinydrm in vc4, so I needed to get a
tinydrm-appropriate panel working and this is what I had on hand.
This is derived from a combination of ili9341.c from tinydrm and
fb_hx8357d.c from staging's fbtft.  The register header is copied
directly from staging's fbtft, on the assumption that we will delete
that copy later.

Signed-off-by: Eric Anholt <eric@anholt.net>
---
 MAINTAINERS                       |   7 +
 drivers/gpu/drm/tinydrm/Kconfig   |  11 ++
 drivers/gpu/drm/tinydrm/Makefile  |   1 +
 drivers/gpu/drm/tinydrm/hx8357d.c | 261 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/tinydrm/hx8357d.h |  71 ++++++++
 5 files changed, 351 insertions(+)
 create mode 100644 drivers/gpu/drm/tinydrm/hx8357d.c
 create mode 100644 drivers/gpu/drm/tinydrm/hx8357d.h

Comments

Noralf Trønnes Oct. 27, 2018, 4:12 p.m. UTC | #1
Den 24.10.2018 20.43, skrev Eric Anholt:
> I want to sort out support for tinydrm in vc4, so I needed to get a
> tinydrm-appropriate panel working and this is what I had on hand.
> This is derived from a combination of ili9341.c from tinydrm and
> fb_hx8357d.c from staging's fbtft.  The register header is copied
> directly from staging's fbtft, on the assumption that we will delete
> that copy later.
>
> Signed-off-by: Eric Anholt <eric@anholt.net>
> ---
>   MAINTAINERS                       |   7 +
>   drivers/gpu/drm/tinydrm/Kconfig   |  11 ++
>   drivers/gpu/drm/tinydrm/Makefile  |   1 +
>   drivers/gpu/drm/tinydrm/hx8357d.c | 261 ++++++++++++++++++++++++++++++
>   drivers/gpu/drm/tinydrm/hx8357d.h |  71 ++++++++
>   5 files changed, 351 insertions(+)
>   create mode 100644 drivers/gpu/drm/tinydrm/hx8357d.c
>   create mode 100644 drivers/gpu/drm/tinydrm/hx8357d.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 39c3f6682ace..e78971e20a11 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4623,6 +4623,13 @@ S:	Maintained
>   F:	drivers/gpu/drm/tinydrm/ili9225.c
>   F:	Documentation/devicetree/bindings/display/ilitek,ili9225.txt
>   
> +DRM DRIVER FOR HX8357D PANELS
> +M:	Eric Anholt <eric@anholt.net>
> +T:	git git://anongit.freedesktop.org/drm/drm-misc
> +S:	Maintained
> +F:	drivers/gpu/drm/tinydrm/hx8357d.c
> +F:	Documentation/devicetree/bindings/display/himax,hx8357d.txt
> +
>   DRM DRIVER FOR INTEL I810 VIDEO CARDS
>   S:	Orphan / Obsolete
>   F:	drivers/gpu/drm/i810/
> diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
> index 16f4b5c91f1b..2c408ac1a900 100644
> --- a/drivers/gpu/drm/tinydrm/Kconfig
> +++ b/drivers/gpu/drm/tinydrm/Kconfig
> @@ -10,6 +10,17 @@ menuconfig DRM_TINYDRM
>   config TINYDRM_MIPI_DBI
>   	tristate
>   
> +config TINYDRM_HX8357D
> +	tristate "DRM support for HX8357D display panels"
> +	depends on DRM_TINYDRM && SPI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	select TINYDRM_MIPI_DBI
> +	help
> +	  DRM driver for the following HX8357D panels:
> +	  * YX350HV15-T 3.5" 340x350 TFT (Adafruit 3.5")
> +
> +	  If M is selected the module will be called hx8357d.
> +
>   config TINYDRM_ILI9225
>   	tristate "DRM support for ILI9225 display panels"
>   	depends on DRM_TINYDRM && SPI
> diff --git a/drivers/gpu/drm/tinydrm/Makefile b/drivers/gpu/drm/tinydrm/Makefile
> index 14d99080665a..f823066f7743 100644
> --- a/drivers/gpu/drm/tinydrm/Makefile
> +++ b/drivers/gpu/drm/tinydrm/Makefile
> @@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_TINYDRM)		+= core/
>   obj-$(CONFIG_TINYDRM_MIPI_DBI)		+= mipi-dbi.o
>   
>   # Displays
> +obj-$(CONFIG_TINYDRM_HX8357D)		+= hx8357d.o
>   obj-$(CONFIG_TINYDRM_ILI9225)		+= ili9225.o
>   obj-$(CONFIG_TINYDRM_ILI9341)		+= ili9341.o
>   obj-$(CONFIG_TINYDRM_MI0283QT)		+= mi0283qt.o
> diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c
> new file mode 100644
> index 000000000000..51d4da624d57
> --- /dev/null
> +++ b/drivers/gpu/drm/tinydrm/hx8357d.c
> @@ -0,0 +1,261 @@
> +// 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/drm_fb_helper.h>
> +#include <drm/drm_gem_framebuffer_helper.h>
> +#include <drm/drm_modeset_helper.h>
> +#include <drm/tinydrm/mipi-dbi.h>
> +#include <drm/tinydrm/tinydrm-helpers.h>
> +#include <video/mipi_display.h>
> +#include "hx8357d.h"

I prefer to have the defines in the driver instead of an extra header file.
The reason is that usually only a handful of defines are actually used,
in this case it's 9.

> +
> +#define HX8357D_MADCTL_MY  0x80
> +#define HX8357D_MADCTL_MX  0x40
> +#define HX8357D_MADCTL_MV  0x20
> +#define HX8357D_MADCTL_ML  0x10
> +#define HX8357D_MADCTL_RGB 0x00
> +#define HX8357D_MADCTL_BGR 0x08
> +#define HX8357D_MADCTL_MH  0x04
> +
> +static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
> +			     struct drm_crtc_state *crtc_state,
> +			     struct drm_plane_state *plane_state)
> +{
> +	struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
> +	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
> +	u8 addr_mode;
> +	int ret;
> +
> +	DRM_DEBUG_KMS("\n");
> +
> +	ret = mipi_dbi_poweron_conditional_reset(mipi);
> +	if (ret < 0)
> +		return;
> +	if (ret == 1)
> +		goto out_enable;
> +
> +	/* setextc */
> +	mipi_dbi_command(mipi, HX8357D_SETC, 0xFF, 0x83, 0x57);
> +	msleep(150);
> +
> +	/* setRGB which also enables SDO */
> +	mipi_dbi_command(mipi, HX8357_SETRGB, 0x00, 0x00, 0x06, 0x06);
> +
> +	/* -1.52V */
> +	mipi_dbi_command(mipi, HX8357D_SETCOM, 0x25);
> +
> +	/* Normal mode 70Hz, Idle mode 55 Hz */
> +	mipi_dbi_command(mipi, HX8357_SETOSC, 0x68);
> +
> +	/* Set Panel - BGR, Gate direction swapped */
> +	mipi_dbi_command(mipi, HX8357_SETPANEL, 0x05);
> +
> +	mipi_dbi_command(mipi, HX8357_SETPWR1,
> +			 0x00,  /* Not deep standby */
> +			 0x15,  /* BT */
> +			 0x1C,  /* VSPR */
> +			 0x1C,  /* VSNR */
> +			 0x83,  /* AP */
> +			 0xAA);  /* FS */
> +
> +	mipi_dbi_command(mipi, HX8357D_SETSTBA,
> +			 0x50,  /* OPON normal */
> +			 0x50,  /* OPON idle */
> +			 0x01,  /* STBA */
> +			 0x3C,  /* STBA */
> +			 0x1E,  /* STBA */
> +			 0x08);  /* GEN */
> +
> +	mipi_dbi_command(mipi, HX8357D_SETCYC,
> +			 0x02,  /* NW 0x02 */
> +			 0x40,  /* RTN */
> +			 0x00,  /* DIV */
> +			 0x2A,  /* DUM */
> +			 0x2A,  /* DUM */
> +			 0x0D,  /* GDON */
> +			 0x78);  /* GDOFF */
> +
> +	mipi_dbi_command(mipi, HX8357D_SETGAMMA,
> +			 0x02,
> +			 0x0A,
> +			 0x11,
> +			 0x1d,
> +			 0x23,
> +			 0x35,
> +			 0x41,
> +			 0x4b,
> +			 0x4b,
> +			 0x42,
> +			 0x3A,
> +			 0x27,
> +			 0x1B,
> +			 0x08,
> +			 0x09,
> +			 0x03,
> +			 0x02,
> +			 0x0A,
> +			 0x11,
> +			 0x1d,
> +			 0x23,
> +			 0x35,
> +			 0x41,
> +			 0x4b,
> +			 0x4b,
> +			 0x42,
> +			 0x3A,
> +			 0x27,
> +			 0x1B,
> +			 0x08,
> +			 0x09,
> +			 0x03,
> +			 0x00,
> +			 0x01);
> +
> +	/* 16 bit */
> +	mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT,
> +			 MIPI_DCS_PIXEL_FMT_16BIT);
> +
> +	/* TE off */
> +	mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_ON, 0x00);
> +
> +	/* tear line */
> +	mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
> +
> +	/* Exit Sleep */
> +	mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE);
> +	msleep(150);
> +
> +	/* display on */
> +	mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
> +	usleep_range(5000, 7000);
> +
> +out_enable:
> +	switch (mipi->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(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
> +	mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
> +}
> +
> +static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
> +	.enable = yx240qv29_enable,
> +	.disable = mipi_dbi_pipe_disable,
> +	.update = tinydrm_display_pipe_update,
> +	.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
> +};
> +
> +static const struct drm_display_mode yx350hv15_mode = {
> +	TINYDRM_MODE(320, 480, 60, 75),
> +};
> +
> +DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
> +
> +static struct drm_driver hx8357d_driver = {
> +	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
> +	.fops			= &hx8357d_fops,
> +	TINYDRM_GEM_DRIVER_OPS,
> +	.debugfs_init		= mipi_dbi_debugfs_init,
> +	.name			= "hx8357d",
> +	.desc			= "HX8357D",
> +	.date			= "20181023",
> +	.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[] = {
> +	{ "hx8357d", 0 },

Last time I tried, module autoloading didn't work unless this contains
the last part of the compatible. In this case: "yx350hv15".
Have you checked that autoloading does work?

Otherwise this looks good:
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>

> +	{ }
> +};
> +MODULE_DEVICE_TABLE(spi, hx8357d_id);
> +
> +static int hx8357d_probe(struct spi_device *spi)
> +{
> +	struct device *dev = &spi->dev;
> +	struct mipi_dbi *mipi;
> +	struct gpio_desc *dc;
> +	u32 rotation = 0;
> +	int ret;
> +
> +	mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
> +	if (!mipi)
> +		return -ENOMEM;
> +
> +	dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
> +	if (IS_ERR(dc)) {
> +		DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
> +		return PTR_ERR(dc);
> +	}
> +
> +	mipi->backlight = devm_of_find_backlight(dev);
> +	if (IS_ERR(mipi->backlight))
> +		return PTR_ERR(mipi->backlight);
> +
> +	device_property_read_u32(dev, "rotation", &rotation);
> +
> +	ret = mipi_dbi_spi_init(spi, mipi, dc);
> +	if (ret)
> +		return ret;
> +
> +	ret = mipi_dbi_init(&spi->dev, mipi, &hx8357d_pipe_funcs,
> +			    &hx8357d_driver, &yx350hv15_mode, rotation);
> +	if (ret)
> +		return ret;
> +
> +	spi_set_drvdata(spi, mipi);
> +
> +	return devm_tinydrm_register(&mipi->tinydrm);
> +}
> +
> +static void hx8357d_shutdown(struct spi_device *spi)
> +{
> +	struct mipi_dbi *mipi = spi_get_drvdata(spi);
> +
> +	tinydrm_shutdown(&mipi->tinydrm);
> +}
> +
> +static struct spi_driver hx8357d_spi_driver = {
> +	.driver = {
> +		.name = "hx8357d",
> +		.of_match_table = hx8357d_of_match,
> +	},
> +	.id_table = hx8357d_id,
> +	.probe = hx8357d_probe,
> +	.shutdown = hx8357d_shutdown,
> +};
> +module_spi_driver(hx8357d_spi_driver);
> +
> +MODULE_DESCRIPTION("HX8357D DRM driver");
> +MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/tinydrm/hx8357d.h b/drivers/gpu/drm/tinydrm/hx8357d.h
> new file mode 100644
> index 000000000000..6180b093f94f
> --- /dev/null
> +++ b/drivers/gpu/drm/tinydrm/hx8357d.h
> @@ -0,0 +1,71 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * This is our library for the Adafruit  ILI9341 Breakout and Shield
> + * ----> http://www.adafruit.com/products/1651
> + *
> + * Check out the links above for our tutorials and wiring diagrams
> + * These displays use SPI to communicate, 4 or 5 pins are required to
> + * interface (RST is optional)
> + * Adafruit invests time and resources providing this open source code,
> + * please support Adafruit and open-source hardware by purchasing
> + * products from Adafruit!
> + *
> + * Written by Limor Fried/Ladyada for Adafruit Industries.
> + * MIT license, all text above must be included in any redistribution
> + */
> +
> +#ifndef __HX8357_H__
> +#define __HX8357_H__
> +
> +#define HX8357D 0xD
> +#define HX8357B 0xB
> +
> +#define HX8357_TFTWIDTH  320
> +#define HX8357_TFTHEIGHT 480
> +
> +#define HX8357_SETOSC 0xB0
> +#define HX8357_SETPWR1 0xB1
> +#define HX8357B_SETDISPLAY 0xB2
> +#define HX8357_SETRGB 0xB3
> +#define HX8357D_SETCOM  0xB6
> +
> +#define HX8357B_SETDISPMODE  0xB4
> +#define HX8357D_SETCYC  0xB4
> +#define HX8357B_SETOTP 0xB7
> +#define HX8357D_SETC 0xB9
> +
> +#define HX8357B_SET_PANEL_DRIVING 0xC0
> +#define HX8357D_SETSTBA 0xC0
> +#define HX8357B_SETDGC  0xC1
> +#define HX8357B_SETID  0xC3
> +#define HX8357B_SETDDB  0xC4
> +#define HX8357B_SETDISPLAYFRAME 0xC5
> +#define HX8357B_GAMMASET 0xC8
> +#define HX8357B_SETCABC  0xC9
> +#define HX8357_SETPANEL  0xCC
> +
> +#define HX8357B_SETPOWER 0xD0
> +#define HX8357B_SETVCOM 0xD1
> +#define HX8357B_SETPWRNORMAL 0xD2
> +
> +#define HX8357B_RDID1   0xDA
> +#define HX8357B_RDID2   0xDB
> +#define HX8357B_RDID3   0xDC
> +#define HX8357B_RDID4   0xDD
> +
> +#define HX8357D_SETGAMMA 0xE0
> +
> +#define HX8357B_SETGAMMA 0xC8
> +#define HX8357B_SETPANELRELATED  0xE9
> +
> +/* Color definitions */
> +#define	HX8357_BLACK   0x0000
> +#define	HX8357_BLUE    0x001F
> +#define	HX8357_RED     0xF800
> +#define	HX8357_GREEN   0x07E0
> +#define HX8357_CYAN    0x07FF
> +#define HX8357_MAGENTA 0xF81F
> +#define HX8357_YELLOW  0xFFE0
> +#define HX8357_WHITE   0xFFFF
> +
> +#endif /* __HX8357_H__ */
Eric Anholt Oct. 30, 2018, 10:46 p.m. UTC | #2
Noralf Trønnes <noralf@tronnes.org> writes:

> Den 24.10.2018 20.43, skrev Eric Anholt:
>> I want to sort out support for tinydrm in vc4, so I needed to get a
>> tinydrm-appropriate panel working and this is what I had on hand.
>> This is derived from a combination of ili9341.c from tinydrm and
>> fb_hx8357d.c from staging's fbtft.  The register header is copied
>> directly from staging's fbtft, on the assumption that we will delete
>> that copy later.
>>
>> Signed-off-by: Eric Anholt <eric@anholt.net>
>> ---
>>   MAINTAINERS                       |   7 +
>>   drivers/gpu/drm/tinydrm/Kconfig   |  11 ++
>>   drivers/gpu/drm/tinydrm/Makefile  |   1 +
>>   drivers/gpu/drm/tinydrm/hx8357d.c | 261 ++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/tinydrm/hx8357d.h |  71 ++++++++
>>   5 files changed, 351 insertions(+)
>>   create mode 100644 drivers/gpu/drm/tinydrm/hx8357d.c
>>   create mode 100644 drivers/gpu/drm/tinydrm/hx8357d.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 39c3f6682ace..e78971e20a11 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -4623,6 +4623,13 @@ S:	Maintained
>>   F:	drivers/gpu/drm/tinydrm/ili9225.c
>>   F:	Documentation/devicetree/bindings/display/ilitek,ili9225.txt
>>   
>> +DRM DRIVER FOR HX8357D PANELS
>> +M:	Eric Anholt <eric@anholt.net>
>> +T:	git git://anongit.freedesktop.org/drm/drm-misc
>> +S:	Maintained
>> +F:	drivers/gpu/drm/tinydrm/hx8357d.c
>> +F:	Documentation/devicetree/bindings/display/himax,hx8357d.txt
>> +
>>   DRM DRIVER FOR INTEL I810 VIDEO CARDS
>>   S:	Orphan / Obsolete
>>   F:	drivers/gpu/drm/i810/
>> diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
>> index 16f4b5c91f1b..2c408ac1a900 100644
>> --- a/drivers/gpu/drm/tinydrm/Kconfig
>> +++ b/drivers/gpu/drm/tinydrm/Kconfig
>> @@ -10,6 +10,17 @@ menuconfig DRM_TINYDRM
>>   config TINYDRM_MIPI_DBI
>>   	tristate
>>   
>> +config TINYDRM_HX8357D
>> +	tristate "DRM support for HX8357D display panels"
>> +	depends on DRM_TINYDRM && SPI
>> +	depends on BACKLIGHT_CLASS_DEVICE
>> +	select TINYDRM_MIPI_DBI
>> +	help
>> +	  DRM driver for the following HX8357D panels:
>> +	  * YX350HV15-T 3.5" 340x350 TFT (Adafruit 3.5")
>> +
>> +	  If M is selected the module will be called hx8357d.
>> +
>>   config TINYDRM_ILI9225
>>   	tristate "DRM support for ILI9225 display panels"
>>   	depends on DRM_TINYDRM && SPI
>> diff --git a/drivers/gpu/drm/tinydrm/Makefile b/drivers/gpu/drm/tinydrm/Makefile
>> index 14d99080665a..f823066f7743 100644
>> --- a/drivers/gpu/drm/tinydrm/Makefile
>> +++ b/drivers/gpu/drm/tinydrm/Makefile
>> @@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_TINYDRM)		+= core/
>>   obj-$(CONFIG_TINYDRM_MIPI_DBI)		+= mipi-dbi.o
>>   
>>   # Displays
>> +obj-$(CONFIG_TINYDRM_HX8357D)		+= hx8357d.o
>>   obj-$(CONFIG_TINYDRM_ILI9225)		+= ili9225.o
>>   obj-$(CONFIG_TINYDRM_ILI9341)		+= ili9341.o
>>   obj-$(CONFIG_TINYDRM_MI0283QT)		+= mi0283qt.o
>> diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c
>> new file mode 100644
>> index 000000000000..51d4da624d57
>> --- /dev/null
>> +++ b/drivers/gpu/drm/tinydrm/hx8357d.c
>> @@ -0,0 +1,261 @@
>> +// 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/drm_fb_helper.h>
>> +#include <drm/drm_gem_framebuffer_helper.h>
>> +#include <drm/drm_modeset_helper.h>
>> +#include <drm/tinydrm/mipi-dbi.h>
>> +#include <drm/tinydrm/tinydrm-helpers.h>
>> +#include <video/mipi_display.h>
>> +#include "hx8357d.h"
>
> I prefer to have the defines in the driver instead of an extra header file.
> The reason is that usually only a handful of defines are actually used,
> in this case it's 9.

Yeah.  Also, that license on the header is pretty sketchy.  I've written
my own defines based on reading the HX8357D spec and included it in the
driver instead.

>> +
>> +static const struct spi_device_id hx8357d_id[] = {
>> +	{ "hx8357d", 0 },
>
> Last time I tried, module autoloading didn't work unless this contains
> the last part of the compatible. In this case: "yx350hv15".
> Have you checked that autoloading does work?

I hadn't since I changed the compatible string to adafruit.  Thanks!

> Otherwise this looks good:
> Reviewed-by: Noralf Trønnes <noralf@tronnes.org>

Patch
diff mbox series

diff --git a/MAINTAINERS b/MAINTAINERS
index 39c3f6682ace..e78971e20a11 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4623,6 +4623,13 @@  S:	Maintained
 F:	drivers/gpu/drm/tinydrm/ili9225.c
 F:	Documentation/devicetree/bindings/display/ilitek,ili9225.txt
 
+DRM DRIVER FOR HX8357D PANELS
+M:	Eric Anholt <eric@anholt.net>
+T:	git git://anongit.freedesktop.org/drm/drm-misc
+S:	Maintained
+F:	drivers/gpu/drm/tinydrm/hx8357d.c
+F:	Documentation/devicetree/bindings/display/himax,hx8357d.txt
+
 DRM DRIVER FOR INTEL I810 VIDEO CARDS
 S:	Orphan / Obsolete
 F:	drivers/gpu/drm/i810/
diff --git a/drivers/gpu/drm/tinydrm/Kconfig b/drivers/gpu/drm/tinydrm/Kconfig
index 16f4b5c91f1b..2c408ac1a900 100644
--- a/drivers/gpu/drm/tinydrm/Kconfig
+++ b/drivers/gpu/drm/tinydrm/Kconfig
@@ -10,6 +10,17 @@  menuconfig DRM_TINYDRM
 config TINYDRM_MIPI_DBI
 	tristate
 
+config TINYDRM_HX8357D
+	tristate "DRM support for HX8357D display panels"
+	depends on DRM_TINYDRM && SPI
+	depends on BACKLIGHT_CLASS_DEVICE
+	select TINYDRM_MIPI_DBI
+	help
+	  DRM driver for the following HX8357D panels:
+	  * YX350HV15-T 3.5" 340x350 TFT (Adafruit 3.5")
+
+	  If M is selected the module will be called hx8357d.
+
 config TINYDRM_ILI9225
 	tristate "DRM support for ILI9225 display panels"
 	depends on DRM_TINYDRM && SPI
diff --git a/drivers/gpu/drm/tinydrm/Makefile b/drivers/gpu/drm/tinydrm/Makefile
index 14d99080665a..f823066f7743 100644
--- a/drivers/gpu/drm/tinydrm/Makefile
+++ b/drivers/gpu/drm/tinydrm/Makefile
@@ -4,6 +4,7 @@  obj-$(CONFIG_DRM_TINYDRM)		+= core/
 obj-$(CONFIG_TINYDRM_MIPI_DBI)		+= mipi-dbi.o
 
 # Displays
+obj-$(CONFIG_TINYDRM_HX8357D)		+= hx8357d.o
 obj-$(CONFIG_TINYDRM_ILI9225)		+= ili9225.o
 obj-$(CONFIG_TINYDRM_ILI9341)		+= ili9341.o
 obj-$(CONFIG_TINYDRM_MI0283QT)		+= mi0283qt.o
diff --git a/drivers/gpu/drm/tinydrm/hx8357d.c b/drivers/gpu/drm/tinydrm/hx8357d.c
new file mode 100644
index 000000000000..51d4da624d57
--- /dev/null
+++ b/drivers/gpu/drm/tinydrm/hx8357d.c
@@ -0,0 +1,261 @@ 
+// 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/drm_fb_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_modeset_helper.h>
+#include <drm/tinydrm/mipi-dbi.h>
+#include <drm/tinydrm/tinydrm-helpers.h>
+#include <video/mipi_display.h>
+#include "hx8357d.h"
+
+#define HX8357D_MADCTL_MY  0x80
+#define HX8357D_MADCTL_MX  0x40
+#define HX8357D_MADCTL_MV  0x20
+#define HX8357D_MADCTL_ML  0x10
+#define HX8357D_MADCTL_RGB 0x00
+#define HX8357D_MADCTL_BGR 0x08
+#define HX8357D_MADCTL_MH  0x04
+
+static void yx240qv29_enable(struct drm_simple_display_pipe *pipe,
+			     struct drm_crtc_state *crtc_state,
+			     struct drm_plane_state *plane_state)
+{
+	struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+	struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+	u8 addr_mode;
+	int ret;
+
+	DRM_DEBUG_KMS("\n");
+
+	ret = mipi_dbi_poweron_conditional_reset(mipi);
+	if (ret < 0)
+		return;
+	if (ret == 1)
+		goto out_enable;
+
+	/* setextc */
+	mipi_dbi_command(mipi, HX8357D_SETC, 0xFF, 0x83, 0x57);
+	msleep(150);
+
+	/* setRGB which also enables SDO */
+	mipi_dbi_command(mipi, HX8357_SETRGB, 0x00, 0x00, 0x06, 0x06);
+
+	/* -1.52V */
+	mipi_dbi_command(mipi, HX8357D_SETCOM, 0x25);
+
+	/* Normal mode 70Hz, Idle mode 55 Hz */
+	mipi_dbi_command(mipi, HX8357_SETOSC, 0x68);
+
+	/* Set Panel - BGR, Gate direction swapped */
+	mipi_dbi_command(mipi, HX8357_SETPANEL, 0x05);
+
+	mipi_dbi_command(mipi, HX8357_SETPWR1,
+			 0x00,  /* Not deep standby */
+			 0x15,  /* BT */
+			 0x1C,  /* VSPR */
+			 0x1C,  /* VSNR */
+			 0x83,  /* AP */
+			 0xAA);  /* FS */
+
+	mipi_dbi_command(mipi, HX8357D_SETSTBA,
+			 0x50,  /* OPON normal */
+			 0x50,  /* OPON idle */
+			 0x01,  /* STBA */
+			 0x3C,  /* STBA */
+			 0x1E,  /* STBA */
+			 0x08);  /* GEN */
+
+	mipi_dbi_command(mipi, HX8357D_SETCYC,
+			 0x02,  /* NW 0x02 */
+			 0x40,  /* RTN */
+			 0x00,  /* DIV */
+			 0x2A,  /* DUM */
+			 0x2A,  /* DUM */
+			 0x0D,  /* GDON */
+			 0x78);  /* GDOFF */
+
+	mipi_dbi_command(mipi, HX8357D_SETGAMMA,
+			 0x02,
+			 0x0A,
+			 0x11,
+			 0x1d,
+			 0x23,
+			 0x35,
+			 0x41,
+			 0x4b,
+			 0x4b,
+			 0x42,
+			 0x3A,
+			 0x27,
+			 0x1B,
+			 0x08,
+			 0x09,
+			 0x03,
+			 0x02,
+			 0x0A,
+			 0x11,
+			 0x1d,
+			 0x23,
+			 0x35,
+			 0x41,
+			 0x4b,
+			 0x4b,
+			 0x42,
+			 0x3A,
+			 0x27,
+			 0x1B,
+			 0x08,
+			 0x09,
+			 0x03,
+			 0x00,
+			 0x01);
+
+	/* 16 bit */
+	mipi_dbi_command(mipi, MIPI_DCS_SET_PIXEL_FORMAT,
+			 MIPI_DCS_PIXEL_FMT_16BIT);
+
+	/* TE off */
+	mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_ON, 0x00);
+
+	/* tear line */
+	mipi_dbi_command(mipi, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x02);
+
+	/* Exit Sleep */
+	mipi_dbi_command(mipi, MIPI_DCS_EXIT_SLEEP_MODE);
+	msleep(150);
+
+	/* display on */
+	mipi_dbi_command(mipi, MIPI_DCS_SET_DISPLAY_ON);
+	usleep_range(5000, 7000);
+
+out_enable:
+	switch (mipi->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(mipi, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
+	mipi_dbi_enable_flush(mipi, crtc_state, plane_state);
+}
+
+static const struct drm_simple_display_pipe_funcs hx8357d_pipe_funcs = {
+	.enable = yx240qv29_enable,
+	.disable = mipi_dbi_pipe_disable,
+	.update = tinydrm_display_pipe_update,
+	.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
+};
+
+static const struct drm_display_mode yx350hv15_mode = {
+	TINYDRM_MODE(320, 480, 60, 75),
+};
+
+DEFINE_DRM_GEM_CMA_FOPS(hx8357d_fops);
+
+static struct drm_driver hx8357d_driver = {
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
+	.fops			= &hx8357d_fops,
+	TINYDRM_GEM_DRIVER_OPS,
+	.debugfs_init		= mipi_dbi_debugfs_init,
+	.name			= "hx8357d",
+	.desc			= "HX8357D",
+	.date			= "20181023",
+	.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[] = {
+	{ "hx8357d", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, hx8357d_id);
+
+static int hx8357d_probe(struct spi_device *spi)
+{
+	struct device *dev = &spi->dev;
+	struct mipi_dbi *mipi;
+	struct gpio_desc *dc;
+	u32 rotation = 0;
+	int ret;
+
+	mipi = devm_kzalloc(dev, sizeof(*mipi), GFP_KERNEL);
+	if (!mipi)
+		return -ENOMEM;
+
+	dc = devm_gpiod_get(dev, "dc", GPIOD_OUT_LOW);
+	if (IS_ERR(dc)) {
+		DRM_DEV_ERROR(dev, "Failed to get gpio 'dc'\n");
+		return PTR_ERR(dc);
+	}
+
+	mipi->backlight = devm_of_find_backlight(dev);
+	if (IS_ERR(mipi->backlight))
+		return PTR_ERR(mipi->backlight);
+
+	device_property_read_u32(dev, "rotation", &rotation);
+
+	ret = mipi_dbi_spi_init(spi, mipi, dc);
+	if (ret)
+		return ret;
+
+	ret = mipi_dbi_init(&spi->dev, mipi, &hx8357d_pipe_funcs,
+			    &hx8357d_driver, &yx350hv15_mode, rotation);
+	if (ret)
+		return ret;
+
+	spi_set_drvdata(spi, mipi);
+
+	return devm_tinydrm_register(&mipi->tinydrm);
+}
+
+static void hx8357d_shutdown(struct spi_device *spi)
+{
+	struct mipi_dbi *mipi = spi_get_drvdata(spi);
+
+	tinydrm_shutdown(&mipi->tinydrm);
+}
+
+static struct spi_driver hx8357d_spi_driver = {
+	.driver = {
+		.name = "hx8357d",
+		.of_match_table = hx8357d_of_match,
+	},
+	.id_table = hx8357d_id,
+	.probe = hx8357d_probe,
+	.shutdown = hx8357d_shutdown,
+};
+module_spi_driver(hx8357d_spi_driver);
+
+MODULE_DESCRIPTION("HX8357D DRM driver");
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tinydrm/hx8357d.h b/drivers/gpu/drm/tinydrm/hx8357d.h
new file mode 100644
index 000000000000..6180b093f94f
--- /dev/null
+++ b/drivers/gpu/drm/tinydrm/hx8357d.h
@@ -0,0 +1,71 @@ 
+/* SPDX-License-Identifier: MIT */
+/*
+ * This is our library for the Adafruit  ILI9341 Breakout and Shield
+ * ----> http://www.adafruit.com/products/1651
+ *
+ * Check out the links above for our tutorials and wiring diagrams
+ * These displays use SPI to communicate, 4 or 5 pins are required to
+ * interface (RST is optional)
+ * Adafruit invests time and resources providing this open source code,
+ * please support Adafruit and open-source hardware by purchasing
+ * products from Adafruit!
+ *
+ * Written by Limor Fried/Ladyada for Adafruit Industries.
+ * MIT license, all text above must be included in any redistribution
+ */
+
+#ifndef __HX8357_H__
+#define __HX8357_H__
+
+#define HX8357D 0xD
+#define HX8357B 0xB
+
+#define HX8357_TFTWIDTH  320
+#define HX8357_TFTHEIGHT 480
+
+#define HX8357_SETOSC 0xB0
+#define HX8357_SETPWR1 0xB1
+#define HX8357B_SETDISPLAY 0xB2
+#define HX8357_SETRGB 0xB3
+#define HX8357D_SETCOM  0xB6
+
+#define HX8357B_SETDISPMODE  0xB4
+#define HX8357D_SETCYC  0xB4
+#define HX8357B_SETOTP 0xB7
+#define HX8357D_SETC 0xB9
+
+#define HX8357B_SET_PANEL_DRIVING 0xC0
+#define HX8357D_SETSTBA 0xC0
+#define HX8357B_SETDGC  0xC1
+#define HX8357B_SETID  0xC3
+#define HX8357B_SETDDB  0xC4
+#define HX8357B_SETDISPLAYFRAME 0xC5
+#define HX8357B_GAMMASET 0xC8
+#define HX8357B_SETCABC  0xC9
+#define HX8357_SETPANEL  0xCC
+
+#define HX8357B_SETPOWER 0xD0
+#define HX8357B_SETVCOM 0xD1
+#define HX8357B_SETPWRNORMAL 0xD2
+
+#define HX8357B_RDID1   0xDA
+#define HX8357B_RDID2   0xDB
+#define HX8357B_RDID3   0xDC
+#define HX8357B_RDID4   0xDD
+
+#define HX8357D_SETGAMMA 0xE0
+
+#define HX8357B_SETGAMMA 0xC8
+#define HX8357B_SETPANELRELATED  0xE9
+
+/* Color definitions */
+#define	HX8357_BLACK   0x0000
+#define	HX8357_BLUE    0x001F
+#define	HX8357_RED     0xF800
+#define	HX8357_GREEN   0x07E0
+#define HX8357_CYAN    0x07FF
+#define HX8357_MAGENTA 0xF81F
+#define HX8357_YELLOW  0xFFE0
+#define HX8357_WHITE   0xFFFF
+
+#endif /* __HX8357_H__ */