From patchwork Tue Oct 23 07:46:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 149434 Delivered-To: patch@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp375645ljp; Tue, 23 Oct 2018 00:47:18 -0700 (PDT) X-Google-Smtp-Source: AJdET5eBF7fuXNdFYwpgJvoQxw2EYiR+JjJodswqQE2dTD0lrlCFNcCcS1xQhR+QrgUnzeO+o74C X-Received: by 2002:a63:42c1:: with SMTP id p184mr3594036pga.202.1540280837944; Tue, 23 Oct 2018 00:47:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1540280837; cv=none; d=google.com; s=arc-20160816; b=FXQHc4k1iy/jF4oZf1gRfROar1uiceDFNEKiS7tGWbgbhmWS1/mzR76nvpxmJM7y8/ a8ueTJus0Kyyla1zAcvq4bqanDSDhk964QgKwH7gpgGtRZ6doR7+OV1IdxM5BTekj7FD Zwpju9ICyElwpKTGB3UsdBQd5FLgaZb4ajxSDYFP31UI+N2evS62S45HIhOiXBwwaPxo mAtJEzhmPahIaE/VrXv9pvD0mY5Co+g2Xe9T4jtCeAk+6GFVB1YcxeVNnjqu+vFphMRi jLC8X/Ro6raiEkAuwXwZXDcctUMkeK8coiy5WIi2hcqs8qlbbi1kL/+oz/Ja9SDW3qFe FIJA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:references:in-reply-to:message-id:date:subject :to:from:delivered-to; bh=aK2y5HfdfCVYU7t7Uk7Ufn+l3Z7FPjYR6vEZm32nJzg=; b=dDkAUW5l0mI3dQNeJmqoKpJiRLonf+SYGB3La7MPvMA8OveSUJJ9ecHph+iaFzMgIl ZCbPgnVAA717cC2sfCrR3n4gnaCDJl37lm6y2rUScIxx81WcIDVIrLJ0w32/2IfoLYo+ AL4tQC1UsmNNM5ix3hfs9GEF8YYL0N6e8MppOcpGB+VsXRxbcHgQVlowlaHBke77A/qe mrjYTQ5glNbklZ8qlozr9f4QrWca526e9mbaLjEhay7uGLKDRGR2jsSE4eNW8L9pMEuZ 3oqpkcjmE0rttyJQhlEYTZ/fSsoCG8Qyi5o42V6MRbX6VcivIDPi1GS2tJwdqQvF3mwj LywQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from gabe.freedesktop.org (gabe.freedesktop.org. [131.252.210.177]) by mx.google.com with ESMTPS id h1-v6si514416pgs.493.2018.10.23.00.47.17 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 23 Oct 2018 00:47:17 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) client-ip=131.252.210.177; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of dri-devel-bounces@lists.freedesktop.org designates 131.252.210.177 as permitted sender) smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C9A846E0CA; Tue, 23 Oct 2018 07:46:46 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-lf1-x144.google.com (mail-lf1-x144.google.com [IPv6:2a00:1450:4864:20::144]) by gabe.freedesktop.org (Postfix) with ESMTPS id 8BBCC6E0C1 for ; Tue, 23 Oct 2018 07:46:43 +0000 (UTC) Received: by mail-lf1-x144.google.com with SMTP id p34-v6so336263lfg.10 for ; Tue, 23 Oct 2018 00:46:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ohEnm9x9LBvUIXzbg/Yg6Ebuv8c2VZLMeYtkg9Ryld0=; b=gQHfK9kYhb8+kZngabbP37P+Evv8BdKGIlrHVitcazC8rKhoaqAq92WJ/8clpyUo7T 4spHSOeox1DXyEszWq9SjRgvwzsW8HpbDFgEhVcyek9OGTh82lcmx9tBSa98ZeX3aRmR zsoIr+2Ll3vjjTWbxuFmMSTpyywGM4Q7UWu+UnssugX4IemzoHy/BtuzX6Ojpd2lQwr7 MNwRicURvTgsAEiGcLWuNT9U5DHgANAKpIOcPbW0Ri+KWBaiStCVTvGqYIQQAP0ipccN jhuInNp4YJUQ3COD4ghXijX+4PfjkEHygEpgsunZ7NQVwYtxP/otZZ13X68R8kaSRDsw Fgzw== X-Gm-Message-State: ABuFfoghiw2HcSBCGcyR2iGYK9LbuBhgU+MBHwIdMMhXRIR2LDIXEfA3 IfQhCMUmxgaD5Bsw9XzBk9IorA== X-Received: by 2002:a19:f20:: with SMTP id e32mr11919251lfi.51.1540280801797; Tue, 23 Oct 2018 00:46:41 -0700 (PDT) Received: from genomnajs.ideon.se ([85.235.10.227]) by smtp.gmail.com with ESMTPSA id d126-v6sm87221lfe.75.2018.10.23.00.46.39 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 23 Oct 2018 00:46:40 -0700 (PDT) From: Linus Walleij To: Thierry Reding , dri-devel@lists.freedesktop.org Subject: [PATCH 2/2 v3] drm/panel: Add driver for Samsung S6D16D0 panel Date: Tue, 23 Oct 2018 09:46:30 +0200 Message-Id: <20181023074630.29186-2-linus.walleij@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20181023074630.29186-1-linus.walleij@linaro.org> References: <20181023074630.29186-1-linus.walleij@linaro.org> X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The Samsung S6D16D0 is a simple comman mode only DSI display that is used on the ST-Ericsson Ux500 reference design TVK1281618 user interface board (UIB). Cc: Andrzej Hajda Reviewed-by: Sam Ravnborg Signed-off-by: Linus Walleij --- ChangeLog v2->v3: - Set HS and LP frequencies using the new struct members. - Put physical height+width into the mode struct - Calculate vrefresh from the HS clock frequency and put in some comments on how it was calculated - Some code cosmetics - Collect Sam's review tag. ChangeLog v1->v2: - Drop Backlight dependency from the Kconfig - this display has built-in backlight, I think. - Drop the big include and replace by more precise to-the-point includes. - Move display on/off to the enable/disable callbacks. - Use DRM_DEV_ERROR() instead of dev_err(). --- drivers/gpu/drm/panel/Kconfig | 6 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-samsung-s6d16d0.c | 264 ++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-samsung-s6d16d0.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 6020c30a33b3..d3bb5b526015 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -126,6 +126,12 @@ config DRM_PANEL_RAYDIUM_RM68200 Say Y here if you want to enable support for Raydium RM68200 720x1280 DSI video mode panel. +config DRM_PANEL_SAMSUNG_S6D16D0 + tristate "Samsung S6D16D0 DSI video mode panel" + depends on OF + depends on DRM_MIPI_DSI + select VIDEOMODE_HELPERS + config DRM_PANEL_SAMSUNG_S6E3HA2 tristate "Samsung S6E3HA2 DSI video mode panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 5ccaaa9d13af..b52e5c5804ca 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c new file mode 100644 index 000000000000..aaf8f39e7830 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MIPI-DSI Samsung s6d16d0 panel driver. This is a 864x480 + * AMOLED panel with a command-only DSI interface. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct s6d16d0 { + struct device *dev; + struct drm_panel panel; + struct regulator *supply; + struct gpio_desc *reset_gpio; +}; + +/* + * The timings are not very helpful as the display is used in + * command mode. + */ +static const struct drm_display_mode samsung_s6d16d0_mode = { + /* HS clock, (htotal*vtotal*vrefresh)/1000 */ + .clock = 420160, + .hdisplay = 864, + .hsync_start = 864 + 154, + .hsync_end = 864 + 154 + 16, + .htotal = 864 + 154 + 16 + 32, + .vdisplay = 480, + .vsync_start = 480 + 1, + .vsync_end = 480 + 1 + 1, + .vtotal = 480 + 1 + 1 + 1, + /* + * This depends on the clocking HS vs LP rate, this value + * is calculated as: + * vrefresh = (clock * 1000) / (htotal*vtotal) + */ + .vrefresh = 816, + .width_mm = 84, + .height_mm = 48, +}; + +static inline struct s6d16d0 *panel_to_s6d16d0(struct drm_panel *panel) +{ + return container_of(panel, struct s6d16d0, panel); +} + +static int s6d16d0_unprepare(struct drm_panel *panel) +{ + struct s6d16d0 *s6 = panel_to_s6d16d0(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev); + int ret; + + /* Enter sleep mode */ + ret = mipi_dsi_dcs_enter_sleep_mode(dsi); + if (ret) { + DRM_DEV_ERROR(s6->dev, "failed to enter sleep mode (%d)\n", + ret); + return ret; + } + + /* Assert RESET */ + gpiod_set_value_cansleep(s6->reset_gpio, 1); + regulator_disable(s6->supply); + + return 0; +} + +static int s6d16d0_prepare(struct drm_panel *panel) +{ + struct s6d16d0 *s6 = panel_to_s6d16d0(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev); + int ret; + + ret = regulator_enable(s6->supply); + if (ret) { + DRM_DEV_ERROR(s6->dev, "failed to enable supply (%d)\n", ret); + return ret; + } + + /* Assert RESET */ + gpiod_set_value_cansleep(s6->reset_gpio, 1); + udelay(10); + /* De-assert RESET */ + gpiod_set_value_cansleep(s6->reset_gpio, 0); + msleep(120); + + /* Enabe tearing mode: send TE (tearing effect) at VBLANK */ + ret = mipi_dsi_dcs_set_tear_on(dsi, + MIPI_DSI_DCS_TEAR_MODE_VBLANK); + if (ret) { + DRM_DEV_ERROR(s6->dev, "failed to enble vblank TE (%d)\n", + ret); + return ret; + } + /* Exit sleep mode and power on */ + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret) { + DRM_DEV_ERROR(s6->dev, "failed to exit sleep mode (%d)\n", + ret); + return ret; + } + + return 0; +} + +static int s6d16d0_enable(struct drm_panel *panel) +{ + struct s6d16d0 *s6 = panel_to_s6d16d0(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev); + int ret; + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret) { + DRM_DEV_ERROR(s6->dev, "failed to turn display on (%d)\n", + ret); + return ret; + } + + return 0; +} + +static int s6d16d0_disable(struct drm_panel *panel) +{ + struct s6d16d0 *s6 = panel_to_s6d16d0(panel); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(s6->dev); + int ret; + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret) { + DRM_DEV_ERROR(s6->dev, "failed to turn display off (%d)\n", + ret); + return ret; + } + + return 0; +} + +static int s6d16d0_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct drm_display_mode *mode; + + strncpy(connector->display_info.name, "Samsung S6D16D0\0", + DRM_DISPLAY_INFO_LEN); + + mode = drm_mode_duplicate(panel->drm, &samsung_s6d16d0_mode); + if (!mode) { + DRM_ERROR("bad mode or failed to add mode\n"); + return -EINVAL; + } + drm_mode_set_name(mode); + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + + drm_mode_probed_add(connector, mode); + + return 1; /* Number of modes */ +} + +static const struct drm_panel_funcs s6d16d0_drm_funcs = { + .disable = s6d16d0_disable, + .unprepare = s6d16d0_unprepare, + .prepare = s6d16d0_prepare, + .enable = s6d16d0_enable, + .get_modes = s6d16d0_get_modes, +}; + +static int s6d16d0_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct s6d16d0 *s6; + int ret; + + s6 = devm_kzalloc(dev, sizeof(struct s6d16d0), GFP_KERNEL); + if (!s6) + return -ENOMEM; + + mipi_dsi_set_drvdata(dsi, s6); + s6->dev = dev; + + dsi->lanes = 2; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->hs_rate = 420160000; + dsi->lp_rate = 19200000; + /* + * This display uses command mode so no MIPI_DSI_MODE_VIDEO + * or MIPI_DSI_MODE_VIDEO_SYNC_PULSE + * + * As we only send commands we do not need to be continously + * clocked. + */ + dsi->mode_flags = + MIPI_DSI_CLOCK_NON_CONTINUOUS | + MIPI_DSI_MODE_EOT_PACKET; + + s6->supply = devm_regulator_get(dev, "vdd1"); + if (IS_ERR(s6->supply)) + return PTR_ERR(s6->supply); + + /* This asserts RESET by default */ + s6->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(s6->reset_gpio)) { + ret = PTR_ERR(s6->reset_gpio); + if (ret != -EPROBE_DEFER) + DRM_DEV_ERROR(dev, "failed to request GPIO (%d)\n", + ret); + return ret; + } + + drm_panel_init(&s6->panel); + s6->panel.dev = dev; + s6->panel.funcs = &s6d16d0_drm_funcs; + + ret = drm_panel_add(&s6->panel); + if (ret < 0) + return ret; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) + drm_panel_remove(&s6->panel); + + return ret; +} + +static int s6d16d0_remove(struct mipi_dsi_device *dsi) +{ + struct s6d16d0 *s6 = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&s6->panel); + + return 0; +} + +static const struct of_device_id s6d16d0_of_match[] = { + { .compatible = "samsung,s6d16d0" }, + { } +}; +MODULE_DEVICE_TABLE(of, s6d16d0_of_match); + +static struct mipi_dsi_driver s6d16d0_driver = { + .probe = s6d16d0_probe, + .remove = s6d16d0_remove, + .driver = { + .name = "panel-samsung-s6d16d0", + .of_match_table = s6d16d0_of_match, + }, +}; +module_mipi_dsi_driver(s6d16d0_driver); + +MODULE_AUTHOR("Linus Wallei "); +MODULE_DESCRIPTION("MIPI-DSI s6d16d0 Panel Driver"); +MODULE_LICENSE("GPL v2");