/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only 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. */ #include #include #include #include #include #include #include #include #include #include #include #include "mdss_dsi.h" #define DT_CMD_HDR 6 DEFINE_LED_TRIGGER(bl_led_trigger); static struct mdss_dsi_phy_ctrl phy_params; void mdss_dsi_panel_pwm_cfg(struct mdss_dsi_ctrl_pdata *ctrl) { int ret; if (!gpio_is_valid(ctrl->pwm_pmic_gpio)) { pr_err("%s: pwm_pmic_gpio=%d Invalid\n", __func__, ctrl->pwm_pmic_gpio); ctrl->pwm_pmic_gpio = -1; return; } ret = gpio_request(ctrl->pwm_pmic_gpio, "disp_pwm"); if (ret) { pr_err("%s: pwm_pmic_gpio=%d request failed\n", __func__, ctrl->pwm_pmic_gpio); ctrl->pwm_pmic_gpio = -1; return; } ctrl->pwm_bl = pwm_request(ctrl->pwm_lpg_chan, "lcd-bklt"); if (ctrl->pwm_bl == NULL || IS_ERR(ctrl->pwm_bl)) { pr_err("%s: lpg_chan=%d pwm request failed", __func__, ctrl->pwm_lpg_chan); gpio_free(ctrl->pwm_pmic_gpio); ctrl->pwm_pmic_gpio = -1; } } static void mdss_dsi_panel_bklt_pwm(struct mdss_dsi_ctrl_pdata *ctrl, int level) { int ret; u32 duty; if (ctrl->pwm_bl == NULL) { pr_err("%s: no PWM\n", __func__); return; } duty = level * ctrl->pwm_period; duty /= ctrl->bklt_max; pr_debug("%s: bklt_ctrl=%d pwm_period=%d pwm_gpio=%d pwm_lpg_chan=%d\n", __func__, ctrl->bklt_ctrl, ctrl->pwm_period, ctrl->pwm_pmic_gpio, ctrl->pwm_lpg_chan); pr_debug("%s: ndx=%d level=%d duty=%d\n", __func__, ctrl->ndx, level, duty); ret = pwm_config(ctrl->pwm_bl, duty, ctrl->pwm_period); if (ret) { pr_err("%s: pwm_config() failed err=%d.\n", __func__, ret); return; } ret = pwm_enable(ctrl->pwm_bl); if (ret) pr_err("%s: pwm_enable() failed err=%d\n", __func__, ret); } static char dcs_cmd[2] = {0x54, 0x00}; /* DTYPE_DCS_READ */ static struct dsi_cmd_desc dcs_read_cmd = { {DTYPE_DCS_READ, 1, 0, 1, 5, sizeof(dcs_cmd)}, dcs_cmd }; u32 mdss_dsi_dcs_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0, char cmd1) { struct dcs_cmd_req cmdreq; dcs_cmd[0] = cmd0; dcs_cmd[1] = cmd1; memset(&cmdreq, 0, sizeof(cmdreq)); cmdreq.cmds = &dcs_read_cmd; cmdreq.cmds_cnt = 1; cmdreq.flags = CMD_REQ_RX | CMD_REQ_COMMIT; cmdreq.rlen = 1; cmdreq.cb = NULL; /* call back */ mdss_dsi_cmdlist_put(ctrl, &cmdreq); /* * blocked here, until call back called */ return 0; } static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_panel_cmds *pcmds) { struct dcs_cmd_req cmdreq; memset(&cmdreq, 0, sizeof(cmdreq)); cmdreq.cmds = pcmds->cmds; cmdreq.cmds_cnt = pcmds->cmd_cnt; cmdreq.flags = CMD_REQ_COMMIT; cmdreq.rlen = 0; cmdreq.cb = NULL; mdss_dsi_cmdlist_put(ctrl, &cmdreq); } static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */ static struct dsi_cmd_desc backlight_cmd = { {DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1)}, led_pwm1 }; static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level) { struct dcs_cmd_req cmdreq; pr_debug("%s: level=%d\n", __func__, level); led_pwm1[1] = (unsigned char)level; memset(&cmdreq, 0, sizeof(cmdreq)); cmdreq.cmds = &backlight_cmd; cmdreq.cmds_cnt = 1; cmdreq.flags = CMD_REQ_COMMIT | CMD_CLK_CTRL; cmdreq.rlen = 0; cmdreq.cb = NULL; mdss_dsi_cmdlist_put(ctrl, &cmdreq); } void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) { pr_debug("%s:%d, reset line not configured\n", __func__, __LINE__); } if (!gpio_is_valid(ctrl_pdata->rst_gpio)) { pr_debug("%s:%d, reset line not configured\n", __func__, __LINE__); return; } pr_debug("%s: enable = %d\n", __func__, enable); if (enable) { gpio_set_value((ctrl_pdata->rst_gpio), 1); msleep(20); gpio_set_value((ctrl_pdata->rst_gpio), 0); udelay(200); gpio_set_value((ctrl_pdata->rst_gpio), 1); msleep(20); if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) gpio_set_value((ctrl_pdata->disp_en_gpio), 1); if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { pr_debug("%s: Panel Not properly turned OFF\n", __func__); ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; pr_debug("%s: Reset panel done\n", __func__); } } else { gpio_set_value((ctrl_pdata->rst_gpio), 0); if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) gpio_set_value((ctrl_pdata->disp_en_gpio), 0); } } static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, u32 bl_level) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); switch (ctrl_pdata->bklt_ctrl) { case BL_WLED: led_trigger_event(bl_led_trigger, bl_level); break; case BL_PWM: mdss_dsi_panel_bklt_pwm(ctrl_pdata, bl_level); break; case BL_DCS_CMD: mdss_dsi_panel_bklt_dcs(ctrl_pdata, bl_level); break; default: pr_err("%s: Unknown bl_ctrl configuration\n", __func__); break; } } static int mdss_dsi_panel_on(struct mdss_panel_data *pdata) { struct mipi_panel_info *mipi; struct mdss_dsi_ctrl_pdata *ctrl = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); mipi = &pdata->panel_info.mipi; pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx); if (ctrl->on_cmds.cmd_cnt) mdss_dsi_panel_cmds_send(ctrl, &ctrl->on_cmds); pr_debug("%s:-\n", __func__); return 0; } static int mdss_dsi_panel_off(struct mdss_panel_data *pdata) { struct mipi_panel_info *mipi; struct mdss_dsi_ctrl_pdata *ctrl = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_debug("%s: ctrl=%p ndx=%d\n", __func__, ctrl, ctrl->ndx); mipi = &pdata->panel_info.mipi; if (ctrl->off_cmds.cmd_cnt) mdss_dsi_panel_cmds_send(ctrl, &ctrl->off_cmds); pr_debug("%s:-\n", __func__); return 0; } static int mdss_dsi_parse_dcs_cmds(struct device_node *np, struct dsi_panel_cmds *pcmds, char *cmd_key, char *link_key) { const char *data; int blen = 0, len; char *buf, *bp; struct dsi_ctrl_hdr *dchdr; int i, cnt; data = of_get_property(np, cmd_key, &blen); if (!data) { pr_err("%s: failed, key=%s\n", __func__, cmd_key); return -ENOMEM; } buf = kzalloc(sizeof(char) * blen, GFP_KERNEL); if (!buf) return -ENOMEM; memcpy(buf, data, blen); /* scan dcs commands */ bp = buf; len = blen; cnt = 0; while (len > sizeof(*dchdr)) { dchdr = (struct dsi_ctrl_hdr *)bp; dchdr->dlen = ntohs(dchdr->dlen); if (dchdr->dlen > len) { pr_err("%s: dtsi cmd=%x error, len=%d", __func__, dchdr->dtype, dchdr->dlen); return -ENOMEM; } bp += sizeof(*dchdr); len -= sizeof(*dchdr); bp += dchdr->dlen; len -= dchdr->dlen; cnt++; } if (len != 0) { pr_err("%s: dcs_cmd=%x len=%d error!", __func__, buf[0], blen); kfree(buf); return -ENOMEM; } pcmds->cmds = kzalloc(cnt * sizeof(struct dsi_cmd_desc), GFP_KERNEL); if (!pcmds->cmds) return -ENOMEM; pcmds->cmd_cnt = cnt; pcmds->buf = buf; pcmds->blen = blen; bp = buf; len = blen; for (i = 0; i < cnt; i++) { dchdr = (struct dsi_ctrl_hdr *)bp; len -= sizeof(*dchdr); bp += sizeof(*dchdr); pcmds->cmds[i].dchdr = *dchdr; pcmds->cmds[i].payload = bp; bp += dchdr->dlen; len -= dchdr->dlen; } pcmds->link_state = DSI_LP_MODE; /* default */ data = of_get_property(np, link_key, NULL); if (!strncmp(data, "DSI_HS_MODE", 11)) pcmds->link_state = DSI_HS_MODE; pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__, pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state); return 0; } static int mdss_panel_parse_dt(struct platform_device *pdev, struct mdss_panel_common_pdata *panel_data) { struct device_node *np = pdev->dev.of_node; u32 res[6], tmp; u32 fbc_res[7]; int rc, i, len; const char *data; static const char *bl_ctrl_type, *pdest; bool fbc_enabled = false; rc = of_property_read_u32_array(np, "qcom,mdss-pan-res", res, 2); if (rc) { pr_err("%s:%d, panel resolution not specified\n", __func__, __LINE__); return -EINVAL; } panel_data->panel_info.xres = (!rc ? res[0] : 640); panel_data->panel_info.yres = (!rc ? res[1] : 480); rc = of_property_read_u32_array(np, "qcom,mdss-pan-active-res", res, 2); if (rc == 0) { panel_data->panel_info.lcdc.xres_pad = panel_data->panel_info.xres - res[0]; panel_data->panel_info.lcdc.yres_pad = panel_data->panel_info.yres - res[1]; } rc = of_property_read_u32(np, "qcom,mdss-pan-bpp", &tmp); if (rc) { pr_err("%s:%d, panel bpp not specified\n", __func__, __LINE__); return -EINVAL; } panel_data->panel_info.bpp = (!rc ? tmp : 24); pdest = of_get_property(pdev->dev.of_node, "qcom,mdss-pan-dest", NULL); if (strlen(pdest) != 9) { pr_err("%s: Unknown pdest specified\n", __func__); return -EINVAL; } if (!strncmp(pdest, "display_1", 9)) panel_data->panel_info.pdest = DISPLAY_1; else if (!strncmp(pdest, "display_2", 9)) panel_data->panel_info.pdest = DISPLAY_2; else { pr_debug("%s: pdest not specified. Set Default\n", __func__); panel_data->panel_info.pdest = DISPLAY_1; } rc = of_property_read_u32_array(np, "qcom,mdss-pan-porch-values", res, 6); panel_data->panel_info.lcdc.h_back_porch = (!rc ? res[0] : 6); panel_data->panel_info.lcdc.h_pulse_width = (!rc ? res[1] : 2); panel_data->panel_info.lcdc.h_front_porch = (!rc ? res[2] : 6); panel_data->panel_info.lcdc.v_back_porch = (!rc ? res[3] : 6); panel_data->panel_info.lcdc.v_pulse_width = (!rc ? res[4] : 2); panel_data->panel_info.lcdc.v_front_porch = (!rc ? res[5] : 6); rc = of_property_read_u32(np, "qcom,mdss-pan-underflow-clr", &tmp); panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff); bl_ctrl_type = of_get_property(pdev->dev.of_node, "qcom,mdss-pan-bl-ctrl", NULL); if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type, "bl_ctrl_wled", 12))) { led_trigger_register_simple("bkl-trigger", &bl_led_trigger); pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__); panel_data->panel_info.bklt_ctrl = BL_WLED; } else if (!strncmp(bl_ctrl_type, "bl_ctrl_pwm", 11)) { panel_data->panel_info.bklt_ctrl = BL_PWM; rc = of_property_read_u32(np, "qcom,pwm-period", &tmp); if (rc) { pr_err("%s:%d, Error, panel pwm_period\n", __func__, __LINE__); return -EINVAL; } panel_data->panel_info.pwm_period = tmp; rc = of_property_read_u32(np, "qcom,pwm-lpg-channel", &tmp); if (rc) { pr_err("%s:%d, Error, dsi lpg channel\n", __func__, __LINE__); return -EINVAL; } panel_data->panel_info.pwm_lpg_chan = tmp; tmp = of_get_named_gpio(np, "qcom,pwm-pmic-gpio", 0); panel_data->panel_info.pwm_pmic_gpio = tmp; } else if (!strncmp(bl_ctrl_type, "bl_ctrl_dcs", 11)) { panel_data->panel_info.bklt_ctrl = BL_DCS_CMD; } else { pr_debug("%s: Unknown backlight control\n", __func__); panel_data->panel_info.bklt_ctrl = UNKNOWN_CTRL; } rc = of_property_read_u32_array(np, "qcom,mdss-pan-bl-levels", res, 2); panel_data->panel_info.bl_min = (!rc ? res[0] : 0); panel_data->panel_info.bl_max = (!rc ? res[1] : 255); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mode", &tmp); panel_data->panel_info.mipi.mode = (!rc ? tmp : DSI_VIDEO_MODE); rc = of_property_read_u32(np, "qcom,mdss-vsync-enable", &tmp); panel_data->panel_info.mipi.vsync_enable = (!rc ? tmp : 0); rc = of_property_read_u32(np, "qcom,mdss-hw-vsync-mode", &tmp); panel_data->panel_info.mipi.hw_vsync_mode = (!rc ? tmp : 0); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-h-pulse-mode", &tmp); panel_data->panel_info.mipi.pulse_mode_hsa_he = (!rc ? tmp : false); rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-h-power-stop", res, 3); panel_data->panel_info.mipi.hbp_power_stop = (!rc ? res[0] : false); panel_data->panel_info.mipi.hsa_power_stop = (!rc ? res[1] : false); panel_data->panel_info.mipi.hfp_power_stop = (!rc ? res[2] : false); rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-bllp-power-stop", res, 2); panel_data->panel_info.mipi.bllp_power_stop = (!rc ? res[0] : false); panel_data->panel_info.mipi.eof_bllp_power_stop = (!rc ? res[1] : false); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-traffic-mode", &tmp); panel_data->panel_info.mipi.traffic_mode = (!rc ? tmp : DSI_NON_BURST_SYNCH_PULSE); rc = of_property_read_u32(np, "qcom,mdss-pan-insert-dcs-cmd", &tmp); panel_data->panel_info.mipi.insert_dcs_cmd = (!rc ? tmp : 1); rc = of_property_read_u32(np, "qcom,mdss-pan-wr-mem-continue", &tmp); panel_data->panel_info.mipi.wr_mem_continue = (!rc ? tmp : 0x3c); rc = of_property_read_u32(np, "qcom,mdss-pan-wr-mem-start", &tmp); panel_data->panel_info.mipi.wr_mem_start = (!rc ? tmp : 0x2c); rc = of_property_read_u32(np, "qcom,mdss-pan-te-sel", &tmp); panel_data->panel_info.mipi.te_sel = (!rc ? tmp : 1); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dst-format", &tmp); panel_data->panel_info.mipi.dst_format = (!rc ? tmp : DSI_VIDEO_DST_FORMAT_RGB888); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-vc", &tmp); panel_data->panel_info.mipi.vc = (!rc ? tmp : 0); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-rgb-swap", &tmp); panel_data->panel_info.mipi.rgb_swap = (!rc ? tmp : DSI_RGB_SWAP_RGB); rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-data-lanes", res, 4); panel_data->panel_info.mipi.data_lane0 = (!rc ? res[0] : true); panel_data->panel_info.mipi.data_lane1 = (!rc ? res[1] : false); panel_data->panel_info.mipi.data_lane2 = (!rc ? res[2] : false); panel_data->panel_info.mipi.data_lane3 = (!rc ? res[3] : false); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dlane-swap", &tmp); panel_data->panel_info.mipi.dlane_swap = (!rc ? tmp : 0); rc = of_property_read_u32_array(np, "qcom,mdss-pan-dsi-t-clk", res, 2); panel_data->panel_info.mipi.t_clk_pre = (!rc ? res[0] : 0x24); panel_data->panel_info.mipi.t_clk_post = (!rc ? res[1] : 0x03); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-stream", &tmp); panel_data->panel_info.mipi.stream = (!rc ? tmp : 0); rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-mdp-tr", &tmp); panel_data->panel_info.mipi.mdp_trigger = (!rc ? tmp : DSI_CMD_TRIGGER_SW); if (panel_data->panel_info.mipi.mdp_trigger > 6) { pr_err("%s:%d, Invalid mdp trigger. Forcing to sw trigger", __func__, __LINE__); panel_data->panel_info.mipi.mdp_trigger = DSI_CMD_TRIGGER_SW; } rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-dma-tr", &tmp); panel_data->panel_info.mipi.dma_trigger = (!rc ? tmp : DSI_CMD_TRIGGER_SW); if (panel_data->panel_info.mipi.dma_trigger > 6) { pr_err("%s:%d, Invalid dma trigger. Forcing to sw trigger", __func__, __LINE__); panel_data->panel_info.mipi.dma_trigger = DSI_CMD_TRIGGER_SW; } rc = of_property_read_u32(np, "qcom,mdss-pan-dsi-frame-rate", &tmp); panel_data->panel_info.mipi.frame_rate = (!rc ? tmp : 60); rc = of_property_read_u32(np, "qcom,mdss-pan-clk-rate", &tmp); panel_data->panel_info.clk_rate = (!rc ? tmp : 0); data = of_get_property(np, "qcom,panel-phy-regulatorSettings", &len); if ((!data) || (len != 7)) { pr_err("%s:%d, Unable to read Phy regulator settings", __func__, __LINE__); goto error; } for (i = 0; i < len; i++) phy_params.regulator[i] = data[i]; data = of_get_property(np, "qcom,panel-phy-timingSettings", &len); if ((!data) || (len != 12)) { pr_err("%s:%d, Unable to read Phy timing settings", __func__, __LINE__); goto error; } for (i = 0; i < len; i++) phy_params.timing[i] = data[i]; data = of_get_property(np, "qcom,panel-phy-strengthCtrl", &len); if ((!data) || (len != 2)) { pr_err("%s:%d, Unable to read Phy Strength ctrl settings", __func__, __LINE__); goto error; } phy_params.strength[0] = data[0]; phy_params.strength[1] = data[1]; data = of_get_property(np, "qcom,panel-phy-bistCtrl", &len); if ((!data) || (len != 6)) { pr_err("%s:%d, Unable to read Phy Bist Ctrl settings", __func__, __LINE__); goto error; } for (i = 0; i < len; i++) phy_params.bistCtrl[i] = data[i]; data = of_get_property(np, "qcom,panel-phy-laneConfig", &len); if ((!data) || (len != 45)) { pr_err("%s:%d, Unable to read Phy lane configure settings", __func__, __LINE__); goto error; } for (i = 0; i < len; i++) phy_params.laneCfg[i] = data[i]; panel_data->panel_info.mipi.dsi_phy_db = &phy_params; fbc_enabled = of_property_read_bool(np, "qcom,fbc-enabled"); if (fbc_enabled) { pr_debug("%s:%d FBC panel enabled.\n", __func__, __LINE__); panel_data->panel_info.fbc.enabled = 1; rc = of_property_read_u32_array(np, "qcom,fbc-mode", fbc_res, 7); panel_data->panel_info.fbc.target_bpp = (!rc ? fbc_res[0] : panel_data->panel_info.bpp); panel_data->panel_info.fbc.comp_mode = (!rc ? fbc_res[1] : 0); panel_data->panel_info.fbc.qerr_enable = (!rc ? fbc_res[2] : 0); panel_data->panel_info.fbc.cd_bias = (!rc ? fbc_res[3] : 0); panel_data->panel_info.fbc.pat_enable = (!rc ? fbc_res[4] : 0); panel_data->panel_info.fbc.vlc_enable = (!rc ? fbc_res[5] : 0); panel_data->panel_info.fbc.bflc_enable = (!rc ? fbc_res[6] : 0); rc = of_property_read_u32_array(np, "qcom,fbc-budget-ctl", fbc_res, 3); panel_data->panel_info.fbc.line_x_budget = (!rc ? fbc_res[0] : 0); panel_data->panel_info.fbc.block_x_budget = (!rc ? fbc_res[1] : 0); panel_data->panel_info.fbc.block_budget = (!rc ? fbc_res[2] : 0); rc = of_property_read_u32_array(np, "qcom,fbc-lossy-mode", fbc_res, 4); panel_data->panel_info.fbc.lossless_mode_thd = (!rc ? fbc_res[0] : 0); panel_data->panel_info.fbc.lossy_mode_thd = (!rc ? fbc_res[1] : 0); panel_data->panel_info.fbc.lossy_rgb_thd = (!rc ? fbc_res[2] : 0); panel_data->panel_info.fbc.lossy_mode_idx = (!rc ? fbc_res[3] : 0); } else { pr_debug("%s:%d Panel does not support FBC.\n", __func__, __LINE__); panel_data->panel_info.fbc.enabled = 0; panel_data->panel_info.fbc.target_bpp = panel_data->panel_info.bpp; } mdss_dsi_parse_dcs_cmds(np, &panel_data->on_cmds, "qcom,panel-on-cmds", "qcom,on-cmds-dsi-state"); mdss_dsi_parse_dcs_cmds(np, &panel_data->off_cmds, "qcom,panel-off-cmds", "qcom,off-cmds-dsi-state"); return 0; error: return -EINVAL; } 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; pr_debug("%s:%d, debug info id=%d", __func__, __LINE__, pdev->id); if (!pdev->dev.of_node) return -ENODEV; panel_name = of_get_property(pdev->dev.of_node, "label", NULL); if (!panel_name) pr_info("%s:%d, panel name not specified\n", __func__, __LINE__); else pr_info("%s: Panel Name = %s\n", __func__, panel_name); rc = mdss_panel_parse_dt(pdev, &vendor_pdata); if (rc) return rc; vendor_pdata.on = mdss_dsi_panel_on; vendor_pdata.off = mdss_dsi_panel_off; vendor_pdata.bl_fnc = mdss_dsi_panel_bl_ctrl; rc = dsi_panel_device_register(pdev, &vendor_pdata); if (rc) return rc; return 0; } static const struct of_device_id mdss_dsi_panel_match[] = { {.compatible = "qcom,mdss-dsi-panel"}, {} }; static struct platform_driver this_driver = { .probe = mdss_dsi_panel_probe, .driver = { .name = "dsi_panel", .of_match_table = mdss_dsi_panel_match, }, }; static int __init mdss_dsi_panel_init(void) { return platform_driver_register(&this_driver); } module_init(mdss_dsi_panel_init);