Created
October 14, 2019 11:13
-
-
Save Sorixelle/238133cd3275956ce01f7ad677d68b78 to your computer and use it in GitHub Desktop.
tianma_499_720p_video_v2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: GPL-2.0-only | |
// Copyright (c) 2013, The Linux Foundation. All rights reserved. | |
static const struct drm_display_mode tianma_499_v2_mode = { | |
.clock = (720 + 52 + 20 + 84) * (1280 + 20 + 8 + 20) * 60 / 1000, | |
.hdisplay = 720, | |
.hsync_start = 720 + 52, | |
.hsync_end = 720 + 52 + 20, | |
.htotal = 720 + 52 + 20 + 84, | |
.vdisplay = 1280, | |
.vsync_start = 1280 + 20, | |
.vsync_end = 1280 + 20 + 8, | |
.vtotal = 1280 + 20 + 8 + 20, | |
.vrefresh = 60, | |
.width_mm = 62, | |
.height_mm = 110, | |
}; | |
static const struct panel_desc_dsi tianma_499_v2 = { | |
.desc = { | |
.modes = &tianma_499_v2_mode, | |
.num_modes = 1, | |
.bpc = 8, | |
.size = { | |
.width = 62, | |
.height = 110, | |
}, | |
}, | |
.flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | | |
MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_CLOCK_NON_CONTINUOUS | | |
MIPI_DSI_MODE_LPM, | |
.format = MIPI_DSI_FMT_RGB888, | |
.lanes = 4, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: GPL-2.0-only | |
// Copyright (c) 2013, The Linux Foundation. All rights reserved. | |
#include <drm/drm_mipi_dsi.h> | |
#include <drm/drm_modes.h> | |
#include <drm/drm_panel.h> | |
#include <linux/backlight.h> | |
#include <linux/delay.h> | |
#include <linux/gpio/consumer.h> | |
#include <linux/module.h> | |
#include <linux/of.h> | |
#include <video/mipi_display.h> | |
struct tianma_499_v2 { | |
struct drm_panel panel; | |
struct mipi_dsi_device *dsi; | |
struct backlight_device *backlight; | |
struct gpio_desc *reset_gpio; | |
bool prepared; | |
bool enabled; | |
}; | |
static inline struct tianma_499_v2 *to_tianma_499_v2(struct drm_panel *panel) | |
{ | |
return container_of(panel, struct tianma_499_v2, panel); | |
} | |
#define dsi_dcs_write_seq(dsi, seq...) do { \ | |
static const u8 d[] = { seq }; \ | |
int ret; \ | |
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \ | |
if (ret < 0) \ | |
return ret; \ | |
} while (0) | |
static void tianma_499_v2_reset(struct tianma_499_v2 *ctx) | |
{ | |
gpiod_set_value_cansleep(ctx->reset_gpio, 1); | |
usleep_range(1000, 2000); | |
gpiod_set_value_cansleep(ctx->reset_gpio, 0); | |
usleep_range(10000, 11000); | |
gpiod_set_value_cansleep(ctx->reset_gpio, 1); | |
msleep(20); | |
} | |
static int tianma_499_v2_on(struct tianma_499_v2 *ctx) | |
{ | |
struct mipi_dsi_device *dsi = ctx->dsi; | |
struct device *dev = &dsi->dev; | |
int ret; | |
dsi_dcs_write_seq(dsi, 0xff, 0x98, 0x81, 0x00); | |
ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x0000); | |
if (ret < 0) { | |
dev_err(dev, "Failed to set display brightness: %d\n", ret); | |
return ret; | |
} | |
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x2c); | |
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x01); | |
dsi_dcs_write_seq(dsi, 0x68, 0x06); | |
ret = mipi_dsi_dcs_exit_sleep_mode(dsi); | |
if (ret < 0) { | |
dev_err(dev, "Failed to exit sleep mode: %d\n", ret); | |
return ret; | |
} | |
msleep(120); | |
ret = mipi_dsi_dcs_set_display_on(dsi); | |
if (ret < 0) { | |
dev_err(dev, "Failed to set display on: %d\n", ret); | |
return ret; | |
} | |
msleep(20); | |
return 0; | |
} | |
static int tianma_499_v2_off(struct tianma_499_v2 *ctx) | |
{ | |
struct mipi_dsi_device *dsi = ctx->dsi; | |
struct device *dev = &dsi->dev; | |
int ret; | |
ret = mipi_dsi_dcs_set_display_off(dsi); | |
if (ret < 0) { | |
dev_err(dev, "Failed to set display off: %d\n", ret); | |
return ret; | |
} | |
msleep(20); | |
ret = mipi_dsi_dcs_enter_sleep_mode(dsi); | |
if (ret < 0) { | |
dev_err(dev, "Failed to enter sleep mode: %d\n", ret); | |
return ret; | |
} | |
msleep(120); | |
return 0; | |
} | |
static int tianma_499_v2_prepare(struct drm_panel *panel) | |
{ | |
struct tianma_499_v2 *ctx = to_tianma_499_v2(panel); | |
struct device *dev = &ctx->dsi->dev; | |
int ret; | |
if (ctx->prepared) | |
return 0; | |
tianma_499_v2_reset(ctx); | |
ret = tianma_499_v2_on(ctx); | |
if (ret < 0) { | |
dev_err(dev, "Failed to initialize panel: %d\n", ret); | |
gpiod_set_value_cansleep(ctx->reset_gpio, 0); | |
return ret; | |
} | |
ctx->prepared = true; | |
return 0; | |
} | |
static int tianma_499_v2_unprepare(struct drm_panel *panel) | |
{ | |
struct tianma_499_v2 *ctx = to_tianma_499_v2(panel); | |
struct device *dev = &ctx->dsi->dev; | |
int ret; | |
if (!ctx->prepared) | |
return 0; | |
ret = tianma_499_v2_off(ctx); | |
if (ret < 0) | |
dev_err(dev, "Failed to un-initialize panel: %d\n", ret); | |
gpiod_set_value_cansleep(ctx->reset_gpio, 0); | |
ctx->prepared = false; | |
return 0; | |
} | |
static int tianma_499_v2_enable(struct drm_panel *panel) | |
{ | |
struct tianma_499_v2 *ctx = to_tianma_499_v2(panel); | |
int ret; | |
if (ctx->enabled) | |
return 0; | |
ret = backlight_enable(ctx->backlight); | |
if (ret < 0) { | |
dev_err(&ctx->dsi->dev, "Failed to enable backlight: %d\n", ret); | |
return ret; | |
} | |
ctx->enabled = true; | |
return 0; | |
} | |
static int tianma_499_v2_disable(struct drm_panel *panel) | |
{ | |
struct tianma_499_v2 *ctx = to_tianma_499_v2(panel); | |
int ret; | |
if (!ctx->enabled) | |
return 0; | |
ret = backlight_disable(ctx->backlight); | |
if (ret < 0) { | |
dev_err(&ctx->dsi->dev, "Failed to disable backlight: %d\n", ret); | |
return ret; | |
} | |
ctx->enabled = false; | |
return 0; | |
} | |
static const struct drm_display_mode tianma_499_v2_mode = { | |
.clock = (720 + 52 + 20 + 84) * (1280 + 20 + 8 + 20) * 60 / 1000, | |
.hdisplay = 720, | |
.hsync_start = 720 + 52, | |
.hsync_end = 720 + 52 + 20, | |
.htotal = 720 + 52 + 20 + 84, | |
.vdisplay = 1280, | |
.vsync_start = 1280 + 20, | |
.vsync_end = 1280 + 20 + 8, | |
.vtotal = 1280 + 20 + 8 + 20, | |
.vrefresh = 60, | |
.width_mm = 62, | |
.height_mm = 110, | |
}; | |
static int tianma_499_v2_get_modes(struct drm_panel *panel) | |
{ | |
struct drm_display_mode *mode; | |
mode = drm_mode_duplicate(panel->drm, &tianma_499_v2_mode); | |
if (!mode) | |
return -ENOMEM; | |
drm_mode_set_name(mode); | |
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; | |
panel->connector->display_info.width_mm = mode->width_mm; | |
panel->connector->display_info.height_mm = mode->height_mm; | |
drm_mode_probed_add(panel->connector, mode); | |
return 1; | |
} | |
static const struct drm_panel_funcs tianma_499_v2_panel_funcs = { | |
.disable = tianma_499_v2_disable, | |
.unprepare = tianma_499_v2_unprepare, | |
.prepare = tianma_499_v2_prepare, | |
.enable = tianma_499_v2_enable, | |
.get_modes = tianma_499_v2_get_modes, | |
}; | |
static int dsi_dcs_bl_get_brightness(struct backlight_device *bl) | |
{ | |
struct mipi_dsi_device *dsi = bl_get_data(bl); | |
int ret; | |
u16 brightness = bl->props.brightness; | |
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; | |
ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness); | |
if (ret < 0) | |
return ret; | |
dsi->mode_flags |= MIPI_DSI_MODE_LPM; | |
return brightness; | |
} | |
static int dsi_dcs_bl_update_status(struct backlight_device *bl) | |
{ | |
struct mipi_dsi_device *dsi = bl_get_data(bl); | |
int ret; | |
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; | |
ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness); | |
if (ret < 0) | |
return ret; | |
dsi->mode_flags |= MIPI_DSI_MODE_LPM; | |
return 0; | |
} | |
static const struct backlight_ops dsi_bl_ops = { | |
.update_status = dsi_dcs_bl_update_status, | |
.get_brightness = dsi_dcs_bl_get_brightness, | |
}; | |
static struct backlight_device * | |
tianma_499_v2_create_backlight(struct mipi_dsi_device *dsi) | |
{ | |
struct device *dev = &dsi->dev; | |
struct backlight_properties props; | |
memset(&props, 0, sizeof(props)); | |
props.type = BACKLIGHT_RAW; | |
props.brightness = 4095; | |
props.max_brightness = 4095; | |
return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, | |
&dsi_bl_ops, &props); | |
} | |
static int tianma_499_v2_probe(struct mipi_dsi_device *dsi) | |
{ | |
struct device *dev = &dsi->dev; | |
struct tianma_499_v2 *ctx; | |
int ret; | |
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); | |
if (!ctx) | |
return -ENOMEM; | |
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | |
if (IS_ERR(ctx->reset_gpio)) { | |
ret = PTR_ERR(ctx->reset_gpio); | |
dev_err(dev, "Failed to get reset-gpios: %d\n", ret); | |
return ret; | |
} | |
ctx->backlight = tianma_499_v2_create_backlight(dsi); | |
if (IS_ERR(ctx->backlight)) { | |
ret = PTR_ERR(ctx->backlight); | |
dev_err(dev, "Failed to create backlight: %d\n", ret); | |
return ret; | |
} | |
ctx->dsi = dsi; | |
mipi_dsi_set_drvdata(dsi, ctx); | |
dsi->lanes = 4; | |
dsi->format = MIPI_DSI_FMT_RGB888; | |
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | | |
MIPI_DSI_MODE_VIDEO_HSE | | |
MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM; | |
drm_panel_init(&ctx->panel); | |
ctx->panel.dev = dev; | |
ctx->panel.funcs = &tianma_499_v2_panel_funcs; | |
ret = drm_panel_add(&ctx->panel); | |
if (ret < 0) { | |
dev_err(dev, "Failed to add panel: %d\n", ret); | |
return ret; | |
} | |
ret = mipi_dsi_attach(dsi); | |
if (ret < 0) { | |
dev_err(dev, "Failed to attach to DSI host: %d\n", ret); | |
return ret; | |
} | |
return 0; | |
} | |
static int tianma_499_v2_remove(struct mipi_dsi_device *dsi) | |
{ | |
struct tianma_499_v2 *ctx = mipi_dsi_get_drvdata(dsi); | |
int ret; | |
ret = mipi_dsi_detach(dsi); | |
if (ret < 0) | |
dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); | |
drm_panel_remove(&ctx->panel); | |
return 0; | |
} | |
static const struct of_device_id tianma_499_v2_of_match[] = { | |
{ .compatible = "mdss,tianma_499_v2" }, // FIXME | |
{ } | |
}; | |
MODULE_DEVICE_TABLE(of, tianma_499_v2_of_match); | |
static struct mipi_dsi_driver tianma_499_v2_driver = { | |
.probe = tianma_499_v2_probe, | |
.remove = tianma_499_v2_remove, | |
.driver = { | |
.name = "panel-tianma-499-v2", | |
.of_match_table = tianma_499_v2_of_match, | |
}, | |
}; | |
module_mipi_dsi_driver(tianma_499_v2_driver); | |
MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator <fix@me>"); | |
MODULE_DESCRIPTION("DRM driver for mipi_mot_video_tianma_720p_499"); | |
MODULE_LICENSE("GPL v2"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment