On Thu, Apr 14, 2016 at 8:10 PM, Archit Taneja architt@codeaurora.org wrote:
On 4/13/2016 11:58 AM, Vinay Simha BN wrote:
Add support for the JDI lt070me05000 WUXGA DSI panel used in Nexus 7 2013 devices.
Programming sequence for the panel is was originally found in the android-msm-flo-3.4-lollipop-release branch from: https://android.googlesource.com/kernel/msm.git
And video mode setting is from dsi-panel-jdi-dualmipi1-video.dtsi file in: git://codeaurora.org/kernel/msm-3.10.git LNX.LA.3.6_rb1.27
Other fixes folded in were provided by Archit Taneja archit.taneja@gmail.com
Signed-off-by: Vinay Simha BN simhavcs@gmail.com [sumit.semwal: Ported to the drm/panel framework] Signed-off-by: Sumit Semwal sumit.semwal@linaro.org [jstultz: Cherry-picked to mainline, folded down other fixes from Vinay and Archit] Signed-off-by: John Stultz john.stultz@linaro.org
.../bindings/display/panel/jdi,lt070me05000.txt | 27 + .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/gpu/drm/panel/Kconfig | 11 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-jdi-lt070me05000.c | 685 +++++++++++++++++++++ 5 files changed, 725 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/jdi,lt070me05000.txt create mode 100644 drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
diff --git a/Documentation/devicetree/bindings/display/panel/jdi,lt070me05000.txt b/Documentation/devicetree/bindings/display/panel/jdi,lt070me05000.txt new file mode 100644 index 0000000..35c5ac7 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/jdi,lt070me05000.txt @@ -0,0 +1,27 @@ +JDI model LT070ME05000 1920x1200 7" DSI Panel
+Basic data sheet is at:
http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet
+This panel has video mode implemented currently in the driver.
+Required properties: +- compatible: should be "jdi,lt070me05000"
+Optional properties: +- power-supply: phandle of the regulator that provides the supply voltage +- reset-gpio: phandle of gpio for reset line +- backlight: phandle of the backlight device attached to the panel
+Example:
dsi@54300000 {
panel: panel@0 {
compatible = "jdi,lt070me05000";
reg = <0>;
power-supply = <...>;
reset-gpio = <...>;
backlight = <...>;
};
};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index a580f3e..ec42bb4 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -130,6 +130,7 @@ invensense InvenSense Inc. isee ISEE 2007 S.L. isil Intersil issi Integrated Silicon Solutions Inc. +jdi Japan Display Inc. jedec JEDEC Solid State Technology Association karo Ka-Ro electronics GmbH keymile Keymile GmbH diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 1500ab9..f41690e 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -61,6 +61,17 @@ config DRM_PANEL_SHARP_LQ101R1SX01 To compile this driver as a module, choose M here: the module will be called panel-sharp-lq101r1sx01.
+config DRM_PANEL_JDI_LT070ME05000
tristate "JDI LT070ME05000 WUXGA DSI 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 JDI WUXGA DSI
video/
command mode panel as found in Google Nexus 7 (2013) devices.
The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses
24 bit RGB per pixel.
- config DRM_PANEL_SHARP_LS043T1LE01 tristate "Sharp LS043T1LE01 qHD video mode panel" depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index f277eed..e6c6fc8 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.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_LS043T1LE01) += panel-sharp-ls043t1le01.o +obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o diff --git a/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c new file mode 100644 index 0000000..051aa1b --- /dev/null +++ b/drivers/gpu/drm/panel/panel-jdi-lt070me05000.c @@ -0,0 +1,685 @@ +/*
- Copyright (C) 2015 InforceComputing
- Author: Vinay Simha BN simhavcs@gmail.com
- Copyright (C) 2015 Linaro Ltd
- Author: Sumit Semwal sumit.semwal@linaro.org
- 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>
+/*
- From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a
- JDI model LT070ME05000, and its data sheet is at:
- */
+struct jdi_panel {
struct drm_panel base;
struct mipi_dsi_device *dsi;
/* TODO: Add backilght support */
struct backlight_device *backlight;
struct regulator *supply;
struct gpio_desc *reset_gpio;
struct gpio_desc *enable_gpio;
struct gpio_desc *vcc_gpio;
struct regulator *backlit;
struct regulator *lvs7;
struct regulator *avdd;
struct regulator *iovdd;
struct gpio_desc *pwm_gpio;
bool prepared;
bool enabled;
const struct drm_display_mode *mode;
+};
+static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel) +{
return container_of(panel, struct jdi_panel, base);
+}
+static char MCAP[2] = {0xB0, 0x00}; +static char interface_setting_cmd[6] = {0xB3, 0x04, 0x08, 0x00, 0x22, 0x00}; +static char interface_setting[6] = {0xB3, 0x26, 0x08, 0x00, 0x20, 0x00};
+static char interface_ID_setting[2] = {0xB4, 0x0C}; +static char DSI_control[3] = {0xB6, 0x3A, 0xD3};
+static char tear_scan_line[3] = {0x44, 0x03, 0x00};
+/* for fps control, set fps to 60.32Hz */ +static char LTPS_timing_setting[2] = {0xC6, 0x78}; +static char sequencer_timing_control[2] = {0xD6, 0x01};
+/* set brightness */ +static char write_display_brightness[] = {0x51, 0xFF}; +/* enable LEDPWM pin output, turn on LEDPWM output, turn off pwm dimming */ +static char write_control_display[] = {0x53, 0x24}; +/*
- choose cabc mode, 0x00(-0%), 0x01(-15%), 0x02(-40%), 0x03(-54%),
- disable SRE(sunlight readability enhancement)
- */
+static char write_cabc[] = {0x55, 0x00}; +/* for cabc mode 0x1(-15%) */ +static char backlight_control1[] = {0xB8, 0x07, 0x87, 0x26, 0x18, 0x00, 0x32}; +/* for cabc mode 0x2(-40%) */ +static char backlight_control2[] = {0xB9, 0x07, 0x75, 0x61, 0x20, 0x16, 0x87}; +/* for cabc mode 0x3(-54%) */ +static char backlight_control3[] = {0xBA, 0x07, 0x70, 0x81, 0x20, 0x45, 0xB4}; +/* for pwm frequency and dimming control */ +static char backlight_control4[] = {0xCE, 0x7D, 0x40, 0x48, 0x56, 0x67, 0x78,
0x88, 0x98, 0xA7, 0xB5, 0xC3, 0xD1, 0xDE, 0xE9, 0xF2,
0xFA,
0xFF, 0x37, 0xF5, 0x0F, 0x0F, 0x42, 0x00};
Apart from the u8 conversion as mentioned by Thierry, you should convert these to const too.
+static int jdi_panel_init(struct jdi_panel *jdi) +{
struct mipi_dsi_device *dsi = jdi->dsi;
int ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
ret = mipi_dsi_dcs_soft_reset(dsi);
if (ret < 0)
return ret;
mdelay(10);
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x70);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_set_column_address(dsi, 0x0000,
0x04AF);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_set_page_address(dsi, 0x0000, 0x077F);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_set_tear_on(dsi,
MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0)
return ret;
mdelay(5);
ret = mipi_dsi_generic_write(dsi, tear_scan_line,
sizeof(tear_scan_line));
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_write_buffer(dsi,
write_display_brightness,
sizeof(write_display_brightness)
);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_write_buffer(dsi,
write_control_display,
sizeof(write_control_display));
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_write_buffer(dsi, write_cabc,
sizeof(write_cabc));
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0)
return ret;
mdelay(120);
ret = mipi_dsi_generic_write(dsi, MCAP, sizeof(MCAP));
if (ret < 0)
return ret;
mdelay(10);
ret = mipi_dsi_generic_write(dsi, interface_setting,
sizeof(interface_setting));
if (ret < 0)
return ret;
mdelay(20);
backlight_control4[18] = 0x04;
backlight_control4[19] = 0x00;
Any reason why these are overwritten? It would be better to have these values in the array itself.
ret = mipi_dsi_generic_write(dsi, backlight_control4,
sizeof(backlight_control4));
if (ret < 0)
return ret;
mdelay(20);
MCAP[1] = 0x03;
ret = mipi_dsi_generic_write(dsi, MCAP, sizeof(MCAP));
if (ret < 0)
return ret;
} else {
/*
* TODO : need to verify panel settings when
* dsi cmd mode supported for apq8064 - simhavcs
*/
ret = mipi_dsi_dcs_soft_reset(dsi);
if (ret < 0)
return ret;
mdelay(5);
ret = mipi_dsi_generic_write(dsi, MCAP, sizeof(MCAP));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi, interface_setting_cmd,
sizeof(interface_setting_cmd));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi, interface_ID_setting,
sizeof(interface_ID_setting));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi, DSI_control,
sizeof(DSI_control));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi, LTPS_timing_setting,
sizeof(LTPS_timing_setting));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi,
sequencer_timing_control,
sizeof(sequencer_timing_control));
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_write_buffer(dsi,
write_display_brightness,
sizeof(write_display_brightness)
);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_write_buffer(dsi,
write_control_display,
sizeof(write_control_display));
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_write_buffer(dsi, write_cabc,
sizeof(write_cabc));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi, backlight_control1,
sizeof(backlight_control1));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi, backlight_control2,
sizeof(backlight_control2));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi, backlight_control3,
sizeof(backlight_control3));
if (ret < 0)
return ret;
ret = mipi_dsi_generic_write(dsi, backlight_control4,
sizeof(backlight_control4));
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_set_column_address(dsi, 0x0000,
0x04AF);
if (ret < 0)
return ret;
ret = mipi_dsi_dcs_set_page_address(dsi, 0x0000, 0x077F);
if (ret < 0)
return ret;
mdelay(120);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0)
return ret;
}
return 0;
+}
+static int jdi_panel_on(struct jdi_panel *jdi) +{
struct mipi_dsi_device *dsi = jdi->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 jdi_panel_off(struct jdi_panel *jdi) +{
struct mipi_dsi_device *dsi = jdi->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;
ret = mipi_dsi_dcs_set_tear_off(dsi);
if (ret < 0)
return ret;
msleep(100);
return 0;
+}
+static int jdi_panel_disable(struct drm_panel *panel) +{
struct jdi_panel *jdi = to_jdi_panel(panel);
if (!jdi->enabled)
return 0;
DRM_DEBUG("disable\n");
if (jdi->backlight) {
jdi->backlight->props.power = FB_BLANK_POWERDOWN;
backlight_update_status(jdi->backlight);
}
jdi->enabled = false;
return 0;
+}
+static int jdi_panel_unprepare(struct drm_panel *panel) +{
struct jdi_panel *jdi = to_jdi_panel(panel);
int ret;
if (!jdi->prepared)
return 0;
DRM_DEBUG("unprepare\n");
ret = jdi_panel_off(jdi);
if (ret) {
dev_err(panel->dev, "failed to set panel off: %d\n", ret);
return ret;
}
regulator_disable(jdi->supply);
if (jdi->vcc_gpio)
gpiod_set_value(jdi->vcc_gpio, 0);
if (jdi->reset_gpio)
gpiod_set_value(jdi->reset_gpio, 0);
if (jdi->enable_gpio)
gpiod_set_value(jdi->enable_gpio, 0);
jdi->prepared = false;
return 0;
+}
+static int jdi_panel_prepare(struct drm_panel *panel) +{
struct jdi_panel *jdi = to_jdi_panel(panel);
int ret;
if (jdi->prepared)
return 0;
DRM_DEBUG("prepare\n");
ret = regulator_enable(jdi->iovdd);
if (ret < 0)
return ret;
ret = regulator_enable(jdi->avdd);
if (ret < 0)
return ret;
ret = regulator_enable(jdi->backlit);
if (ret < 0)
return ret;
ret = regulator_enable(jdi->lvs7);
if (ret < 0)
return ret;
ret = regulator_enable(jdi->supply);
if (ret < 0)
return ret;
msleep(20);
if (jdi->vcc_gpio) {
gpiod_set_value(jdi->vcc_gpio, 1);
usleep_range(10, 20);
}
if (jdi->reset_gpio) {
gpiod_set_value(jdi->reset_gpio, 1);
usleep_range(10, 20);
}
if (jdi->pwm_gpio) {
gpiod_set_value(jdi->pwm_gpio, 1);
usleep_range(10, 20);
}
if (jdi->enable_gpio) {
gpiod_set_value(jdi->enable_gpio, 1);
usleep_range(10, 20);
}
ret = jdi_panel_init(jdi);
if (ret) {
dev_err(panel->dev, "failed to init panel: %d\n", ret);
goto poweroff;
}
ret = jdi_panel_on(jdi);
if (ret) {
dev_err(panel->dev, "failed to set panel on: %d\n", ret);
goto poweroff;
}
jdi->prepared = true;
return 0;
+poweroff:
regulator_disable(jdi->supply);
if (jdi->reset_gpio)
gpiod_set_value(jdi->reset_gpio, 0);
if (jdi->enable_gpio)
gpiod_set_value(jdi->enable_gpio, 0);
if (jdi->vcc_gpio)
gpiod_set_value(jdi->vcc_gpio, 0);
return ret;
+}
+static int jdi_panel_enable(struct drm_panel *panel) +{
struct jdi_panel *jdi = to_jdi_panel(panel);
if (jdi->enabled)
return 0;
DRM_DEBUG("enable\n");
if (jdi->backlight) {
jdi->backlight->props.power = FB_BLANK_UNBLANK;
backlight_update_status(jdi->backlight);
}
jdi->enabled = true;
return 0;
+}
The prepare/enable split seems a bit strange. Don't we want to put mipi_dsi_dcs_set_display_on in the enable() op too?
enable will be called after the prepare(). enable() - usually the backlight update status BLANK/UNBLANK is done
+static const struct drm_display_mode default_mode = {
.clock = 155000,
htotal * vtotal * vrefresh (1934 * 1340 * 60.32(as in comment)) comes at around 156.3 Mhz. Could you plug in the correct frequency?
.hdisplay = 1200,
.hsync_start = 1200 + 48,
.hsync_end = 1200 + 48 + 32,
.htotal = 1200 + 48 + 32 + 60,
.vdisplay = 1920,
.vsync_start = 1920 + 3,
.vsync_end = 1920 + 3 + 5,
.vtotal = 1920 + 3 + 5 + 6,
.vrefresh = 60,
.flags = 0,
+};
+static int jdi_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);
We should use the dsi->dev device pointer here like used elsewhere, not the drm device pointer.
return -ENOMEM;
}
drm_mode_set_name(mode);
drm_mode_probed_add(panel->connector, mode);
return 1;
+}
+static const struct drm_panel_funcs jdi_panel_funcs = {
.disable = jdi_panel_disable,
.unprepare = jdi_panel_unprepare,
.prepare = jdi_panel_prepare,
.enable = jdi_panel_enable,
.get_modes = jdi_panel_get_modes,
+};
+static const struct of_device_id jdi_of_match[] = {
{ .compatible = "jdi,lt070me05000", },
{ }
+}; +MODULE_DEVICE_TABLE(of, jdi_of_match);
+static int jdi_panel_add(struct jdi_panel *jdi) +{
struct device *dev = &jdi->dsi->dev;
int ret;
jdi->mode = &default_mode;
/* lvs5 */
jdi->supply = devm_regulator_get(dev, "power");
if (IS_ERR(jdi->supply))
return PTR_ERR(jdi->supply);
You could consider using regulator_get_bulk() api here, it would clean up the code a bit.
/* l17 */
jdi->backlit = devm_regulator_get(dev, "backlit");
if (IS_ERR(jdi->supply))
return PTR_ERR(jdi->supply);
jdi->lvs7 = devm_regulator_get(dev, "lvs7");
if (IS_ERR(jdi->lvs7))
return PTR_ERR(jdi->lvs7);
jdi->avdd = devm_regulator_get(dev, "avdd");
if (IS_ERR(jdi->avdd))
return PTR_ERR(jdi->avdd);
jdi->iovdd = devm_regulator_get(dev, "iovdd");
if (IS_ERR(jdi->iovdd))
return PTR_ERR(jdi->iovdd);
jdi->vcc_gpio = devm_gpiod_get(dev, "vcc", GPIOD_OUT_LOW);
if (IS_ERR(jdi->vcc_gpio)) {
dev_err(dev, "cannot get vcc-gpio %ld\n",
PTR_ERR(jdi->vcc_gpio));
jdi->vcc_gpio = NULL;
} else {
gpiod_direction_output(jdi->vcc_gpio, 0);
}
jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(jdi->reset_gpio)) {
dev_err(dev, "cannot get reset-gpios %ld\n",
PTR_ERR(jdi->reset_gpio));
jdi->reset_gpio = NULL;
} else {
gpiod_direction_output(jdi->reset_gpio, 0);
}
jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(jdi->enable_gpio)) {
dev_err(dev, "cannot get enable-gpio %ld\n",
PTR_ERR(jdi->enable_gpio));
jdi->enable_gpio = NULL;
} else {
gpiod_direction_output(jdi->enable_gpio, 0);
}
jdi->pwm_gpio = devm_gpiod_get(dev, "pwm", GPIOD_OUT_LOW);
if (IS_ERR(jdi->pwm_gpio)) {
dev_err(dev, "cannot get pwm-gpio %ld\n",
PTR_ERR(jdi->pwm_gpio));
jdi->pwm_gpio = NULL;
} else {
gpiod_direction_output(jdi->pwm_gpio, 0);
}
/* we don't have backlight right now, proceed further */
+#ifdef BACKLIGHT
np = of_parse_phandle(dev->of_node, "backlight", 0);
if (np) {
jdi->backlight = of_find_backlight_by_node(np);
of_node_put(np);
if (!jdi->backlight)
return -EPROBE_DEFER;
}
+#endif
drm_panel_init(&jdi->base);
jdi->base.funcs = &jdi_panel_funcs;
jdi->base.dev = &jdi->dsi->dev;
ret = drm_panel_add(&jdi->base);
if (ret < 0)
goto put_backlight;
return 0;
+put_backlight:
if (jdi->backlight)
put_device(&jdi->backlight->dev);
return ret;
+}
+static void jdi_panel_del(struct jdi_panel *jdi) +{
if (jdi->base.dev)
drm_panel_remove(&jdi->base);
if (jdi->backlight)
put_device(&jdi->backlight->dev);
+}
+static int jdi_panel_probe(struct mipi_dsi_device *dsi) +{
struct jdi_panel *jdi;
int ret;
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_HFP | MIPI_DSI_MODE_VIDEO_HBP
|
MIPI_DSI_MODE_VIDEO_HSA |
MIPI_DSI_CLOCK_NON_CONTINUOUS;
jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);
if (!jdi)
return -ENOMEM;
mipi_dsi_set_drvdata(dsi, jdi);
jdi->dsi = dsi;
ret = jdi_panel_add(jdi);
if (ret < 0)
return ret;
return mipi_dsi_attach(dsi);
+}
+static int jdi_panel_remove(struct mipi_dsi_device *dsi) +{
struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
int ret;
ret = jdi_panel_disable(&jdi->base);
if (ret < 0)
dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
Ideally, the driver's remove op shouldn't try to disable the panel. It should be done by the dsi host's connector itself. We can drop this unless there is a specfic reason to do so.
panel_disable() - sets the backlight brightness off fyi, include/drm/drm_panel.h Before stopping video transmission from the display controller it can be necessary to turn off the panel to avoid visual glitches. This is done in the .disable() function.
Thanks for working on this.
Archit
-- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project