All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sam Ravnborg <sam@ravnborg.org>
To: Josef Lusticky <josef@lusticky.cz>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 1/2] drm/panel: Add Ilitek ILI9341 parallel RGB panel driver
Date: Wed, 5 Jun 2019 23:21:12 +0200	[thread overview]
Message-ID: <20190605212112.GB2348@ravnborg.org> (raw)
In-Reply-To: <20190219132101.27196-2-josef@lusticky.cz>

Hi Josef.

Thanks for the patch. A little late review follows.

Just a few thing, but please fix and resend.

	Sam

> +++ b/MAINTAINERS
> @@ -4800,6 +4800,12 @@ S:	Maintained
>  F:	drivers/gpu/drm/tinydrm/ili9225.c
>  F:	Documentation/devicetree/bindings/display/ilitek,ili9225.txt
>  
> +DRM DRIVER FOR ILITEK ILI9341 PANELS
> +M:	Josef Lusticky <josef@lusticky.cz>
> +S:	Maintained
> +F:	drivers/gpu/drm/panel/panel-ilitek-ili9341.c
> +F:	Documentation/devicetree/bindings/display/panel/ilitek,ili9341.txt
> +
>  DRM DRIVER FOR HX8357D PANELS
>  M:	Eric Anholt <eric@anholt.net>
>  T:	git git://anongit.freedesktop.org/drm/drm-misc

I recall entries in MAINTAINERS are supposed to be ordred alphabitically
after their title. So this needs to be fixed (H comes before I)

>  
> +config DRM_PANEL_ILITEK_IL9341
> +	tristate "Ilitek ILI9341 240x320 panels"
> +	depends on OF && SPI
> +	help
> +	  Say Y here if you want to enable support for Ilitek IL9341
> +	  QVGA (240x320) RGB panel.
The panel uses backlight - should it depens on BACKLIGHT?

> +
>  config DRM_PANEL_ILITEK_ILI9881C
>  	tristate "Ilitek ILI9881C-based panels"
>  	depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index e7ab71968bbf..1df564018bc4 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -3,6 +3,7 @@ obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
>  obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
>  obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
>  obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
> +obj-$(CONFIG_DRM_PANEL_ILITEK_IL9341) += panel-ilitek-ili9341.o
>  obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
>  obj-$(CONFIG_DRM_PANEL_INNOLUX_P079ZCA) += panel-innolux-p079zca.o
>  obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o
> diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
> new file mode 100644
> index 000000000000..51ed03140f8d
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c
> @@ -0,0 +1,320 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Ilitek ILI9341 drm_panel driver
> + * 240RGBx320 dots resolution TFT LCD display
> + *
> + * This driver support the following panel configurations:
> + * - 18-bit parallel RGB interface
> + * - 8-bit SPI with Data/Command GPIO
> + *
> + * Copyright (C) 2019 Josef Lusticky <josef@lusticky.cz>
> + *
> + */
> +
> +#include <drm/drm_modes.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_print.h>
> +
> +#include <linux/backlight.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/spi/spi.h>
> +
> +#include <video/mipi_display.h>

Please include files in following blocks:

#include <linux/*>

#include <video/*>

#include <drm/*>

This matches what other panel drivers do today.
(It was only recently made the same for all drivers)


> +
> +/* ILI9341 extended register set */
> +#define ILI9341_IFMODE         0xB0 // clock polarity
> +#define ILI9341_IFCTL          0xF6 // interface conrol
> +#define ILI9341_PGAMCTRL       0xE0 // positive gamma control
> +#define ILI9341_NGAMCTRL       0xE1 // negative gamma control
> +
> +#define ILI9341_MADCTL_MV      BIT(5)
> +#define ILI9341_MADCTL_MX      BIT(6)
> +#define ILI9341_MADCTL_MY      BIT(7)
> +
> +/**
> + * struct ili9341_config - the display specific configuration
> + * @width_mm: physical panel width [mm]
> + * @height_mm: physical panel height [mm]
> + */
> +struct ili9341_config {
> +	u32 width_mm;
> +	u32 height_mm;
> +};
> +
> +struct ili9341 {
> +	const struct ili9341_config *conf;
> +	struct drm_panel panel;
> +	struct spi_device *spi;
> +	struct backlight_device *backlight;
> +	struct gpio_desc *dc_gpio;
> +	struct gpio_desc *reset_gpio;
> +};
No power-supply?
It is not in the binding, so likely not. But just wondering.

> +
> +static inline struct ili9341 *panel_to_ili9341(struct drm_panel *panel)
> +{
> +	return container_of(panel, struct ili9341, panel);
> +}
> +
> +static int ili9341_spi_write_command(struct ili9341 *ili, u8 cmd)
> +{
> +	struct spi_transfer xfer = {
> +		.tx_buf = &cmd,
> +		.bits_per_word = 8,
> +		.len = 1
> +	};
> +	struct spi_message msg;
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfer, &msg);
> +
> +	gpiod_set_value(ili->dc_gpio, 0);
> +
> +	return spi_sync(ili->spi, &msg);
> +}
> +
> +static int ili9341_spi_write_data(struct ili9341 *ili, u8 *data, size_t size)
> +{
> +	struct spi_transfer xfer = {
> +		.tx_buf = data,
> +		.bits_per_word = 8,
> +		.len = size
> +	};
> +
> +	struct spi_message msg;
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfer, &msg);
> +
> +	gpiod_set_value(ili->dc_gpio, 1);
> +
> +	return spi_sync(ili->spi, &msg);
> +}
> +
> +#define ili9341_spi_write(ili, cmd, data...) \
> +({ \
> +	u8 d[] = { data }; \
> +	ili9341_spi_write_command(ili, cmd); \
> +	if (ARRAY_SIZE(d) > 0) \
> +		ili9341_spi_write_data(ili, d, ARRAY_SIZE(d)); \
> +})
> +
> +static int ili9341_deinit(struct drm_panel *panel, struct ili9341 *ili)
> +{
> +	ili9341_spi_write(ili, MIPI_DCS_SET_DISPLAY_OFF);
> +	ili9341_spi_write(ili, MIPI_DCS_ENTER_SLEEP_MODE);
> +	msleep(5);
> +	return 0;
> +}
> +
> +static int ili9341_init(struct drm_panel *panel, struct ili9341 *ili)
> +{
> +	/* HW / SW Reset display and wait */
> +	if (ili->reset_gpio) {
> +		gpiod_set_value(ili->reset_gpio, 0);
> +		usleep_range(20, 1000);
> +		gpiod_set_value(ili->reset_gpio, 1);
> +	} else {
> +		ili9341_spi_write(ili, MIPI_DCS_SOFT_RESET);
> +	}
> +	msleep(120);
> +
> +	/* Polarity */
> +	ili9341_spi_write(ili, ILI9341_IFMODE, 0xC0);
> +
> +	/* Interface control */
> +	ili9341_spi_write(ili, ILI9341_IFCTL, 0x09, 0x01, 0x26);
> +
> +	/* Pixel format */
> +	ili9341_spi_write(ili, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_18BIT << 4);
> +
> +	/* Gamma */
> +	ili9341_spi_write(ili, MIPI_DCS_SET_GAMMA_CURVE, 0x01);
> +	ili9341_spi_write(ili, ILI9341_PGAMCTRL,
> +		0x0f, 0x31, 0x2b, 0x0c, 0x0e, 0x08, 0x4e, 0xf1,
> +		0x37, 0x07, 0x10, 0x03, 0x0e, 0x09, 0x00);
> +	ili9341_spi_write(ili, ILI9341_NGAMCTRL,
> +		0x00, 0x0e, 0x14, 0x03, 0x11, 0x07, 0x31, 0xc1,
> +		0x48, 0x08, 0x0f, 0x0c, 0x31, 0x36, 0x0f);
> +
> +	/* Rotation */
> +	ili9341_spi_write(ili, MIPI_DCS_SET_ADDRESS_MODE, ILI9341_MADCTL_MX);
> +
> +	/* Exit sleep mode */
> +	ili9341_spi_write(ili, MIPI_DCS_EXIT_SLEEP_MODE);
> +	msleep(120);
> +
> +	ili9341_spi_write(ili, MIPI_DCS_SET_DISPLAY_ON);
> +
> +	return 0;
> +}
> +
> +static int ili9341_unprepare(struct drm_panel *panel)
> +{
> +	struct ili9341 *ili = panel_to_ili9341(panel);
> +	return ili9341_deinit(panel, ili);
> +}
> +
> +static int ili9341_prepare(struct drm_panel *panel)
> +{
> +	struct ili9341 *ili = panel_to_ili9341(panel);
> +	int ret;
> +
> +	ret = ili9341_init(panel, ili);
> +	if (ret < 0)
> +		ili9341_unprepare(panel);
> +	return ret;
> +}
> +
> +static int ili9341_enable(struct drm_panel *panel)
> +{
> +	struct ili9341 *ili = panel_to_ili9341(panel);
> +	return backlight_enable(ili->backlight);
> +}
> +
> +static int ili9341_disable(struct drm_panel *panel)
> +{
> +	struct ili9341 *ili = panel_to_ili9341(panel);
> +	return backlight_disable(ili->backlight);
> +}
> +
> +static const struct drm_display_mode prgb_240x320_mode = {
> +	.clock = 6350,
> +
> +	.hdisplay = 240,
> +	.hsync_start = 240 + 10,
> +	.hsync_end = 240 + 10 + 10,
> +	.htotal = 240 + 10 + 10 + 20,
> +
> +	.vdisplay = 320,
> +	.vsync_start = 320 + 4,
> +	.vsync_end = 320 + 4 + 2,
> +	.vtotal = 320 + 4 + 2 + 2,
> +
> +	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
> +	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED
> +};
> +
> +static int ili9341_get_modes(struct drm_panel *panel)
> +{
> +	struct drm_connector *connector = panel->connector;
> +	struct ili9341 *ili = panel_to_ili9341(panel);
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_mode_duplicate(panel->drm, &prgb_240x320_mode);
check if drm_mode_duplicate() fails, and handle this.
See how other drivers do it.

> +	drm_mode_set_name(mode);
> +
> +	mode->width_mm = ili->conf->width_mm;
> +	mode->height_mm = ili->conf->height_mm;
> +
> +	strncpy(connector->display_info.name, "ILI9341 TFT LCD driver\0",
> +		DRM_DISPLAY_INFO_LEN);
> +	connector->display_info.width_mm = mode->width_mm;
> +	connector->display_info.height_mm = mode->height_mm;
> +	connector->display_info.bus_flags |= DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE |
> +		DRM_BUS_FLAG_SYNC_NEGEDGE;
> +
> +	drm_mode_probed_add(connector, mode);
> +
> +	return 1; /* Number of modes */
> +}
> +
> +static const struct drm_panel_funcs ili9341_drm_funcs = {
> +	.disable = ili9341_disable,
> +	.unprepare = ili9341_unprepare,
> +	.prepare = ili9341_prepare,
> +	.enable = ili9341_enable,
> +	.get_modes = ili9341_get_modes,
> +};
> +
> +static int ili9341_probe(struct spi_device *spi)
> +{
> +	struct device *dev = &spi->dev;
> +	struct ili9341 *ili;
> +	int ret;
> +
> +	ili = devm_kzalloc(dev, sizeof(struct ili9341), GFP_KERNEL);
> +	if (!ili)
> +		return -ENOMEM;
> +
> +	spi_set_drvdata(spi, ili);
> +
> +	ili->spi = spi;
> +
> +	/*
> +	 * Every new incarnation of this display must have a unique
> +	 * data entry for the system in this driver.
> +	 */
> +	ili->conf = of_device_get_match_data(dev);
> +	if (!ili->conf) {
> +		DRM_DEV_ERROR(dev, "missing device configuration\n");
> +		return -ENODEV;
> +	}
> +
> +	ili->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
> +	if (IS_ERR(ili->reset_gpio)) {
> +		DRM_DEV_ERROR(dev, "failed to get reset gpio\n");
> +		return PTR_ERR(ili->reset_gpio);
> +	}
> +
> +	ili->dc_gpio = devm_gpiod_get_optional(dev, "dc", GPIOD_OUT_LOW);
> +	if (IS_ERR(ili->dc_gpio)) {
> +		DRM_DEV_ERROR(dev, "failed to get dc gpio\n");
> +		return PTR_ERR(ili->dc_gpio);
> +	}
> +
> +	ili->backlight = devm_of_find_backlight(dev);
> +	if (IS_ERR(ili->backlight)) {
> +		DRM_DEV_ERROR(dev, "failed to get backlight\n");
> +		return PTR_ERR(ili->backlight);
> +	}
> +
> +	ret = spi_setup(spi);
> +	if (ret < 0) {
> +		DRM_DEV_ERROR(dev, "spi setup failed\n");
> +		return ret;
> +	}
> +
> +	drm_panel_init(&ili->panel);
> +	ili->panel.dev = dev;
> +	ili->panel.funcs = &ili9341_drm_funcs;
> +
> +	return drm_panel_add(&ili->panel);
> +}
> +
> +static int ili9341_remove(struct spi_device *spi)
> +{
> +	struct ili9341 *ili = spi_get_drvdata(spi);
> +
> +	drm_panel_remove(&ili->panel);
> +
> +	ili9341_disable(&ili->panel);
> +	ili9341_unprepare(&ili->panel);
> +
> +	return 0;
> +}
> +
> +static const struct ili9341_config dt024ctft_data = {
> +	.width_mm = 37,
> +	.height_mm = 49,
> +};
> +
> +static const struct of_device_id ili9341_of_match[] = {
> +	{ .compatible = "displaytech,dt024ctft", .data = &dt024ctft_data },
> +	{ }
Many drivers add the comment { /* sentinel */ } to document this is a
mandatory end marker.

> +};
> +MODULE_DEVICE_TABLE(of, ili9341_of_match);
> +
> +static struct spi_driver ili9341_driver = {
> +	.probe = ili9341_probe,
> +	.remove = ili9341_remove,
> +	.driver = {
> +		.name = "panel-ilitek-ili9341",
> +		.of_match_table = ili9341_of_match,
> +	},
> +};
> +module_spi_driver(ili9341_driver);
> +
> +MODULE_AUTHOR("Josef Lusticky <josef@lusticky.cz>");
> +MODULE_DESCRIPTION("ILI9341 LCD panel driver");
> +MODULE_LICENSE("GPL");
> -- 
> 2.20.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2019-06-05 21:21 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-19 13:20 [PATCH 0/2] Add DRM panel driver for Ilitek ILI9341 based panels in parallel RGB mode Josef Lusticky
2019-02-19 13:21 ` [PATCH 1/2] drm/panel: Add Ilitek ILI9341 parallel RGB panel driver Josef Lusticky
2019-06-05 21:21   ` Sam Ravnborg [this message]
2019-02-19 13:21 ` [PATCH 2/2] dt-bindings: panel: Add Ilitek ILI9341 panel documentation Josef Lusticky
2019-06-05 21:16   ` Sam Ravnborg
2019-06-26 12:57 ` [PATCH 0/2] Add DRM panel driver for Ilitek ILI9341 based panels in parallel RGB mode Sam Ravnborg
2019-06-26 15:21   ` Josef Luštický
2019-06-26 16:04     ` Sam Ravnborg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190605212112.GB2348@ravnborg.org \
    --to=sam@ravnborg.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=josef@lusticky.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.