Created
February 23, 2014 19:14
-
-
Save axsddlr/9175821 to your computer and use it in GitHub Desktop.
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
From aba17bad720d05543aaca27bf0364370a06390f8 Mon Sep 17 00:00:00 2001 | |
From: myfluxi <[email protected]> | |
Date: Sun, 23 Feb 2014 07:19:12 -0500 | |
Subject: [PATCH] msm: mdss: Display gamma control | |
TODO: confirm rgb channels, identify other tunables, cleanup, | |
apply values without switching screen (off and) on. | |
sysfs: /sys/devices/qcom,mdss_dsi_jdi_command_ors.69/* | |
msm: mdss: Find a stable sysfs node for the gamma interface | |
Move sysfs files to /sys/module/dsi_panel/* | |
msm: mdss: Use workqueue to send panel commands | |
Sending panel commands is known to be expensive, honor this by | |
scheduling this task. Also check for panel state and send commands | |
only when we're actually awake. | |
These fixes adress bug reports regarding behaviour during boot. | |
msm: mdss: Add hardware revision check | |
Our gamma interface works with both current hardware revisions, | |
11 and 11j, although all testing was carried out on 11. As we | |
don't know about possible future revisions, let's bail out until | |
correct offsets for panel commands have been added. | |
Signed-off-by: Paul Reioux <[email protected]> | |
msm: mdss: Send panel commands via separate function | |
Sending panel comnmands is very expensive, add a separate function to | |
accomplish this. Once all commands have been stored write anything to | |
the kgamma_send file. | |
msm: mdss: Finalize gamma interface and cleanup | |
- Remove all sysfs files of unused commands | |
- Remove auto sync for negative polarities, these must be written separately | |
- Protect offset bit of white point command as well | |
- Apply white point bit 2 as duplicate of bit 1 | |
msm: mdss: Add safety check for user input | |
Leave more checks either to the control app or the user's intelligence. | |
msm: mdss: Identify white point in sysfs | |
msm: mdss: Remove sysfs for unused commands | |
msm: mdss: distinguish between Gamma RGB polarity Positive/Negative | |
Signed-off-by: Paul Reioux <[email protected]> | |
msm: mdss: Remove tunable for command 32 | |
Even slight changes look ugly or distort the screen. | |
msm: mdss: Apply commands values without switching screen (off and) on | |
--- | |
drivers/video/msm/mdss/mdss_dsi.c | 3 + | |
drivers/video/msm/mdss/mdss_dsi_panel.c | 217 +++++++++++++++++++++++++++++++- | |
2 files changed, 218 insertions(+), 2 deletions(-) | |
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c | |
index d6d6b02..74c827a 100644 | |
--- a/drivers/video/msm/mdss/mdss_dsi.c | |
+++ b/drivers/video/msm/mdss/mdss_dsi.c | |
@@ -37,6 +37,7 @@ static unsigned char *mdss_dsi_base; | |
static int mdss_dsi_use_vdd_supply; | |
static u32 mdss_dsi_bit_rate; | |
extern struct mdss_panel_data *pdata_base; | |
+extern struct mdss_panel_data *cmds_panel_data; | |
#endif | |
static int mdss_dsi_regulator_init(struct platform_device *pdev) | |
@@ -294,6 +295,8 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable) | |
panel_data); | |
pr_debug("%s: enable=%d\n", __func__, enable); | |
+ cmds_panel_data = pdata; | |
+ | |
if (enable) { | |
if (ctrl_pdata->power_data.num_vreg > 0) { | |
ret = msm_dss_enable_vreg( | |
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c | |
index 6b39c33..403fdb1 100644 | |
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c | |
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c | |
@@ -31,9 +31,13 @@ | |
#include <linux/err.h> | |
#endif | |
+#include <asm/system_info.h> | |
+ | |
#include "mdss_dsi.h" | |
#define DT_CMD_HDR 6 | |
+#define GAMMA_COMPAT 11 | |
+ | |
#ifdef CONFIG_LGE_LCD_TUNING | |
#define TUNING_REGSIZE 400 | |
#endif | |
@@ -87,6 +91,11 @@ extern int mdss_dsi_off(struct mdss_panel_data *pdata); | |
#endif | |
static struct mdss_dsi_phy_ctrl phy_params; | |
+static struct mdss_panel_common_pdata *local_pdata; | |
+static struct work_struct send_cmds_work; | |
+struct mdss_panel_data *cmds_panel_data; | |
+static struct platform_driver this_driver; | |
+struct kobject *module_kobj; | |
#ifdef CONFIG_LGE_SUPPORT_LCD_MAKER_ID | |
int g_mvol_for_lcd; | |
@@ -455,7 +464,8 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) | |
tun_dsi_panel_on_cmds, | |
num_of_on_cmds); | |
#else | |
- mdss_dsi_panel_cmds_send(ctrl, &ctrl->on_cmds); | |
+ if (local_pdata->on_cmds.cmd_cnt) | |
+ mdss_dsi_panel_cmds_send(ctrl, &local_pdata->on_cmds); | |
#ifdef CONFIG_OLED_SUPPORT | |
mdss_dsi_panel_img_tune_apply(IMG_TUNE_COUNT); | |
@@ -1187,11 +1197,198 @@ struct syscore_ops panel_syscore_ops = { | |
}; | |
#endif | |
+static int read_local_on_cmds(char *buf, size_t cmd) | |
+{ | |
+ int i, len = 0; | |
+ int dlen; | |
+ | |
+ if (system_rev != GAMMA_COMPAT) { | |
+ pr_err("Incompatible hardware revision: %d\n", system_rev); | |
+ return -EINVAL; | |
+ } | |
+ | |
+ dlen = local_pdata->on_cmds.cmds[cmd].dchdr.dlen - 1; | |
+ if (!dlen) | |
+ return -ENOMEM; | |
+ | |
+ /* don't print first and last bits */ | |
+ for (i = 1; i < dlen; i++) | |
+ len += sprintf(buf + len, "%d ", | |
+ local_pdata->on_cmds.cmds[cmd].payload[i]); | |
+ | |
+ len += sprintf(buf + len, "\n"); | |
+ | |
+ return len; | |
+} | |
+ | |
+static unsigned int cnt; | |
+ | |
+static int write_local_on_cmds(struct device *dev, const char *buf, | |
+ size_t cmd) | |
+{ | |
+ int i, rc = 0; | |
+ int dlen; | |
+ unsigned int val; | |
+ char tmp[3]; | |
+ struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
+ struct mdss_panel_common_pdata *prev_local_data; | |
+ | |
+ if (cnt) { | |
+ cnt = 0; | |
+ return -EINVAL; | |
+ } | |
+ | |
+ if (system_rev != GAMMA_COMPAT) { | |
+ pr_err("Incompatible hardware revision: %d\n", system_rev); | |
+ return -EINVAL; | |
+ } | |
+ | |
+ if (cmds_panel_data == NULL) { | |
+ pr_err("%s: Invalid input data\n", __func__); | |
+ return -EINVAL; | |
+ } | |
+ | |
+ ctrl = container_of(cmds_panel_data, struct mdss_dsi_ctrl_pdata, | |
+ panel_data); | |
+ | |
+ /* | |
+ * Last bit is not written because it's either fixed at 0x00 for | |
+ * RGB or a duplicate of the previous bit for the white point. | |
+ */ | |
+ dlen = local_pdata->on_cmds.cmds[cmd].dchdr.dlen - 1; | |
+ if (!dlen) | |
+ return -EINVAL; | |
+ | |
+ prev_local_data = local_pdata; | |
+ | |
+ for (i = 1; i < dlen; i++) { | |
+ rc = sscanf(buf, "%u", &val); | |
+ if (rc != 1) | |
+ return -EINVAL; | |
+ | |
+ if (val > 255) { | |
+ pr_err("%s: Invalid input data %u (0-255)\n", __func__, val); | |
+ local_pdata = prev_local_data; | |
+ return -EINVAL; | |
+ } | |
+ | |
+ local_pdata->on_cmds.cmds[cmd].payload[i] = val; | |
+ /* white point value must be duplicated */ | |
+ if (cmd == 5) | |
+ local_pdata->on_cmds.cmds[cmd].payload[i + 1] = val; | |
+ | |
+ sscanf(buf, "%s", tmp); | |
+ buf += strlen(tmp) + 1; | |
+ cnt = strlen(tmp); | |
+ } | |
+ | |
+ pr_info("%s\n", __func__); | |
+ | |
+ return rc; | |
+} | |
+ | |
+static void send_local_on_cmds(struct work_struct *work) | |
+{ | |
+ struct mdss_dsi_ctrl_pdata *ctrl = NULL; | |
+ | |
+ if (cmds_panel_data == NULL) { | |
+ pr_err("%s: Invalid input data\n", __func__); | |
+ return; | |
+ } | |
+ | |
+ ctrl = container_of(cmds_panel_data, struct mdss_dsi_ctrl_pdata, | |
+ panel_data); | |
+ | |
+ if (local_pdata->on_cmds.cmd_cnt) | |
+ mdss_dsi_panel_cmds_send(ctrl, &local_pdata->on_cmds); | |
+ | |
+ pr_info("%s\n", __func__); | |
+} | |
+ | |
+/************************** sysfs interface ************************/ | |
+ | |
+static ssize_t write_kgamma_send(struct device *dev, | |
+ struct device_attribute *attr, | |
+ const char *buf, size_t count) | |
+{ | |
+ if (!cmds_panel_data->panel_info.panel_power_on) { | |
+ pr_err("%s: Panel off, failed to send commands\n", __func__); | |
+ return -EPERM; | |
+ } | |
+ | |
+ schedule_work(&send_cmds_work); | |
+ | |
+ return count; | |
+} | |
+ | |
+static DEVICE_ATTR(kgamma_send, 0644, NULL, write_kgamma_send); | |
+ | |
+#define read_one(file_name, cmd) \ | |
+static ssize_t read_##file_name \ | |
+(struct device *dev, struct device_attribute *attr, char *buf) \ | |
+{ \ | |
+ return read_local_on_cmds(buf, cmd); \ | |
+} | |
+ | |
+read_one(kgamma_w, 5); | |
+read_one(kgamma_rp, 7); | |
+read_one(kgamma_rn, 9); | |
+read_one(kgamma_gp, 11); | |
+read_one(kgamma_gn, 13); | |
+read_one(kgamma_bp, 15); | |
+read_one(kgamma_bn, 17); | |
+ | |
+#define write_one(file_name, cmd) \ | |
+static ssize_t write_##file_name \ | |
+(struct device *dev, struct device_attribute *attr, \ | |
+ const char *buf, size_t count) \ | |
+{ \ | |
+ return write_local_on_cmds(dev, buf, cmd); \ | |
+} | |
+ | |
+write_one(kgamma_w, 5); | |
+write_one(kgamma_rp, 7); | |
+write_one(kgamma_rn, 9); | |
+write_one(kgamma_gp, 11); | |
+write_one(kgamma_gn, 13); | |
+write_one(kgamma_bp, 15); | |
+write_one(kgamma_bn, 17); | |
+ | |
+#define define_one_rw(_name) \ | |
+static DEVICE_ATTR(_name, 0644, read_##_name, write_##_name); | |
+ | |
+define_one_rw(kgamma_w); | |
+define_one_rw(kgamma_rp); | |
+define_one_rw(kgamma_rn); | |
+define_one_rw(kgamma_gp); | |
+define_one_rw(kgamma_gn); | |
+define_one_rw(kgamma_bp); | |
+define_one_rw(kgamma_bn); | |
+ | |
+static struct attribute *dsi_panel_attributes[] = { | |
+ &dev_attr_kgamma_w.attr, | |
+ &dev_attr_kgamma_rp.attr, | |
+ &dev_attr_kgamma_rn.attr, | |
+ &dev_attr_kgamma_gp.attr, | |
+ &dev_attr_kgamma_gn.attr, | |
+ &dev_attr_kgamma_bp.attr, | |
+ &dev_attr_kgamma_bn.attr, | |
+ &dev_attr_kgamma_send.attr, | |
+ NULL | |
+}; | |
+ | |
+static struct attribute_group dsi_panel_attribute_group = { | |
+ .attrs = dsi_panel_attributes, | |
+}; | |
+ | |
+/**************************** sysfs end **************************/ | |
+ | |
static int __devinit mdss_dsi_panel_probe(struct platform_device *pdev) | |
{ | |
int rc = 0; | |
static struct mdss_panel_common_pdata vendor_pdata; | |
static const char *panel_name; | |
+ const char *driver_name = this_driver.driver.name; | |
#ifdef CONFIG_LGE_SUPPORT_LCD_MAKER_ID | |
struct class *panel; | |
@@ -1259,7 +1456,23 @@ static int __devinit mdss_dsi_panel_probe(struct platform_device *pdev) | |
pr_info("panel maker ID is %d\n", lge_get_panel_maker()); | |
#endif | |
- return 0; | |
+ INIT_WORK(&send_cmds_work, send_local_on_cmds); | |
+ | |
+ local_pdata = &vendor_pdata; | |
+ if (!local_pdata) | |
+ return -EINVAL; | |
+ | |
+ module_kobj = kobject_create_and_add(driver_name, &module_kset->kobj); | |
+ if (!module_kobj) { | |
+ pr_err("%s: kobject create failed\n", driver_name); | |
+ return -ENOMEM; | |
+ } | |
+ | |
+ rc = sysfs_create_group(module_kobj, &dsi_panel_attribute_group); | |
+ if (rc) | |
+ pr_err("%s: sysfs create failed: %d\n", panel_name, rc); | |
+ | |
+ return rc; | |
} | |
static const struct of_device_id mdss_dsi_panel_match[] = { | |
-- | |
1.9.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment