mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 15:11:31 +00:00
drm/panel: Changes for v4.5-rc1
This set of changes brings in a few more helpers for DSI support as well as a couple of new drivers and support for some more simple panels. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJWcZxDAAoJEN0jrNd/PrOhuWkP/0VX9HrqF0R3eGB4Vk7I2O1Q ftM7LNnLkN9fhs2D+uL3mkNyMEdYwCVuwkPM3dfWLDZ17Y1MQgqmdRCUwavzjxTx ZHATjCPry2sB/0A8a4HiRd7tmexJGSuxU4TKZgBMykdcdtK3Pxu4X3RyLeiirPsm /8XU/WmEnWnmNuyXWtgGDokiu/QW6kcjZrcHVVMklvdl6kNgSB60HoaH56z7+g51 y4ixFHvdj4ijBNf5wB6Gd8CVQY/2yLNq5GVuh4H0KYL7LapzB2VNFJDp5jxM3KCA 63hPBa9y2Yews0jdRK+BQCVerVzWG92cwm/3sKdUfABHULLdZ+qBwfKON/Obm3pQ a1QNFr+2KVTRT1BfVv5qoLNzC0xUa55tFeduFOssZI1DhQClrsWkkzPxs3TDrAYf 6fo3pSYSlvb3P1vAcVcA15NlwoCGAV0QDIIFPL+uZPwObcCVuWWGGvfYT2hrrD+u Gh1L3Mw2+tvMm1xx3U38ABs5ZiFwnogZKOY0g3AWR0n0HP0Hs/znWtUE8wyfpMf4 fVKrU+4vxYAYsY40jTrmOzT3Pt6b5lfIBvdpeqb8lFuWpsMzslc9p2mkXpIBkn3K VbY8Z0e6F0LySThG0iLykxaeMklEIfe9eybkCQGV5sWrIIQ2+falKAZvu5Ho9zzh ioGnJn/05KVIfKd6w2E8 =vV7Q -----END PGP SIGNATURE----- Merge tag 'drm/panel/for-4.5-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next drm/panel: Changes for v4.5-rc1 This set of changes brings in a few more helpers for DSI support as well as a couple of new drivers and support for some more simple panels. * tag 'drm/panel/for-4.5-rc1' of git://anongit.freedesktop.org/tegra/linux: drm/panel: simple: Add QiaoDian qd43003c0-40 of: Add vendor prefix for QiaoDian Xianshi drm/panel: add kernel doc for size attributes in panel_desc drm/panel: simple: Add support for Kyocera TCG121XGLP panel devicetree: add vendor prefix for Kyocera Corporation drm/bridge: Remove gratuitous blank line drm/bridge: dw-hdmi: Use dashes in filenames drm/panel: Add Sharp LS043T1LE01 MIPI DSI panel dt-bindings: Add Sharp LS043T1LE01 panel binding drm/dsi: Add Turn On/Shutdown Peripheral command helpers drm/panel: Add Panasonic VVX10F034N00 MIPI DSI panel dt-bindings: Add Panasonic VVX10F034N00 panel binding drm/panel: simple: Add support for Innolux G121X1-L03 drm/panel: simple: Add support for BOE TV080WUM-NL0 dt-bindings: Add BOE TV080WUM-NL0 panel binding of: Add vendor prefix for BOE Technology Group drm/dsi: Add a helper to get bits per pixel of MIPI DSI pixel format
This commit is contained in:
commit
07ade84461
@ -0,0 +1,7 @@
|
|||||||
|
Boe Corporation 8.0" WUXGA TFT LCD panel
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "boe,tv080wum-nl0"
|
||||||
|
|
||||||
|
This binding is compatible with the simple-panel binding, which is specified
|
||||||
|
in simple-panel.txt in this directory.
|
@ -0,0 +1,7 @@
|
|||||||
|
Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "innolux,g121x1-l03"
|
||||||
|
|
||||||
|
This binding is compatible with the simple-panel binding, which is specified
|
||||||
|
in simple-panel.txt in this directory.
|
@ -0,0 +1,7 @@
|
|||||||
|
Kyocera Corporation 12.1" XGA (1024x768) TFT LCD panel
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "kyo,tcg121xglp"
|
||||||
|
|
||||||
|
This binding is compatible with the simple-panel binding, which is specified
|
||||||
|
in simple-panel.txt in this directory.
|
@ -0,0 +1,22 @@
|
|||||||
|
Sharp Microelectronics 4.3" qHD TFT LCD panel
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "sharp,ls043t1le01-qhd"
|
||||||
|
- reg: DSI virtual channel of the peripheral
|
||||||
|
- power-supply: phandle of the regulator that provides the supply voltage
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- backlight: phandle of the backlight device attached to the panel
|
||||||
|
- reset-gpios: a GPIO spec for the reset pin
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
mdss_dsi@fd922800 {
|
||||||
|
panel@0 {
|
||||||
|
compatible = "sharp,ls043t1le01-qhd";
|
||||||
|
reg = <0>;
|
||||||
|
avdd-supply = <&pm8941_l22>;
|
||||||
|
backlight = <&pm8941_wled>;
|
||||||
|
reset-gpios = <&pm8941_gpios 19 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,20 @@
|
|||||||
|
Panasonic 10" WUXGA TFT LCD panel
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "panasonic,vvx10f034n00"
|
||||||
|
- reg: DSI virtual channel of the peripheral
|
||||||
|
- power-supply: phandle of the regulator that provides the supply voltage
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- backlight: phandle of the backlight device attached to the panel
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
mdss_dsi@fd922800 {
|
||||||
|
panel@0 {
|
||||||
|
compatible = "panasonic,vvx10f034n00";
|
||||||
|
reg = <0>;
|
||||||
|
power-supply = <&vreg_vsp>;
|
||||||
|
backlight = <&lp8566_wled>;
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,7 @@
|
|||||||
|
QiaoDian XianShi Corporation 4"3 TFT LCD panel
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "qiaodian,qd43003c0-40"
|
||||||
|
|
||||||
|
This binding is compatible with the simple-panel binding, which is specified
|
||||||
|
in simple-panel.txt in this directory.
|
@ -33,6 +33,7 @@ auo AU Optronics Corporation
|
|||||||
avago Avago Technologies
|
avago Avago Technologies
|
||||||
avic Shanghai AVIC Optoelectronics Co., Ltd.
|
avic Shanghai AVIC Optoelectronics Co., Ltd.
|
||||||
axis Axis Communications AB
|
axis Axis Communications AB
|
||||||
|
boe BOE Technology Group Co., Ltd.
|
||||||
bosch Bosch Sensortec GmbH
|
bosch Bosch Sensortec GmbH
|
||||||
boundary Boundary Devices Inc.
|
boundary Boundary Devices Inc.
|
||||||
brcm Broadcom Corporation
|
brcm Broadcom Corporation
|
||||||
@ -123,6 +124,7 @@ jedec JEDEC Solid State Technology Association
|
|||||||
karo Ka-Ro electronics GmbH
|
karo Ka-Ro electronics GmbH
|
||||||
keymile Keymile GmbH
|
keymile Keymile GmbH
|
||||||
kinetic Kinetic Technologies
|
kinetic Kinetic Technologies
|
||||||
|
kyo Kyocera Corporation
|
||||||
lacie LaCie
|
lacie LaCie
|
||||||
lantiq Lantiq Semiconductor
|
lantiq Lantiq Semiconductor
|
||||||
lenovo Lenovo Group Ltd.
|
lenovo Lenovo Group Ltd.
|
||||||
@ -180,6 +182,7 @@ qca Qualcomm Atheros, Inc.
|
|||||||
qcom Qualcomm Technologies, Inc
|
qcom Qualcomm Technologies, Inc
|
||||||
qemu QEMU, a generic and open source machine emulator and virtualizer
|
qemu QEMU, a generic and open source machine emulator and virtualizer
|
||||||
qi Qi Hardware
|
qi Qi Hardware
|
||||||
|
qiaodian QiaoDian XianShi Corporation
|
||||||
qnap QNAP Systems, Inc.
|
qnap QNAP Systems, Inc.
|
||||||
radxa Radxa
|
radxa Radxa
|
||||||
raidsonic RaidSonic Technology GmbH
|
raidsonic RaidSonic Technology GmbH
|
||||||
|
@ -22,7 +22,6 @@ config DRM_DW_HDMI_AHB_AUDIO
|
|||||||
Designware HDMI block. This is used in conjunction with
|
Designware HDMI block. This is used in conjunction with
|
||||||
the i.MX6 HDMI driver.
|
the i.MX6 HDMI driver.
|
||||||
|
|
||||||
|
|
||||||
config DRM_NXP_PTN3460
|
config DRM_NXP_PTN3460
|
||||||
tristate "NXP PTN3460 DP/LVDS bridge"
|
tristate "NXP PTN3460 DP/LVDS bridge"
|
||||||
depends on OF
|
depends on OF
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
ccflags-y := -Iinclude/drm
|
ccflags-y := -Iinclude/drm
|
||||||
|
|
||||||
obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
|
obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
|
||||||
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw_hdmi-ahb-audio.o
|
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
|
||||||
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
|
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
|
||||||
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
|
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#include <sound/pcm_drm_eld.h>
|
#include <sound/pcm_drm_eld.h>
|
||||||
#include <sound/pcm_iec958.h>
|
#include <sound/pcm_iec958.h>
|
||||||
|
|
||||||
#include "dw_hdmi-audio.h"
|
#include "dw-hdmi-audio.h"
|
||||||
|
|
||||||
#define DRIVER_NAME "dw-hdmi-ahb-audio"
|
#define DRIVER_NAME "dw-hdmi-ahb-audio"
|
||||||
|
|
@ -27,8 +27,8 @@
|
|||||||
#include <drm/drm_encoder_slave.h>
|
#include <drm/drm_encoder_slave.h>
|
||||||
#include <drm/bridge/dw_hdmi.h>
|
#include <drm/bridge/dw_hdmi.h>
|
||||||
|
|
||||||
#include "dw_hdmi.h"
|
#include "dw-hdmi.h"
|
||||||
#include "dw_hdmi-audio.h"
|
#include "dw-hdmi-audio.h"
|
||||||
|
|
||||||
#define HDMI_EDID_LEN 512
|
#define HDMI_EDID_LEN 512
|
||||||
|
|
@ -365,6 +365,44 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mipi_dsi_create_packet);
|
EXPORT_SYMBOL(mipi_dsi_create_packet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command
|
||||||
|
* @dsi: DSI peripheral device
|
||||||
|
*
|
||||||
|
* Return: 0 on success or a negative error code on failure.
|
||||||
|
*/
|
||||||
|
int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_msg msg = {
|
||||||
|
.channel = dsi->channel,
|
||||||
|
.type = MIPI_DSI_SHUTDOWN_PERIPHERAL,
|
||||||
|
.tx_buf = (u8 [2]) { 0, 0 },
|
||||||
|
.tx_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
return mipi_dsi_device_transfer(dsi, &msg);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mipi_dsi_shutdown_peripheral);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command
|
||||||
|
* @dsi: DSI peripheral device
|
||||||
|
*
|
||||||
|
* Return: 0 on success or a negative error code on failure.
|
||||||
|
*/
|
||||||
|
int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_msg msg = {
|
||||||
|
.channel = dsi->channel,
|
||||||
|
.type = MIPI_DSI_TURN_ON_PERIPHERAL,
|
||||||
|
.tx_buf = (u8 [2]) { 0, 0 },
|
||||||
|
.tx_len = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
return mipi_dsi_device_transfer(dsi, &msg);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mipi_dsi_turn_on_peripheral);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the
|
* mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the
|
||||||
* the payload in a long packet transmitted from the peripheral back to the
|
* the payload in a long packet transmitted from the peripheral back to the
|
||||||
|
@ -31,6 +31,16 @@ config DRM_PANEL_LG_LG4573
|
|||||||
Say Y here if you want to enable support for LG4573 RGB panel.
|
Say Y here if you want to enable support for LG4573 RGB panel.
|
||||||
To compile this driver as a module, choose M here.
|
To compile this driver as a module, choose M here.
|
||||||
|
|
||||||
|
config DRM_PANEL_PANASONIC_VVX10F034N00
|
||||||
|
tristate "Panasonic VVX10F034N00 1920x1200 video mode panel"
|
||||||
|
depends on OF
|
||||||
|
depends on DRM_MIPI_DSI
|
||||||
|
depends on BACKLIGHT_CLASS_DEVICE
|
||||||
|
help
|
||||||
|
Say Y here if you want to enable support for Panasonic VVX10F034N00
|
||||||
|
WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some
|
||||||
|
Xperia Z2 tablets
|
||||||
|
|
||||||
config DRM_PANEL_SAMSUNG_S6E8AA0
|
config DRM_PANEL_SAMSUNG_S6E8AA0
|
||||||
tristate "Samsung S6E8AA0 DSI video mode panel"
|
tristate "Samsung S6E8AA0 DSI video mode panel"
|
||||||
depends on OF
|
depends on OF
|
||||||
@ -51,4 +61,13 @@ config DRM_PANEL_SHARP_LQ101R1SX01
|
|||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called panel-sharp-lq101r1sx01.
|
will be called panel-sharp-lq101r1sx01.
|
||||||
|
|
||||||
|
config DRM_PANEL_SHARP_LS043T1LE01
|
||||||
|
tristate "Sharp LS043T1LE01 qHD video mode panel"
|
||||||
|
depends on OF
|
||||||
|
depends on DRM_MIPI_DSI
|
||||||
|
depends on BACKLIGHT_CLASS_DEVICE
|
||||||
|
help
|
||||||
|
Say Y here if you want to enable support for Sharp LS043T1LE01 qHD
|
||||||
|
(540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
|
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
|
||||||
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
|
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
|
||||||
|
obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o
|
||||||
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
|
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
|
||||||
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
|
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
|
||||||
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
|
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
|
||||||
|
obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
|
||||||
|
334
drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
Normal file
334
drivers/gpu/drm/panel/panel-panasonic-vvx10f034n00.c
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Red Hat
|
||||||
|
* Copyright (C) 2015 Sony Mobile Communications Inc.
|
||||||
|
* Author: Werner Johansson <werner.johansson@sonymobile.com>
|
||||||
|
*
|
||||||
|
* Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published by
|
||||||
|
* the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/backlight.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
|
#include <drm/drmP.h>
|
||||||
|
#include <drm/drm_crtc.h>
|
||||||
|
#include <drm/drm_mipi_dsi.h>
|
||||||
|
#include <drm/drm_panel.h>
|
||||||
|
|
||||||
|
#include <video/mipi_display.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When power is turned off to this panel a minimum off time of 500ms has to be
|
||||||
|
* observed before powering back on as there's no external reset pin. Keep
|
||||||
|
* track of earliest wakeup time and delay subsequent prepare call accordingly
|
||||||
|
*/
|
||||||
|
#define MIN_POFF_MS (500)
|
||||||
|
|
||||||
|
struct wuxga_nt_panel {
|
||||||
|
struct drm_panel base;
|
||||||
|
struct mipi_dsi_device *dsi;
|
||||||
|
|
||||||
|
struct backlight_device *backlight;
|
||||||
|
struct regulator *supply;
|
||||||
|
|
||||||
|
bool prepared;
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
|
ktime_t earliest_wake;
|
||||||
|
|
||||||
|
const struct drm_display_mode *mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct wuxga_nt_panel *to_wuxga_nt_panel(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
return container_of(panel, struct wuxga_nt_panel, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_on(struct wuxga_nt_panel *wuxga_nt)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_device *dsi = wuxga_nt->dsi;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = mipi_dsi_turn_on_peripheral(dsi);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_disable(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
|
||||||
|
|
||||||
|
if (!wuxga_nt->enabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mipi_dsi_shutdown_peripheral(wuxga_nt->dsi);
|
||||||
|
|
||||||
|
if (wuxga_nt->backlight) {
|
||||||
|
wuxga_nt->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||||
|
wuxga_nt->backlight->props.state |= BL_CORE_FBBLANK;
|
||||||
|
backlight_update_status(wuxga_nt->backlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
wuxga_nt->enabled = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_unprepare(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
|
||||||
|
|
||||||
|
if (!wuxga_nt->prepared)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
regulator_disable(wuxga_nt->supply);
|
||||||
|
wuxga_nt->earliest_wake = ktime_add_ms(ktime_get_real(), MIN_POFF_MS);
|
||||||
|
wuxga_nt->prepared = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_prepare(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
|
||||||
|
int ret;
|
||||||
|
s64 enablewait;
|
||||||
|
|
||||||
|
if (wuxga_nt->prepared)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user re-enabled the panel before the required off-time then
|
||||||
|
* we need to wait the remaining period before re-enabling regulator
|
||||||
|
*/
|
||||||
|
enablewait = ktime_ms_delta(wuxga_nt->earliest_wake, ktime_get_real());
|
||||||
|
|
||||||
|
/* Sanity check, this should never happen */
|
||||||
|
if (enablewait > MIN_POFF_MS)
|
||||||
|
enablewait = MIN_POFF_MS;
|
||||||
|
|
||||||
|
if (enablewait > 0)
|
||||||
|
msleep(enablewait);
|
||||||
|
|
||||||
|
ret = regulator_enable(wuxga_nt->supply);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A minimum delay of 250ms is required after power-up until commands
|
||||||
|
* can be sent
|
||||||
|
*/
|
||||||
|
msleep(250);
|
||||||
|
|
||||||
|
ret = wuxga_nt_panel_on(wuxga_nt);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(panel->dev, "failed to set panel on: %d\n", ret);
|
||||||
|
goto poweroff;
|
||||||
|
}
|
||||||
|
|
||||||
|
wuxga_nt->prepared = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
poweroff:
|
||||||
|
regulator_disable(wuxga_nt->supply);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_enable(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct wuxga_nt_panel *wuxga_nt = to_wuxga_nt_panel(panel);
|
||||||
|
|
||||||
|
if (wuxga_nt->enabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (wuxga_nt->backlight) {
|
||||||
|
wuxga_nt->backlight->props.power = FB_BLANK_UNBLANK;
|
||||||
|
wuxga_nt->backlight->props.state &= ~BL_CORE_FBBLANK;
|
||||||
|
backlight_update_status(wuxga_nt->backlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
wuxga_nt->enabled = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_display_mode default_mode = {
|
||||||
|
.clock = 164402,
|
||||||
|
.hdisplay = 1920,
|
||||||
|
.hsync_start = 1920 + 152,
|
||||||
|
.hsync_end = 1920 + 152 + 52,
|
||||||
|
.htotal = 1920 + 152 + 52 + 20,
|
||||||
|
.vdisplay = 1200,
|
||||||
|
.vsync_start = 1200 + 24,
|
||||||
|
.vsync_end = 1200 + 24 + 6,
|
||||||
|
.vtotal = 1200 + 24 + 6 + 48,
|
||||||
|
.vrefresh = 60,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_get_modes(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct drm_display_mode *mode;
|
||||||
|
|
||||||
|
mode = drm_mode_duplicate(panel->drm, &default_mode);
|
||||||
|
if (!mode) {
|
||||||
|
dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
|
||||||
|
default_mode.hdisplay, default_mode.vdisplay,
|
||||||
|
default_mode.vrefresh);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_mode_set_name(mode);
|
||||||
|
|
||||||
|
drm_mode_probed_add(panel->connector, mode);
|
||||||
|
|
||||||
|
panel->connector->display_info.width_mm = 217;
|
||||||
|
panel->connector->display_info.height_mm = 136;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_panel_funcs wuxga_nt_panel_funcs = {
|
||||||
|
.disable = wuxga_nt_panel_disable,
|
||||||
|
.unprepare = wuxga_nt_panel_unprepare,
|
||||||
|
.prepare = wuxga_nt_panel_prepare,
|
||||||
|
.enable = wuxga_nt_panel_enable,
|
||||||
|
.get_modes = wuxga_nt_panel_get_modes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id wuxga_nt_of_match[] = {
|
||||||
|
{ .compatible = "panasonic,vvx10f034n00", },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, wuxga_nt_of_match);
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_add(struct wuxga_nt_panel *wuxga_nt)
|
||||||
|
{
|
||||||
|
struct device *dev = &wuxga_nt->dsi->dev;
|
||||||
|
struct device_node *np;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
wuxga_nt->mode = &default_mode;
|
||||||
|
|
||||||
|
wuxga_nt->supply = devm_regulator_get(dev, "power");
|
||||||
|
if (IS_ERR(wuxga_nt->supply))
|
||||||
|
return PTR_ERR(wuxga_nt->supply);
|
||||||
|
|
||||||
|
np = of_parse_phandle(dev->of_node, "backlight", 0);
|
||||||
|
if (np) {
|
||||||
|
wuxga_nt->backlight = of_find_backlight_by_node(np);
|
||||||
|
of_node_put(np);
|
||||||
|
|
||||||
|
if (!wuxga_nt->backlight)
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_panel_init(&wuxga_nt->base);
|
||||||
|
wuxga_nt->base.funcs = &wuxga_nt_panel_funcs;
|
||||||
|
wuxga_nt->base.dev = &wuxga_nt->dsi->dev;
|
||||||
|
|
||||||
|
ret = drm_panel_add(&wuxga_nt->base);
|
||||||
|
if (ret < 0)
|
||||||
|
goto put_backlight;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
put_backlight:
|
||||||
|
if (wuxga_nt->backlight)
|
||||||
|
put_device(&wuxga_nt->backlight->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wuxga_nt_panel_del(struct wuxga_nt_panel *wuxga_nt)
|
||||||
|
{
|
||||||
|
if (wuxga_nt->base.dev)
|
||||||
|
drm_panel_remove(&wuxga_nt->base);
|
||||||
|
|
||||||
|
if (wuxga_nt->backlight)
|
||||||
|
put_device(&wuxga_nt->backlight->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_probe(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct wuxga_nt_panel *wuxga_nt;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dsi->lanes = 4;
|
||||||
|
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||||
|
dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
|
||||||
|
MIPI_DSI_MODE_VIDEO_HSE |
|
||||||
|
MIPI_DSI_CLOCK_NON_CONTINUOUS |
|
||||||
|
MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
wuxga_nt = devm_kzalloc(&dsi->dev, sizeof(*wuxga_nt), GFP_KERNEL);
|
||||||
|
if (!wuxga_nt)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mipi_dsi_set_drvdata(dsi, wuxga_nt);
|
||||||
|
|
||||||
|
wuxga_nt->dsi = dsi;
|
||||||
|
|
||||||
|
ret = wuxga_nt_panel_add(wuxga_nt);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return mipi_dsi_attach(dsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wuxga_nt_panel_remove(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = wuxga_nt_panel_disable(&wuxga_nt->base);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
|
||||||
|
|
||||||
|
ret = mipi_dsi_detach(dsi);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
|
||||||
|
|
||||||
|
drm_panel_detach(&wuxga_nt->base);
|
||||||
|
wuxga_nt_panel_del(wuxga_nt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wuxga_nt_panel_shutdown(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct wuxga_nt_panel *wuxga_nt = mipi_dsi_get_drvdata(dsi);
|
||||||
|
|
||||||
|
wuxga_nt_panel_disable(&wuxga_nt->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mipi_dsi_driver wuxga_nt_panel_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "panel-panasonic-vvx10f034n00",
|
||||||
|
.of_match_table = wuxga_nt_of_match,
|
||||||
|
},
|
||||||
|
.probe = wuxga_nt_panel_probe,
|
||||||
|
.remove = wuxga_nt_panel_remove,
|
||||||
|
.shutdown = wuxga_nt_panel_shutdown,
|
||||||
|
};
|
||||||
|
module_mipi_dsi_driver(wuxga_nt_panel_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
|
||||||
|
MODULE_DESCRIPTION("Panasonic VVX10F034N00 Novatek NT1397-based WUXGA (1920x1200) video mode panel driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
387
drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
Normal file
387
drivers/gpu/drm/panel/panel-sharp-ls043t1le01.c
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Red Hat
|
||||||
|
* Copyright (C) 2015 Sony Mobile Communications Inc.
|
||||||
|
* Author: Werner Johansson <werner.johansson@sonymobile.com>
|
||||||
|
*
|
||||||
|
* Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published by
|
||||||
|
* the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/backlight.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
|
#include <drm/drmP.h>
|
||||||
|
#include <drm/drm_crtc.h>
|
||||||
|
#include <drm/drm_mipi_dsi.h>
|
||||||
|
#include <drm/drm_panel.h>
|
||||||
|
|
||||||
|
#include <video/mipi_display.h>
|
||||||
|
|
||||||
|
struct sharp_nt_panel {
|
||||||
|
struct drm_panel base;
|
||||||
|
struct mipi_dsi_device *dsi;
|
||||||
|
|
||||||
|
struct backlight_device *backlight;
|
||||||
|
struct regulator *supply;
|
||||||
|
struct gpio_desc *reset_gpio;
|
||||||
|
|
||||||
|
bool prepared;
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
|
const struct drm_display_mode *mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
return container_of(panel, struct sharp_nt_panel, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_device *dsi = sharp_nt->dsi;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
msleep(120);
|
||||||
|
|
||||||
|
/* Novatek two-lane operation */
|
||||||
|
ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Set both MCU and RGB I/F to 24bpp */
|
||||||
|
ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
|
||||||
|
(MIPI_DCS_PIXEL_FMT_24BIT << 4));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_device *dsi = sharp_nt->dsi;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
ret = mipi_dsi_dcs_set_display_on(dsi);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt)
|
||||||
|
{
|
||||||
|
struct mipi_dsi_device *dsi = sharp_nt->dsi;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||||
|
|
||||||
|
ret = mipi_dsi_dcs_set_display_off(dsi);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int sharp_nt_panel_disable(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
|
||||||
|
|
||||||
|
if (!sharp_nt->enabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sharp_nt->backlight) {
|
||||||
|
sharp_nt->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||||
|
backlight_update_status(sharp_nt->backlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
sharp_nt->enabled = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sharp_nt_panel_unprepare(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!sharp_nt->prepared)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = sharp_nt_panel_off(sharp_nt);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(panel->dev, "failed to set panel off: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
regulator_disable(sharp_nt->supply);
|
||||||
|
if (sharp_nt->reset_gpio)
|
||||||
|
gpiod_set_value(sharp_nt->reset_gpio, 0);
|
||||||
|
|
||||||
|
sharp_nt->prepared = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sharp_nt_panel_prepare(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (sharp_nt->prepared)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = regulator_enable(sharp_nt->supply);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
msleep(20);
|
||||||
|
|
||||||
|
if (sharp_nt->reset_gpio) {
|
||||||
|
gpiod_set_value(sharp_nt->reset_gpio, 1);
|
||||||
|
msleep(1);
|
||||||
|
gpiod_set_value(sharp_nt->reset_gpio, 0);
|
||||||
|
msleep(1);
|
||||||
|
gpiod_set_value(sharp_nt->reset_gpio, 1);
|
||||||
|
msleep(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sharp_nt_panel_init(sharp_nt);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(panel->dev, "failed to init panel: %d\n", ret);
|
||||||
|
goto poweroff;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sharp_nt_panel_on(sharp_nt);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(panel->dev, "failed to set panel on: %d\n", ret);
|
||||||
|
goto poweroff;
|
||||||
|
}
|
||||||
|
|
||||||
|
sharp_nt->prepared = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
poweroff:
|
||||||
|
regulator_disable(sharp_nt->supply);
|
||||||
|
if (sharp_nt->reset_gpio)
|
||||||
|
gpiod_set_value(sharp_nt->reset_gpio, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sharp_nt_panel_enable(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
|
||||||
|
|
||||||
|
if (sharp_nt->enabled)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sharp_nt->backlight) {
|
||||||
|
sharp_nt->backlight->props.power = FB_BLANK_UNBLANK;
|
||||||
|
backlight_update_status(sharp_nt->backlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
sharp_nt->enabled = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_display_mode default_mode = {
|
||||||
|
.clock = 41118,
|
||||||
|
.hdisplay = 540,
|
||||||
|
.hsync_start = 540 + 48,
|
||||||
|
.hsync_end = 540 + 48 + 80,
|
||||||
|
.htotal = 540 + 48 + 80 + 32,
|
||||||
|
.vdisplay = 960,
|
||||||
|
.vsync_start = 960 + 3,
|
||||||
|
.vsync_end = 960 + 3 + 15,
|
||||||
|
.vtotal = 960 + 3 + 15 + 1,
|
||||||
|
.vrefresh = 60,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sharp_nt_panel_get_modes(struct drm_panel *panel)
|
||||||
|
{
|
||||||
|
struct drm_display_mode *mode;
|
||||||
|
|
||||||
|
mode = drm_mode_duplicate(panel->drm, &default_mode);
|
||||||
|
if (!mode) {
|
||||||
|
dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
|
||||||
|
default_mode.hdisplay, default_mode.vdisplay,
|
||||||
|
default_mode.vrefresh);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_mode_set_name(mode);
|
||||||
|
|
||||||
|
drm_mode_probed_add(panel->connector, mode);
|
||||||
|
|
||||||
|
panel->connector->display_info.width_mm = 54;
|
||||||
|
panel->connector->display_info.height_mm = 95;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct drm_panel_funcs sharp_nt_panel_funcs = {
|
||||||
|
.disable = sharp_nt_panel_disable,
|
||||||
|
.unprepare = sharp_nt_panel_unprepare,
|
||||||
|
.prepare = sharp_nt_panel_prepare,
|
||||||
|
.enable = sharp_nt_panel_enable,
|
||||||
|
.get_modes = sharp_nt_panel_get_modes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
|
||||||
|
{
|
||||||
|
struct device *dev = &sharp_nt->dsi->dev;
|
||||||
|
struct device_node *np;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
sharp_nt->mode = &default_mode;
|
||||||
|
|
||||||
|
sharp_nt->supply = devm_regulator_get(dev, "avdd");
|
||||||
|
if (IS_ERR(sharp_nt->supply))
|
||||||
|
return PTR_ERR(sharp_nt->supply);
|
||||||
|
|
||||||
|
sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(sharp_nt->reset_gpio)) {
|
||||||
|
dev_err(dev, "cannot get reset-gpios %ld\n",
|
||||||
|
PTR_ERR(sharp_nt->reset_gpio));
|
||||||
|
sharp_nt->reset_gpio = NULL;
|
||||||
|
} else {
|
||||||
|
gpiod_set_value(sharp_nt->reset_gpio, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
np = of_parse_phandle(dev->of_node, "backlight", 0);
|
||||||
|
if (np) {
|
||||||
|
sharp_nt->backlight = of_find_backlight_by_node(np);
|
||||||
|
of_node_put(np);
|
||||||
|
|
||||||
|
if (!sharp_nt->backlight)
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_panel_init(&sharp_nt->base);
|
||||||
|
sharp_nt->base.funcs = &sharp_nt_panel_funcs;
|
||||||
|
sharp_nt->base.dev = &sharp_nt->dsi->dev;
|
||||||
|
|
||||||
|
ret = drm_panel_add(&sharp_nt->base);
|
||||||
|
if (ret < 0)
|
||||||
|
goto put_backlight;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
put_backlight:
|
||||||
|
if (sharp_nt->backlight)
|
||||||
|
put_device(&sharp_nt->backlight->dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
|
||||||
|
{
|
||||||
|
if (sharp_nt->base.dev)
|
||||||
|
drm_panel_remove(&sharp_nt->base);
|
||||||
|
|
||||||
|
if (sharp_nt->backlight)
|
||||||
|
put_device(&sharp_nt->backlight->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct sharp_nt_panel *sharp_nt;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dsi->lanes = 2;
|
||||||
|
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||||
|
dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
|
||||||
|
MIPI_DSI_MODE_VIDEO_HSE |
|
||||||
|
MIPI_DSI_CLOCK_NON_CONTINUOUS |
|
||||||
|
MIPI_DSI_MODE_EOT_PACKET;
|
||||||
|
|
||||||
|
sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL);
|
||||||
|
if (!sharp_nt)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mipi_dsi_set_drvdata(dsi, sharp_nt);
|
||||||
|
|
||||||
|
sharp_nt->dsi = dsi;
|
||||||
|
|
||||||
|
ret = sharp_nt_panel_add(sharp_nt);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return mipi_dsi_attach(dsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = sharp_nt_panel_disable(&sharp_nt->base);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
|
||||||
|
|
||||||
|
ret = mipi_dsi_detach(dsi);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
|
||||||
|
|
||||||
|
drm_panel_detach(&sharp_nt->base);
|
||||||
|
sharp_nt_panel_del(sharp_nt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)
|
||||||
|
{
|
||||||
|
struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
|
||||||
|
|
||||||
|
sharp_nt_panel_disable(&sharp_nt->base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id sharp_nt_of_match[] = {
|
||||||
|
{ .compatible = "sharp,ls043t1le01-qhd", },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, sharp_nt_of_match);
|
||||||
|
|
||||||
|
static struct mipi_dsi_driver sharp_nt_panel_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "panel-sharp-ls043t1le01-qhd",
|
||||||
|
.of_match_table = sharp_nt_of_match,
|
||||||
|
},
|
||||||
|
.probe = sharp_nt_panel_probe,
|
||||||
|
.remove = sharp_nt_panel_remove,
|
||||||
|
.shutdown = sharp_nt_panel_shutdown,
|
||||||
|
};
|
||||||
|
module_mipi_dsi_driver(sharp_nt_panel_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
|
||||||
|
MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -44,6 +44,10 @@ struct panel_desc {
|
|||||||
|
|
||||||
unsigned int bpc;
|
unsigned int bpc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @width: width (in millimeters) of the panel's active display area
|
||||||
|
* @height: height (in millimeters) of the panel's active display area
|
||||||
|
*/
|
||||||
struct {
|
struct {
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
@ -832,6 +836,34 @@ static const struct panel_desc innolux_g121i1_l01 = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct drm_display_mode innolux_g121x1_l03_mode = {
|
||||||
|
.clock = 65000,
|
||||||
|
.hdisplay = 1024,
|
||||||
|
.hsync_start = 1024 + 0,
|
||||||
|
.hsync_end = 1024 + 1,
|
||||||
|
.htotal = 1024 + 0 + 1 + 320,
|
||||||
|
.vdisplay = 768,
|
||||||
|
.vsync_start = 768 + 38,
|
||||||
|
.vsync_end = 768 + 38 + 1,
|
||||||
|
.vtotal = 768 + 38 + 1 + 0,
|
||||||
|
.vrefresh = 60,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct panel_desc innolux_g121x1_l03 = {
|
||||||
|
.modes = &innolux_g121x1_l03_mode,
|
||||||
|
.num_modes = 1,
|
||||||
|
.bpc = 6,
|
||||||
|
.size = {
|
||||||
|
.width = 246,
|
||||||
|
.height = 185,
|
||||||
|
},
|
||||||
|
.delay = {
|
||||||
|
.enable = 200,
|
||||||
|
.unprepare = 200,
|
||||||
|
.disable = 400,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static const struct drm_display_mode innolux_n116bge_mode = {
|
static const struct drm_display_mode innolux_n116bge_mode = {
|
||||||
.clock = 76420,
|
.clock = 76420,
|
||||||
.hdisplay = 1366,
|
.hdisplay = 1366,
|
||||||
@ -902,6 +934,30 @@ static const struct panel_desc innolux_zj070na_01p = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct display_timing kyo_tcg121xglp_timing = {
|
||||||
|
.pixelclock = { 52000000, 65000000, 71000000 },
|
||||||
|
.hactive = { 1024, 1024, 1024 },
|
||||||
|
.hfront_porch = { 2, 2, 2 },
|
||||||
|
.hback_porch = { 2, 2, 2 },
|
||||||
|
.hsync_len = { 86, 124, 244 },
|
||||||
|
.vactive = { 768, 768, 768 },
|
||||||
|
.vfront_porch = { 2, 2, 2 },
|
||||||
|
.vback_porch = { 2, 2, 2 },
|
||||||
|
.vsync_len = { 6, 34, 73 },
|
||||||
|
.flags = DISPLAY_FLAGS_DE_HIGH,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct panel_desc kyo_tcg121xglp = {
|
||||||
|
.timings = &kyo_tcg121xglp_timing,
|
||||||
|
.num_timings = 1,
|
||||||
|
.bpc = 8,
|
||||||
|
.size = {
|
||||||
|
.width = 246,
|
||||||
|
.height = 184,
|
||||||
|
},
|
||||||
|
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct drm_display_mode lg_lb070wv8_mode = {
|
static const struct drm_display_mode lg_lb070wv8_mode = {
|
||||||
.clock = 33246,
|
.clock = 33246,
|
||||||
.hdisplay = 800,
|
.hdisplay = 800,
|
||||||
@ -1027,6 +1083,30 @@ static const struct panel_desc ortustech_com43h4m85ulc = {
|
|||||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct drm_display_mode qd43003c0_40_mode = {
|
||||||
|
.clock = 9000,
|
||||||
|
.hdisplay = 480,
|
||||||
|
.hsync_start = 480 + 8,
|
||||||
|
.hsync_end = 480 + 8 + 4,
|
||||||
|
.htotal = 480 + 8 + 4 + 39,
|
||||||
|
.vdisplay = 272,
|
||||||
|
.vsync_start = 272 + 4,
|
||||||
|
.vsync_end = 272 + 4 + 10,
|
||||||
|
.vtotal = 272 + 4 + 10 + 2,
|
||||||
|
.vrefresh = 60,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct panel_desc qd43003c0_40 = {
|
||||||
|
.modes = &qd43003c0_40_mode,
|
||||||
|
.num_modes = 1,
|
||||||
|
.bpc = 8,
|
||||||
|
.size = {
|
||||||
|
.width = 95,
|
||||||
|
.height = 53,
|
||||||
|
},
|
||||||
|
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct drm_display_mode samsung_ltn101nt05_mode = {
|
static const struct drm_display_mode samsung_ltn101nt05_mode = {
|
||||||
.clock = 54030,
|
.clock = 54030,
|
||||||
.hdisplay = 1024,
|
.hdisplay = 1024,
|
||||||
@ -1157,6 +1237,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||||||
}, {
|
}, {
|
||||||
.compatible ="innolux,g121i1-l01",
|
.compatible ="innolux,g121i1-l01",
|
||||||
.data = &innolux_g121i1_l01
|
.data = &innolux_g121i1_l01
|
||||||
|
}, {
|
||||||
|
.compatible = "innolux,g121x1-l03",
|
||||||
|
.data = &innolux_g121x1_l03,
|
||||||
}, {
|
}, {
|
||||||
.compatible = "innolux,n116bge",
|
.compatible = "innolux,n116bge",
|
||||||
.data = &innolux_n116bge,
|
.data = &innolux_n116bge,
|
||||||
@ -1166,6 +1249,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||||||
}, {
|
}, {
|
||||||
.compatible = "innolux,zj070na-01p",
|
.compatible = "innolux,zj070na-01p",
|
||||||
.data = &innolux_zj070na_01p,
|
.data = &innolux_zj070na_01p,
|
||||||
|
}, {
|
||||||
|
.compatible = "kyo,tcg121xglp",
|
||||||
|
.data = &kyo_tcg121xglp,
|
||||||
}, {
|
}, {
|
||||||
.compatible = "lg,lb070wv8",
|
.compatible = "lg,lb070wv8",
|
||||||
.data = &lg_lb070wv8,
|
.data = &lg_lb070wv8,
|
||||||
@ -1181,6 +1267,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||||||
}, {
|
}, {
|
||||||
.compatible = "ortustech,com43h4m85ulc",
|
.compatible = "ortustech,com43h4m85ulc",
|
||||||
.data = &ortustech_com43h4m85ulc,
|
.data = &ortustech_com43h4m85ulc,
|
||||||
|
}, {
|
||||||
|
.compatible = "qiaodian,qd43003c0-40",
|
||||||
|
.data = &qd43003c0_40,
|
||||||
}, {
|
}, {
|
||||||
.compatible = "samsung,ltn101nt05",
|
.compatible = "samsung,ltn101nt05",
|
||||||
.data = &samsung_ltn101nt05,
|
.data = &samsung_ltn101nt05,
|
||||||
@ -1263,6 +1352,36 @@ static const struct panel_desc_dsi auo_b080uan01 = {
|
|||||||
.lanes = 4,
|
.lanes = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct drm_display_mode boe_tv080wum_nl0_mode = {
|
||||||
|
.clock = 160000,
|
||||||
|
.hdisplay = 1200,
|
||||||
|
.hsync_start = 1200 + 120,
|
||||||
|
.hsync_end = 1200 + 120 + 20,
|
||||||
|
.htotal = 1200 + 120 + 20 + 21,
|
||||||
|
.vdisplay = 1920,
|
||||||
|
.vsync_start = 1920 + 21,
|
||||||
|
.vsync_end = 1920 + 21 + 3,
|
||||||
|
.vtotal = 1920 + 21 + 3 + 18,
|
||||||
|
.vrefresh = 60,
|
||||||
|
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct panel_desc_dsi boe_tv080wum_nl0 = {
|
||||||
|
.desc = {
|
||||||
|
.modes = &boe_tv080wum_nl0_mode,
|
||||||
|
.num_modes = 1,
|
||||||
|
.size = {
|
||||||
|
.width = 107,
|
||||||
|
.height = 172,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.flags = MIPI_DSI_MODE_VIDEO |
|
||||||
|
MIPI_DSI_MODE_VIDEO_BURST |
|
||||||
|
MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
|
||||||
|
.format = MIPI_DSI_FMT_RGB888,
|
||||||
|
.lanes = 4,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
|
static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
|
||||||
.clock = 71000,
|
.clock = 71000,
|
||||||
.hdisplay = 800,
|
.hdisplay = 800,
|
||||||
@ -1348,10 +1467,14 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
|
|||||||
.lanes = 4,
|
.lanes = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const struct of_device_id dsi_of_match[] = {
|
static const struct of_device_id dsi_of_match[] = {
|
||||||
{
|
{
|
||||||
.compatible = "auo,b080uan01",
|
.compatible = "auo,b080uan01",
|
||||||
.data = &auo_b080uan01
|
.data = &auo_b080uan01
|
||||||
|
}, {
|
||||||
|
.compatible = "boe,tv080wum-nl0",
|
||||||
|
.data = &boe_tv080wum_nl0
|
||||||
}, {
|
}, {
|
||||||
.compatible = "lg,ld070wx3-sl01",
|
.compatible = "lg,ld070wx3-sl01",
|
||||||
.data = &lg_ld070wx3_sl01
|
.data = &lg_ld070wx3_sl01
|
||||||
|
@ -163,9 +163,36 @@ static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)
|
|||||||
return container_of(dev, struct mipi_dsi_device, dev);
|
return container_of(dev, struct mipi_dsi_device, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
|
||||||
|
* given pixel format defined by the MIPI DSI
|
||||||
|
* specification
|
||||||
|
* @fmt: MIPI DSI pixel format
|
||||||
|
*
|
||||||
|
* Returns: The number of bits per pixel of the given pixel format.
|
||||||
|
*/
|
||||||
|
static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
|
||||||
|
{
|
||||||
|
switch (fmt) {
|
||||||
|
case MIPI_DSI_FMT_RGB888:
|
||||||
|
case MIPI_DSI_FMT_RGB666:
|
||||||
|
return 24;
|
||||||
|
|
||||||
|
case MIPI_DSI_FMT_RGB666_PACKED:
|
||||||
|
return 18;
|
||||||
|
|
||||||
|
case MIPI_DSI_FMT_RGB565:
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
|
struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
|
||||||
int mipi_dsi_attach(struct mipi_dsi_device *dsi);
|
int mipi_dsi_attach(struct mipi_dsi_device *dsi);
|
||||||
int mipi_dsi_detach(struct mipi_dsi_device *dsi);
|
int mipi_dsi_detach(struct mipi_dsi_device *dsi);
|
||||||
|
int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi);
|
||||||
|
int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
|
||||||
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
|
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
|
||||||
u16 value);
|
u16 value);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user