cregit-Linux how code gets into the kernel

Release 4.17 drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c

/*
 * MIPI-DSI based S6E63J0X03 AMOLED lcd 1.63 inch panel driver.
 *
 * Copyright (c) 2014-2017 Samsung Electronics Co., Ltd
 *
 * Inki Dae <inki.dae@samsung.com>
 * Hoegeun Kwon <hoegeun.kwon@samsung.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.
 */

#include <drm/drmP.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
#include <linux/backlight.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>


#define MCS_LEVEL2_KEY		0xf0

#define MCS_MTP_KEY		0xf1

#define MCS_MTP_SET3		0xd4


#define MAX_BRIGHTNESS		100

#define DEFAULT_BRIGHTNESS	80


#define NUM_GAMMA_STEPS		9

#define GAMMA_CMD_CNT		28


#define FIRST_COLUMN 20


struct s6e63j0x03 {
	
struct device *dev;
	
struct drm_panel panel;
	
struct backlight_device *bl_dev;

	
struct regulator_bulk_data supplies[2];
	
struct gpio_desc *reset_gpio;
};


static const struct drm_display_mode default_mode = {
	.clock = 4649,
	.hdisplay = 320,
	.hsync_start = 320 + 1,
	.hsync_end = 320 + 1 + 1,
	.htotal = 320 + 1 + 1 + 1,
	.vdisplay = 320,
	.vsync_start = 320 + 150,
	.vsync_end = 320 + 150 + 1,
	.vtotal = 320 + 150 + 1 + 2,
	.vrefresh = 30,
	.flags = 0,
};


static const unsigned char gamma_tbl[NUM_GAMMA_STEPS][GAMMA_CMD_CNT] = {
	{	/* Gamma 10 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x52, 0x6b, 0x6f, 0x26,
		0x28, 0x2d, 0x28, 0x26, 0x27, 0x33, 0x34, 0x32, 0x36, 0x36,
		0x35, 0x00, 0xab, 0x00, 0xae, 0x00, 0xbf
	},
	{	/* gamma 30 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x70, 0x7f, 0x7f, 0x4e, 0x64, 0x69, 0x26,
		0x27, 0x2a, 0x28, 0x29, 0x27, 0x31, 0x32, 0x31, 0x35, 0x34,
		0x35, 0x00, 0xc4, 0x00, 0xca, 0x00, 0xdc
	},
	{	/* gamma 60 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x65, 0x7b, 0x7d, 0x5f, 0x67, 0x68, 0x2a,
		0x28, 0x29, 0x28, 0x2a, 0x27, 0x31, 0x2f, 0x30, 0x34, 0x33,
		0x34, 0x00, 0xd9, 0x00, 0xe4, 0x00, 0xf5
	},
	{	/* gamma 90 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x4d, 0x6f, 0x71, 0x67, 0x6a, 0x6c, 0x29,
		0x28, 0x28, 0x28, 0x29, 0x27, 0x30, 0x2e, 0x30, 0x32, 0x31,
		0x31, 0x00, 0xea, 0x00, 0xf6, 0x01, 0x09
	},
	{	/* gamma 120 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x3d, 0x66, 0x68, 0x69, 0x69, 0x69, 0x28,
		0x28, 0x27, 0x28, 0x28, 0x27, 0x30, 0x2e, 0x2f, 0x31, 0x31,
		0x30, 0x00, 0xf9, 0x01, 0x05, 0x01, 0x1b
	},
	{	/* gamma 150 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x31, 0x51, 0x53, 0x66, 0x66, 0x67, 0x28,
		0x29, 0x27, 0x28, 0x27, 0x27, 0x2e, 0x2d, 0x2e, 0x31, 0x31,
		0x30, 0x01, 0x04, 0x01, 0x11, 0x01, 0x29
	},
	{	/* gamma 200 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x2f, 0x4f, 0x51, 0x67, 0x65, 0x65, 0x29,
		0x2a, 0x28, 0x27, 0x25, 0x26, 0x2d, 0x2c, 0x2c, 0x30, 0x30,
		0x30, 0x01, 0x14, 0x01, 0x23, 0x01, 0x3b
	},
	{	/* gamma 240 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x2c, 0x4d, 0x50, 0x65, 0x63, 0x64, 0x2a,
		0x2c, 0x29, 0x26, 0x24, 0x25, 0x2c, 0x2b, 0x2b, 0x30, 0x30,
		0x30, 0x01, 0x1e, 0x01, 0x2f, 0x01, 0x47
	},
	{	/* gamma 300 */
		MCS_MTP_SET3,
		0x00, 0x00, 0x00, 0x38, 0x61, 0x64, 0x65, 0x63, 0x64, 0x28,
		0x2a, 0x27, 0x26, 0x23, 0x25, 0x2b, 0x2b, 0x2a, 0x30, 0x2f,
		0x30, 0x01, 0x2d, 0x01, 0x3f, 0x01, 0x57
	}
};


static inline struct s6e63j0x03 *panel_to_s6e63j0x03(struct drm_panel *panel) { return container_of(panel, struct s6e63j0x03, panel); }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon25100.00%1100.00%
Total25100.00%1100.00%


static inline ssize_t s6e63j0x03_dcs_write_seq(struct s6e63j0x03 *ctx, const void *seq, size_t len) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); return mipi_dsi_dcs_write_buffer(dsi, seq, len); }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon42100.00%1100.00%
Total42100.00%1100.00%

#define s6e63j0x03_dcs_write_seq_static(ctx, seq...) \ ({ \ static const u8 d[] = { seq }; \ s6e63j0x03_dcs_write_seq(ctx, d, ARRAY_SIZE(d)); \ })
static inline int s6e63j0x03_enable_lv2_command(struct s6e63j0x03 *ctx) { return s6e63j0x03_dcs_write_seq_static(ctx, MCS_LEVEL2_KEY, 0x5a, 0x5a); }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon24100.00%1100.00%
Total24100.00%1100.00%


static inline int s6e63j0x03_apply_mtp_key(struct s6e63j0x03 *ctx, bool on) { if (on) return s6e63j0x03_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0x5a, 0x5a); return s6e63j0x03_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0xa5, 0xa5); }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon43100.00%1100.00%
Total43100.00%1100.00%


static int s6e63j0x03_power_on(struct s6e63j0x03 *ctx) { int ret; ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) return ret; msleep(30); gpiod_set_value(ctx->reset_gpio, 1); usleep_range(1000, 2000); gpiod_set_value(ctx->reset_gpio, 0); usleep_range(5000, 6000); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon79100.00%1100.00%
Total79100.00%1100.00%


static int s6e63j0x03_power_off(struct s6e63j0x03 *ctx) { return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon26100.00%1100.00%
Total26100.00%1100.00%


static unsigned int s6e63j0x03_get_brightness_index(unsigned int brightness) { unsigned int index; index = brightness / (MAX_BRIGHTNESS / NUM_GAMMA_STEPS); if (index >= NUM_GAMMA_STEPS) index = NUM_GAMMA_STEPS - 1; return index; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon40100.00%1100.00%
Total40100.00%1100.00%


static int s6e63j0x03_update_gamma(struct s6e63j0x03 *ctx, unsigned int brightness) { struct backlight_device *bl_dev = ctx->bl_dev; unsigned int index = s6e63j0x03_get_brightness_index(brightness); int ret; ret = s6e63j0x03_apply_mtp_key(ctx, true); if (ret < 0) return ret; ret = s6e63j0x03_dcs_write_seq(ctx, gamma_tbl[index], GAMMA_CMD_CNT); if (ret < 0) return ret; ret = s6e63j0x03_apply_mtp_key(ctx, false); if (ret < 0) return ret; bl_dev->props.brightness = brightness; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon106100.00%1100.00%
Total106100.00%1100.00%


static int s6e63j0x03_set_brightness(struct backlight_device *bl_dev) { struct s6e63j0x03 *ctx = bl_get_data(bl_dev); unsigned int brightness = bl_dev->props.brightness; return s6e63j0x03_update_gamma(ctx, brightness); }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon39100.00%1100.00%
Total39100.00%1100.00%

static const struct backlight_ops s6e63j0x03_bl_ops = { .update_status = s6e63j0x03_set_brightness, };
static int s6e63j0x03_disable(struct drm_panel *panel) { struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) return ret; ctx->bl_dev->props.power = FB_BLANK_NORMAL; ret = mipi_dsi_dcs_enter_sleep_mode(dsi); if (ret < 0) return ret; msleep(120); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon86100.00%1100.00%
Total86100.00%1100.00%


static int s6e63j0x03_unprepare(struct drm_panel *panel) { struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel); int ret; ret = s6e63j0x03_power_off(ctx); if (ret < 0) return ret; ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon53100.00%1100.00%
Total53100.00%1100.00%


static int s6e63j0x03_panel_init(struct s6e63j0x03 *ctx) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; ret = s6e63j0x03_enable_lv2_command(ctx); if (ret < 0) return ret; ret = s6e63j0x03_apply_mtp_key(ctx, true); if (ret < 0) return ret; /* set porch adjustment */ ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf2, 0x1c, 0x28); if (ret < 0) return ret; /* set frame freq */ ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb5, 0x00, 0x02, 0x00); if (ret < 0) return ret; /* set caset, paset */ ret = mipi_dsi_dcs_set_column_address(dsi, FIRST_COLUMN, default_mode.hdisplay - 1 + FIRST_COLUMN); if (ret < 0) return ret; ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1); if (ret < 0) return ret; /* set ltps timming 0, 1 */ ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf8, 0x08, 0x08, 0x08, 0x17, 0x00, 0x2a, 0x02, 0x26, 0x00, 0x00, 0x02, 0x00, 0x00); if (ret < 0) return ret; ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xf7, 0x02); if (ret < 0) return ret; /* set param pos te_edge */ ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb0, 0x01); if (ret < 0) return ret; /* set te rising edge */ ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xe2, 0x0f); if (ret < 0) return ret; /* set param pos default */ ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb0, 0x00); if (ret < 0) return ret; ret = mipi_dsi_dcs_exit_sleep_mode(dsi); if (ret < 0) return ret; ret = s6e63j0x03_apply_mtp_key(ctx, false); if (ret < 0) return ret; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon324100.00%1100.00%
Total324100.00%1100.00%


static int s6e63j0x03_prepare(struct drm_panel *panel) { struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel); int ret; ret = s6e63j0x03_power_on(ctx); if (ret < 0) return ret; ret = s6e63j0x03_panel_init(ctx); if (ret < 0) goto err; ctx->bl_dev->props.power = FB_BLANK_NORMAL; return 0; err: s6e63j0x03_power_off(ctx); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon79100.00%1100.00%
Total79100.00%1100.00%


static int s6e63j0x03_enable(struct drm_panel *panel) { struct s6e63j0x03 *ctx = panel_to_s6e63j0x03(panel); struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; msleep(120); ret = s6e63j0x03_apply_mtp_key(ctx, true); if (ret < 0) return ret; /* set elvss_cond */ ret = s6e63j0x03_dcs_write_seq_static(ctx, 0xb1, 0x00, 0x09); if (ret < 0) return ret; /* set pos */ ret = s6e63j0x03_dcs_write_seq_static(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x40); if (ret < 0) return ret; /* set default white brightness */ ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x00ff); if (ret < 0) return ret; /* set white ctrl */ ret = s6e63j0x03_dcs_write_seq_static(ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); if (ret < 0) return ret; /* set acl off */ ret = s6e63j0x03_dcs_write_seq_static(ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00); if (ret < 0) return ret; ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); if (ret < 0) return ret; ret = s6e63j0x03_apply_mtp_key(ctx, false); if (ret < 0) return ret; ret = mipi_dsi_dcs_set_display_on(dsi); if (ret < 0) return ret; ctx->bl_dev->props.power = FB_BLANK_UNBLANK; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon229100.00%1100.00%
Total229100.00%1100.00%


static int s6e63j0x03_get_modes(struct drm_panel *panel) { struct drm_connector *connector = panel->connector; struct drm_display_mode *mode; mode = drm_mode_duplicate(panel->drm, &default_mode); if (!mode) { DRM_ERROR("failed to add mode %ux%ux@%u\n", default_mode.hdisplay, default_mode.vdisplay, default_mode.vrefresh); return -ENOMEM; } drm_mode_set_name(mode); mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode); connector->display_info.width_mm = 29; connector->display_info.height_mm = 29; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon104100.00%1100.00%
Total104100.00%1100.00%

static const struct drm_panel_funcs s6e63j0x03_funcs = { .disable = s6e63j0x03_disable, .unprepare = s6e63j0x03_unprepare, .prepare = s6e63j0x03_prepare, .enable = s6e63j0x03_enable, .get_modes = s6e63j0x03_get_modes, };
static int s6e63j0x03_probe(struct mipi_dsi_device *dsi) { struct device *dev = &dsi->dev; struct s6e63j0x03 *ctx; int ret; ctx = devm_kzalloc(dev, sizeof(struct s6e63j0x03), GFP_KERNEL); if (!ctx) return -ENOMEM; mipi_dsi_set_drvdata(dsi, ctx); ctx->dev = dev; dsi->lanes = 1; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_EOT_PACKET; ctx->supplies[0].supply = "vdd3"; ctx->supplies[1].supply = "vci"; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) { dev_err(dev, "failed to get regulators: %d\n", ret); return ret; } ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { dev_err(dev, "cannot get reset-gpio: %ld\n", PTR_ERR(ctx->reset_gpio)); return PTR_ERR(ctx->reset_gpio); } drm_panel_init(&ctx->panel); ctx->panel.dev = dev; ctx->panel.funcs = &s6e63j0x03_funcs; ctx->bl_dev = backlight_device_register("s6e63j0x03", dev, ctx, &s6e63j0x03_bl_ops, NULL); if (IS_ERR(ctx->bl_dev)) { dev_err(dev, "failed to register backlight device\n"); return PTR_ERR(ctx->bl_dev); } ctx->bl_dev->props.max_brightness = MAX_BRIGHTNESS; ctx->bl_dev->props.brightness = DEFAULT_BRIGHTNESS; ctx->bl_dev->props.power = FB_BLANK_POWERDOWN; ret = drm_panel_add(&ctx->panel); if (ret < 0) goto unregister_backlight; ret = mipi_dsi_attach(dsi); if (ret < 0) goto remove_panel; return ret; remove_panel: drm_panel_remove(&ctx->panel); unregister_backlight: backlight_device_unregister(ctx->bl_dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon349100.00%1100.00%
Total349100.00%1100.00%


static int s6e63j0x03_remove(struct mipi_dsi_device *dsi) { struct s6e63j0x03 *ctx = mipi_dsi_get_drvdata(dsi); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); backlight_device_unregister(ctx->bl_dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon44100.00%1100.00%
Total44100.00%1100.00%

static const struct of_device_id s6e63j0x03_of_match[] = { { .compatible = "samsung,s6e63j0x03" }, { } }; MODULE_DEVICE_TABLE(of, s6e63j0x03_of_match); static struct mipi_dsi_driver s6e63j0x03_driver = { .probe = s6e63j0x03_probe, .remove = s6e63j0x03_remove, .driver = { .name = "panel_samsung_s6e63j0x03", .of_match_table = s6e63j0x03_of_match, }, }; module_mipi_dsi_driver(s6e63j0x03_driver); MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); MODULE_AUTHOR("Hoegeun Kwon <hoegeun.kwon@samsung.com>"); MODULE_DESCRIPTION("MIPI-DSI based s6e63j0x03 AMOLED LCD Panel Driver"); MODULE_LICENSE("GPL v2");

Overall Contributors

PersonTokensPropCommitsCommitProp
Hoegeun Kwon2548100.00%1100.00%
Total2548100.00%1100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.