summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2020-11-04 03:55:11 +0300
committerDave Airlie <airlied@redhat.com>2020-11-04 04:49:10 +0300
commit1cd260a7905e3ba2e5dfa39b110ad6cf8f466f49 (patch)
treebfb701fdb0fcb32f8e6e53fb1692361c8fa33a6a /drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c
parent3cea11cd5e3b00d91caf0b4730194039b45c5891 (diff)
parent4dfec0d1d7b9970f36931de714b379dbeaed83f8 (diff)
downloadlinux-1cd260a7905e3ba2e5dfa39b110ad6cf8f466f49.tar.xz
Merge tag 'drm-misc-next-2020-10-27' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for 5.11: UAPI Changes: - doc: rules for EBUSY on non-blocking commits; requirements for fourcc modifiers; on parsing EDID - fbdev/sbuslib: Remove unused FBIOSCURSOR32 - fourcc: deprecate DRM_FORMAT_MOD_NONE - virtio: Support blob resources for memory allocations; Expose host-visible and cross-device features Cross-subsystem Changes: - devicetree: Add vendor Prefix for Yes Optoelectronics, Shanghai Top Display Optoelectronics - dma-buf: Add struct dma_buf_map that stores DMA pointer and I/O-memory flag; dma_buf_vmap()/vunmap() return address in dma_buf_map; Use struct_size() macro Core Changes: - atomic: pass full state to CRTC atomic enable/disable; warn for EBUSY during non-blocking commits - dp: Prepare for DP 2.0 DPCD - dp_mst: Receive extended DPCD caps - dma-buf: Documentation - doc: Format modifiers; dma-buf-map; Cleanups - fbdev: Don't use compat_alloc_user_space(); mark as orphaned - fb-helper: Take lock in drm_fb_helper_restore_work_fb() - gem: Convert implementation and drivers to GEM object functions, remove GEM callbacks from struct drm_driver (expect gem_prime_mmap) - panel: Cleanups - pci: Add legacy infix to drm_irq_by_busid() - sched: Avoid infinite waits in drm_sched_entity_destroy() - switcheroo: Cleanups - ttm: Remove AGP support; Don't modify caching during swapout; Major refactoring of the implementation and API that affects all depending drivers; Add ttm_bo_wait_ctx(); Add ttm_bo_pin()/unpin() in favor of TTM_PL_FLAG_NO_EVICT; Remove ttm_bo_create(); Remove fault_reserve_notify() callback; Push move() implementation into drivers; Remove TTM_PAGE_FLAG_WRITE; Replace caching flags with init-time cache setting; Push ttm_tt_bind() into drivers; Replace move_notify() with delete_mem_notify(); No overlapping memcpy(); no more ttm_set_populated() - vram-helper: Fix BO top-down placement; TTM-related changes; Init GEM object functions with defaults; Default placement in system memory; Cleanups Driver Changes: - amdgpu: Use GEM object functions - armada: Use GEM object functions - aspeed: Configure output via sysfs; Init struct drm_driver with - ast: Reload LUT after FB format changes - bridge: Add driver and DT bindings for anx7625; Cleanups - bridge/dw-hdmi: Constify ops - bridge/ti-sn65dsi86: Add retries for link training - bridge/lvds-codec: Add support for regulator - bridge/tc358768: Restore connector support DRM_GEM_CMA_DRIVEROPS; Cleanups - display/ti,j721e-dss: Add DT properies assigned-clocks, assigned-clocks-parent and dma-coherent - display/ti,am65s-dss: Add DT properies assigned-clocks, assigned-clocks-parent and dma-coherent - etnaviv: Use GEM object functions - exynos: Use GEM object functions - fbdev: Cleanups and compiler fixes throughout framebuffer drivers - fbdev/cirrusfb: Avoid division by 0 - gma500: Use GEM object functions; Fix double-free of connector; Cleanups - hisilicon/hibmc: I2C-based DDC support; Use to_hibmc_drm_device(); Cleanups - i915: Use GEM object functions - imx/dcss: Init driver with DRM_GEM_CMA_DRIVER_OPS; Cleanups - ingenic: Reset pixel clock when parent clock changes; support reserved memory; Alloc F0 and F1 DMA channels at once; Support different pixel formats; Revert support for cached mmap buffers on F0/F1; support 30-bit/24-bit/8-bit-palette modes - komeda: Use DEFINE_SHOW_ATTRIBUTE - mcde: Detect platform_get_irq() errors - mediatek: Use GEM object functions - msm: Use GEM object functions - nouveau: Cleanups; TTM-related changes; Use GEM object functions - omapdrm: Use GEM object functions - panel: Add driver and DT bindings for Novatak nt36672a; Add driver and DT bindings for YTC700TLAG-05-201C; Add driver and DT bindings for TDO TL070WSH30; Cleanups - panel/mantix: Fix reset; Fix deref of NULL pointer in mantix_get_modes() - panel/otm8009a: Allow non-continuous dsi clock; Cleanups - panel/rm68200: Allow non-continuous dsi clock; Fix mode to 50 FPS - panfrost: Fix job timeout handling; Cleanups - pl111: Use GEM object functions - qxl: Cleanups; TTM-related changes; Pin new BOs with ttm_bo_init_reserved() - radeon: Cleanups; TTM-related changes; Use GEM object functions - rockchip: Use GEM object functions - shmobile: Cleanups - tegra: Use GEM object functions - tidss: Set drm_plane_helper_funcs.prepare_fb - tilcdc: Don't keep vblank interrupt enabled all the time - tve200: Detect platform_get_irq() errors - vc4: Use GEM object functions; Only register components once DSI is attached; Add Maxime as maintainer - vgem: Use GEM object functions - via: Simplify critical section in via_mem_alloc() - virtgpu: Use GEM object functions - virtio: Implement blob resources, host-visible and cross-device features; Support mapping of host-allocated resources; Use UUID APi; Cleanups - vkms: Use GEM object functions; Switch to SHMEM - vmwgfx: TTM-related changes; Inline ttm_bo_swapout_all() - xen: Use GEM object functions - xlnx: Use GEM object functions Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patchwork.freedesktop.org/patch/msgid/20201027100936.GA4858@linux-uq9g
Diffstat (limited to 'drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c')
-rw-r--r--drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c b/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c
new file mode 100644
index 000000000000..820731be7147
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-tdo-tl070wsh30.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+struct tdo_tl070wsh30_panel {
+ struct drm_panel base;
+ struct mipi_dsi_device *link;
+
+ struct regulator *supply;
+ struct gpio_desc *reset_gpio;
+
+ bool prepared;
+};
+
+static inline
+struct tdo_tl070wsh30_panel *to_tdo_tl070wsh30_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct tdo_tl070wsh30_panel, base);
+}
+
+static int tdo_tl070wsh30_panel_prepare(struct drm_panel *panel)
+{
+ struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
+ int err;
+
+ if (tdo_tl070wsh30->prepared)
+ return 0;
+
+ err = regulator_enable(tdo_tl070wsh30->supply);
+ if (err < 0)
+ return err;
+
+ usleep_range(10000, 11000);
+
+ gpiod_set_value_cansleep(tdo_tl070wsh30->reset_gpio, 1);
+
+ usleep_range(10000, 11000);
+
+ gpiod_set_value_cansleep(tdo_tl070wsh30->reset_gpio, 0);
+
+ msleep(200);
+
+ err = mipi_dsi_dcs_exit_sleep_mode(tdo_tl070wsh30->link);
+ if (err < 0) {
+ dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
+ regulator_disable(tdo_tl070wsh30->supply);
+ return err;
+ }
+
+ msleep(200);
+
+ err = mipi_dsi_dcs_set_display_on(tdo_tl070wsh30->link);
+ if (err < 0) {
+ dev_err(panel->dev, "failed to set display on: %d\n", err);
+ regulator_disable(tdo_tl070wsh30->supply);
+ return err;
+ }
+
+ msleep(20);
+
+ tdo_tl070wsh30->prepared = true;
+
+ return 0;
+}
+
+static int tdo_tl070wsh30_panel_unprepare(struct drm_panel *panel)
+{
+ struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = to_tdo_tl070wsh30_panel(panel);
+ int err;
+
+ if (!tdo_tl070wsh30->prepared)
+ return 0;
+
+ err = mipi_dsi_dcs_set_display_off(tdo_tl070wsh30->link);
+ if (err < 0)
+ dev_err(panel->dev, "failed to set display off: %d\n", err);
+
+ usleep_range(10000, 11000);
+
+ err = mipi_dsi_dcs_enter_sleep_mode(tdo_tl070wsh30->link);
+ if (err < 0) {
+ dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
+ return err;
+ }
+
+ usleep_range(10000, 11000);
+
+ regulator_disable(tdo_tl070wsh30->supply);
+
+ tdo_tl070wsh30->prepared = false;
+
+ return 0;
+}
+
+static const struct drm_display_mode default_mode = {
+ .clock = 47250,
+ .hdisplay = 1024,
+ .hsync_start = 1024 + 46,
+ .hsync_end = 1024 + 46 + 80,
+ .htotal = 1024 + 46 + 80 + 100,
+ .vdisplay = 600,
+ .vsync_start = 600 + 5,
+ .vsync_end = 600 + 5 + 5,
+ .vtotal = 600 + 5 + 5 + 20,
+ .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+};
+
+static int tdo_tl070wsh30_panel_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, &default_mode);
+ if (!mode) {
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ default_mode.hdisplay, default_mode.vdisplay,
+ drm_mode_vrefresh(&default_mode));
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ drm_mode_probed_add(connector, mode);
+
+ connector->display_info.width_mm = 154;
+ connector->display_info.height_mm = 85;
+ connector->display_info.bpc = 8;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs tdo_tl070wsh30_panel_funcs = {
+ .unprepare = tdo_tl070wsh30_panel_unprepare,
+ .prepare = tdo_tl070wsh30_panel_prepare,
+ .get_modes = tdo_tl070wsh30_panel_get_modes,
+};
+
+static const struct of_device_id tdo_tl070wsh30_of_match[] = {
+ { .compatible = "tdo,tl070wsh30", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tdo_tl070wsh30_of_match);
+
+static int tdo_tl070wsh30_panel_add(struct tdo_tl070wsh30_panel *tdo_tl070wsh30)
+{
+ struct device *dev = &tdo_tl070wsh30->link->dev;
+ int err;
+
+ tdo_tl070wsh30->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(tdo_tl070wsh30->supply))
+ return PTR_ERR(tdo_tl070wsh30->supply);
+
+ tdo_tl070wsh30->reset_gpio = devm_gpiod_get(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(tdo_tl070wsh30->reset_gpio)) {
+ err = PTR_ERR(tdo_tl070wsh30->reset_gpio);
+ dev_dbg(dev, "failed to get reset gpio: %d\n", err);
+ return err;
+ }
+
+ drm_panel_init(&tdo_tl070wsh30->base, &tdo_tl070wsh30->link->dev,
+ &tdo_tl070wsh30_panel_funcs, DRM_MODE_CONNECTOR_DSI);
+
+ err = drm_panel_of_backlight(&tdo_tl070wsh30->base);
+ if (err)
+ return err;
+
+ drm_panel_add(&tdo_tl070wsh30->base);
+
+ return 0;
+}
+
+static int tdo_tl070wsh30_panel_probe(struct mipi_dsi_device *dsi)
+{
+ struct tdo_tl070wsh30_panel *tdo_tl070wsh30;
+ int err;
+
+ dsi->lanes = 4;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM;
+
+ tdo_tl070wsh30 = devm_kzalloc(&dsi->dev, sizeof(*tdo_tl070wsh30),
+ GFP_KERNEL);
+ if (!tdo_tl070wsh30)
+ return -ENOMEM;
+
+ mipi_dsi_set_drvdata(dsi, tdo_tl070wsh30);
+ tdo_tl070wsh30->link = dsi;
+
+ err = tdo_tl070wsh30_panel_add(tdo_tl070wsh30);
+ if (err < 0)
+ return err;
+
+ return mipi_dsi_attach(dsi);
+}
+
+static int tdo_tl070wsh30_panel_remove(struct mipi_dsi_device *dsi)
+{
+ struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = mipi_dsi_get_drvdata(dsi);
+ int err;
+
+ err = mipi_dsi_detach(dsi);
+ if (err < 0)
+ dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
+
+ drm_panel_remove(&tdo_tl070wsh30->base);
+ drm_panel_disable(&tdo_tl070wsh30->base);
+ drm_panel_unprepare(&tdo_tl070wsh30->base);
+
+ return 0;
+}
+
+static void tdo_tl070wsh30_panel_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct tdo_tl070wsh30_panel *tdo_tl070wsh30 = mipi_dsi_get_drvdata(dsi);
+
+ drm_panel_disable(&tdo_tl070wsh30->base);
+ drm_panel_unprepare(&tdo_tl070wsh30->base);
+}
+
+static struct mipi_dsi_driver tdo_tl070wsh30_panel_driver = {
+ .driver = {
+ .name = "panel-tdo-tl070wsh30",
+ .of_match_table = tdo_tl070wsh30_of_match,
+ },
+ .probe = tdo_tl070wsh30_panel_probe,
+ .remove = tdo_tl070wsh30_panel_remove,
+ .shutdown = tdo_tl070wsh30_panel_shutdown,
+};
+module_mipi_dsi_driver(tdo_tl070wsh30_panel_driver);
+
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION("TDO TL070WSH30 panel driver");
+MODULE_LICENSE("GPL v2");