msm: Bringup 2 instances of ADV7533 for 8996

Bringup 2 instances of ADV7533 for 8996. Change all register writes
from constant to pdata variables. Move the DBA init from
mdss_dsi.c to mdss_dsi_panel.c.

Change-Id: Ib0fc9f7c2348efa04a44bc021cb50973e90d7f22
Signed-off-by: Siddharth Zaveri <szaveri@codeaurora.org>
[cip@codeaurora.org: Removed spurious drivers/video/msm/Makefile change]
Signed-off-by: Clarence Ip <cip@codeaurora.org>
This commit is contained in:
Siddharth Zaveri 2015-10-13 17:14:05 -04:00 committed by David Keitel
parent 8acce572a5
commit 4698f91320
8 changed files with 533 additions and 428 deletions

View file

@ -2051,249 +2051,6 @@ int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
return 0;
}
static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_drvdata_from_panel_data(
struct mdss_panel_data *mpd)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
if (!mpd) {
pr_err("%s: Invalid panel data\n", __func__);
goto end;
}
ctrl_pdata = container_of(mpd, struct mdss_dsi_ctrl_pdata,
panel_data);
end:
return ctrl_pdata;
}
static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_drvdata_from_sysfs_dev(
struct device *device)
{
struct msm_fb_data_type *mfd = NULL;
struct mdss_panel_data *panel_data = NULL;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct fb_info *fbi;
if (!device) {
pr_err("%s: Invalid device data\n", __func__);
goto end;
}
fbi = dev_get_drvdata(device);
if (!fbi) {
pr_err("%s: Invalid fbi data\n", __func__);
goto end;
}
mfd = (struct msm_fb_data_type *)fbi->par;
if (!mfd) {
pr_err("%s: Invalid mfd data\n", __func__);
goto end;
}
panel_data = dev_get_platdata(&mfd->pdev->dev);
if (!panel_data) {
pr_err("%s: Invalid panel data\n", __func__);
goto end;
}
ctrl_pdata = mdss_dsi_get_drvdata_from_panel_data(panel_data);
end:
return ctrl_pdata;
}
static ssize_t mdss_dsi_sysfs_rda_connected(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
if (!dev) {
DEV_ERR("%s: invalid device\n", __func__);
return -EINVAL;
}
ctrl_pdata = mdss_dsi_get_drvdata_from_sysfs_dev(dev);
if (!ctrl_pdata) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
ret = snprintf(buf, PAGE_SIZE, "%d\n", ctrl_pdata->hpd_state);
pr_debug("%s: '%d'\n", __func__, ctrl_pdata->hpd_state);
return ret;
}
static DEVICE_ATTR(connected, S_IRUGO, mdss_dsi_sysfs_rda_connected, NULL);
static struct attribute *mdss_dsi_fs_attrs[] = {
&dev_attr_connected.attr,
NULL,
};
static struct attribute_group mdss_dsi_fs_attrs_group = {
.attrs = mdss_dsi_fs_attrs,
};
static int mdss_dsi_sysfs_create(struct kobject *kobj)
{
int rc;
if (!kobj) {
DEV_ERR("%s: invalid input\n", __func__);
return -ENODEV;
}
rc = sysfs_create_group(kobj, &mdss_dsi_fs_attrs_group);
if (rc) {
pr_err("%s: failed, rc=%d\n", __func__, rc);
return rc;
}
return 0;
}
static inline void mdss_dsi_send_cable_notification(
struct mdss_dsi_ctrl_pdata *ctrl_pdata, int val)
{
int state = 0;
if (!ctrl_pdata) {
DEV_ERR("%s: invalid input\n", __func__);
return;
}
state = ctrl_pdata->sdev.state;
switch_set_state(&ctrl_pdata->sdev, val);
DEV_INFO("%s: cable state %s %d\n", __func__,
ctrl_pdata->sdev.state == state ?
"is same" : "switched to",
ctrl_pdata->sdev.state);
}
static void mdss_dsi_dba_cb(void *data, enum msm_dba_callback_event event)
{
int ret = -EINVAL;
struct mdss_dsi_ctrl_pdata *ctrl_pdata =
(struct mdss_dsi_ctrl_pdata *) data;
if (!ctrl_pdata) {
pr_err("%s: Invalid data\n", __func__);
return;
}
switch (event) {
case MSM_DBA_CB_HPD_CONNECT:
ctrl_pdata->hpd_state = true;
if (ctrl_pdata->dba_ops.get_raw_edid)
ret = ctrl_pdata->dba_ops.get_raw_edid(
ctrl_pdata->dba_data,
sizeof(ctrl_pdata->edid_buf),
ctrl_pdata->edid_buf, 0);
if (!ret)
hdmi_edid_parser(ctrl_pdata->edid_data);
mdss_dsi_send_cable_notification(ctrl_pdata, 1);
break;
case MSM_DBA_CB_HPD_DISCONNECT:
mdss_dsi_send_cable_notification(ctrl_pdata, 0);
ctrl_pdata->hpd_state = false;
break;
default:
break;
}
}
static void mdss_dsi_ctrl_init_dba(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
struct hdmi_edid_init_data edid_init_data;
struct fb_info *fbi;
msm_dba_cb dba_cb = mdss_dsi_dba_cb;
if (!ctrl_pdata) {
pr_err("%s: Invalid ctrl data\n", __func__);
goto end;
}
fbi = ctrl_pdata->fbi;
if (!fbi) {
pr_err("%s: Invalid fbi data\n", __func__);
goto end;
}
strlcpy(ctrl_pdata->dba_info.client_name, "dsi",
MSM_DBA_CLIENT_NAME_LEN);
strlcpy(ctrl_pdata->dba_info.chip_name, "adv7533",
MSM_DBA_CHIP_NAME_MAX_LEN);
ctrl_pdata->dba_info.instance_id = 0;
ctrl_pdata->dba_info.cb = dba_cb;
ctrl_pdata->dba_info.cb_data = ctrl_pdata;
ctrl_pdata->dba_data = msm_dba_register_client(
&ctrl_pdata->dba_info,
&ctrl_pdata->dba_ops);
if (IS_ERR_OR_NULL(ctrl_pdata->dba_data)) {
pr_err("%s: ds not configured\n", __func__);
goto end;
}
if (mdss_dsi_sysfs_create(&fbi->dev->kobj)) {
pr_err("%s:sysfs creation failed\n",
__func__);
goto end;
}
ctrl_pdata->sdev.name = "dsi";
if (switch_dev_register(&ctrl_pdata->sdev) < 0) {
pr_err("%s: DSI switch registration failed\n",
__func__);
goto end;
}
/* Initialize EDID feature */
edid_init_data.kobj = &fbi->dev->kobj;
edid_init_data.ds_data = NULL;
ctrl_pdata->edid_data = hdmi_edid_init(&edid_init_data);
if (!ctrl_pdata->edid_data) {
pr_err("%s: edid parser init failed\n", __func__);
goto end;
}
if (ctrl_pdata->dba_ops.power_on)
ctrl_pdata->dba_ops.power_on(ctrl_pdata->dba_data,
true, 0);
ctrl_pdata->ds_registered = true;
end:
return;
}
static void mdss_dsi_dba_work(struct work_struct *work)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct delayed_work *dw = to_delayed_work(work);
ctrl_pdata = container_of(dw, struct mdss_dsi_ctrl_pdata, dba_work);
if (!ctrl_pdata) {
pr_err("%s: invalid ctrl data\n", __func__);
return;
}
mdss_dsi_ctrl_init_dba(ctrl_pdata);
}
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
@ -2414,11 +2171,6 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
break;
case MDSS_EVENT_FB_REGISTERED:
mdss_dsi_debugfs_init(ctrl_pdata);
ctrl_pdata->fbi = (struct fb_info *)arg;
queue_delayed_work(ctrl_pdata->workq, &ctrl_pdata->dba_work,
HZ);
break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
@ -2600,7 +2352,8 @@ exit:
return dsi_pan_node;
}
static struct device_node *mdss_dsi_config_panel(struct platform_device *pdev)
static struct device_node *mdss_dsi_config_panel(struct platform_device *pdev,
int ndx)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev);
char panel_cfg[MDSS_MAX_PANEL_LEN];
@ -2627,7 +2380,7 @@ static struct device_node *mdss_dsi_config_panel(struct platform_device *pdev)
return NULL;
}
rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata);
rc = mdss_dsi_panel_init(dsi_pan_node, ctrl_pdata, ndx);
if (rc) {
pr_err("%s: dsi panel init failed\n", __func__);
of_node_put(dsi_pan_node);
@ -2857,7 +2610,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev)
return -EPERM;
}
dsi_pan_node = mdss_dsi_config_panel(pdev);
dsi_pan_node = mdss_dsi_config_panel(pdev, index);
if (!dsi_pan_node) {
pr_err("%s: panel configuration failed\n", __func__);
return -EINVAL;
@ -2918,16 +2671,6 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev)
}
disable_irq(gpio_to_irq(ctrl_pdata->disp_te_gpio));
}
ctrl_pdata->workq = create_workqueue("mdss_dsi_dba");
if (!ctrl_pdata->workq) {
pr_err("%s: Error creating workqueue\n", __func__);
rc = -EPERM;
goto error_pan_node;
}
INIT_DELAYED_WORK(&ctrl_pdata->dba_work, mdss_dsi_dba_work);
pr_debug("%s: Dsi Ctrl->%d initialized\n", __func__, index);
if (index == 0)
@ -3406,10 +3149,6 @@ static int mdss_dsi_ctrl_remove(struct platform_device *pdev)
msm_dss_iounmap(&ctrl_pdata->phy_io);
msm_dss_iounmap(&ctrl_pdata->ctrl_io);
mdss_dsi_debugfs_cleanup(ctrl_pdata);
if (ctrl_pdata->workq)
destroy_workqueue(ctrl_pdata->workq);
return 0;
}

View file

@ -512,7 +512,6 @@ struct mdss_dsi_ctrl_pdata {
struct dsi_err_container err_cont;
bool dfps_status; /* dynamic refresh status */
struct switch_dev sdev;
bool hpd_state;
bool ds_registered;
@ -622,7 +621,8 @@ void mdss_dsi_get_hw_revision(struct mdss_dsi_ctrl_pdata *ctrl);
u32 mdss_dsi_panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0,
char cmd1, void (*fxn)(int), char *rbuf, int len);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata);
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
int ndx);
int mdss_dsi_panel_timing_switch(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
struct mdss_panel_timing *timing);

View file

@ -716,6 +716,10 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
ret = ctrl->dba_ops.video_on(
ctrl->dba_data, true,
&ctrl->dba_video_cfg, 0);
if (ret) {
pr_err("%s: video on failed for chip %s\n",
__func__, ctrl->dba_info.chip_name);
}
}
end:
@ -2147,9 +2151,12 @@ static int mdss_dsi_panel_timing_from_dt(struct device_node *np,
{
u32 tmp;
u64 tmp64;
int rc, i, len;
int rc, i, len, num_lanes;
const char *data;
struct mdss_dsi_ctrl_pdata *ctrl_pdata;
struct mdss_panel_info *pinfo;
pinfo = &panel_data->panel_info;
ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata,
panel_data);
@ -2211,6 +2218,35 @@ static int mdss_dsi_panel_timing_from_dt(struct device_node *np,
"qcom,mdss-dsi-panel-clockrate", (u32 *)&tmp64);
pt->timing.clk_rate = !rc ? tmp64 : 0;
/* Update timing parameter to DBA structure*/
ctrl_pdata->dba_video_cfg.h_active =
pt->timing.xres;
ctrl_pdata->dba_video_cfg.h_front_porch =
pt->timing.h_front_porch;
ctrl_pdata->dba_video_cfg.h_back_porch =
pt->timing.h_back_porch;
ctrl_pdata->dba_video_cfg.h_pulse_width =
pt->timing.h_pulse_width;
ctrl_pdata->dba_video_cfg.v_active =
pt->timing.yres;
ctrl_pdata->dba_video_cfg.v_front_porch =
pt->timing.v_front_porch;
ctrl_pdata->dba_video_cfg.v_back_porch =
pt->timing.v_back_porch;
ctrl_pdata->dba_video_cfg.v_pulse_width =
pt->timing.v_pulse_width;
num_lanes = 0;
if (pinfo->mipi.data_lane0)
num_lanes++;
if (pinfo->mipi.data_lane1)
num_lanes++;
if (pinfo->mipi.data_lane2)
num_lanes++;
if (pinfo->mipi.data_lane3)
num_lanes++;
ctrl_pdata->dba_video_cfg.num_of_input_lanes = num_lanes;
data = of_get_property(np, "qcom,mdss-dsi-panel-timings", &len);
if ((!data) || (len != 12)) {
pr_err("%s:%d, Unable to read Phy timing settings",
@ -2565,8 +2601,121 @@ error:
return -EINVAL;
}
static inline void mdss_dsi_send_cable_notification(
struct mdss_dsi_ctrl_pdata *ctrl_pdata, int val)
{
int state = 0;
if (!ctrl_pdata) {
DEV_ERR("%s: invalid input\n", __func__);
return;
}
state = ctrl_pdata->sdev.state;
switch_set_state(&ctrl_pdata->sdev, val);
DEV_INFO("%s: cable state %s %d\n", __func__,
ctrl_pdata->sdev.state == state ?
"is same" : "switched to",
ctrl_pdata->sdev.state);
}
static void mdss_dsi_dba_cb(void *data, enum msm_dba_callback_event event)
{
int ret = -EINVAL;
struct mdss_dsi_ctrl_pdata *ctrl_pdata =
(struct mdss_dsi_ctrl_pdata *) data;
if (!ctrl_pdata) {
pr_err("%s: Invalid data\n", __func__);
return;
}
switch (event) {
case MSM_DBA_CB_HPD_CONNECT:
ctrl_pdata->hpd_state = true;
if (ctrl_pdata->dba_ops.get_raw_edid)
ret = ctrl_pdata->dba_ops.get_raw_edid(
ctrl_pdata->dba_data,
sizeof(ctrl_pdata->edid_buf),
ctrl_pdata->edid_buf, 0);
if (!ret)
hdmi_edid_parser(ctrl_pdata->edid_data);
mdss_dsi_send_cable_notification(ctrl_pdata, 1);
break;
case MSM_DBA_CB_HPD_DISCONNECT:
mdss_dsi_send_cable_notification(ctrl_pdata, 0);
ctrl_pdata->hpd_state = false;
break;
default:
break;
}
}
static void mdss_dsi_ctrl_init_dba(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
int ndx)
{
struct hdmi_edid_init_data edid_init_data;
msm_dba_cb dba_cb = mdss_dsi_dba_cb;
if (!ctrl_pdata) {
pr_err("%s: Invalid ctrl data\n", __func__);
goto end;
}
snprintf(ctrl_pdata->dba_info.client_name, MSM_DBA_CLIENT_NAME_LEN,
"dsi-%d", ndx);
strlcpy(ctrl_pdata->dba_info.chip_name, "adv7533",
MSM_DBA_CHIP_NAME_MAX_LEN);
ctrl_pdata->dba_info.instance_id = ndx;
ctrl_pdata->dba_info.cb = dba_cb;
ctrl_pdata->dba_info.cb_data = ctrl_pdata;
ctrl_pdata->dba_data = msm_dba_register_client(
&ctrl_pdata->dba_info,
&ctrl_pdata->dba_ops);
if (IS_ERR_OR_NULL(ctrl_pdata->dba_data)) {
pr_err("%s: ds not configured, %p\n", __func__,
ctrl_pdata->dba_data);
goto end;
}
ctrl_pdata->sdev.name = ctrl_pdata->dba_info.client_name;
if (switch_dev_register(&ctrl_pdata->sdev) < 0) {
pr_err("%s: DSI switch registration failed\n",
__func__);
goto end;
}
memset(&edid_init_data, 0x00, sizeof(edid_init_data));
ctrl_pdata->edid_data = hdmi_edid_init(&edid_init_data);
if (!ctrl_pdata->edid_data) {
pr_err("%s: edid parser init failed\n", __func__);
goto end;
}
if (ctrl_pdata->dba_ops.power_on)
ctrl_pdata->dba_ops.power_on(ctrl_pdata->dba_data,
true, 0);
ctrl_pdata->ds_registered = true;
ctrl_pdata->hpd_state = true;
mdss_dsi_send_cable_notification(ctrl_pdata, 1);
end:
return;
}
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
int ndx)
{
int rc = 0;
static const char *panel_name;
@ -2606,5 +2755,7 @@ int mdss_dsi_panel_init(struct device_node *node,
ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode;
mdss_dsi_ctrl_init_dba(ctrl_pdata, ndx);
return 0;
}

View file

@ -21,4 +21,4 @@ config MSM_DBA_ADV7533
---help---
Support for ADV7533 DSI to HDMI display bridge driver. The driver
controls the ADV7533 HW through the I2C interface and configures
the DSi input and HDMI output video format.
the DSI input and HDMI output video format.

View file

@ -29,6 +29,7 @@
#include "msm_dba_internal.h"
#define ADV7533_REG_CHIP_REVISION (0x00)
#define ADV7533_DSI_CEC_I2C_ADDR_REG (0xE1)
#define ADV7533_RESET_DELAY (100)
#define PINCTRL_STATE_ACTIVE "pmx_adv7533_active"
@ -45,7 +46,7 @@
#define MAX_RW_TRIES (3)
enum adv7533_i2c_addr {
ADV7533_MAIN = 0x39,
ADV7533_MAIN = 0x3D,
ADV7533_CEC_DSI = 0x3C,
};
@ -60,6 +61,7 @@ struct adv7533_reg_cfg {
u8 i2c_addr;
u8 reg;
u8 val;
int sleep_in_ms;
};
struct adv7533_platform_data {
@ -89,98 +91,43 @@ struct adv7533_platform_data {
};
static struct adv7533_reg_cfg adv7533_init_setup[] = {
/* power down */
{ADV7533_MAIN, 0x41, 0x50},
/* HPD override */
{ADV7533_MAIN, 0xD6, 0x48},
{ADV7533_MAIN, 0xD6, 0x48, 5},
/* power down */
{ADV7533_MAIN, 0x41, 0x50, 5},
/* color space */
{ADV7533_MAIN, 0x16, 0x20},
{ADV7533_MAIN, 0x16, 0x20, 0},
/* Fixed */
{ADV7533_MAIN, 0x9A, 0xE0},
{ADV7533_MAIN, 0x9A, 0xE0, 0},
/* HDCP */
{ADV7533_MAIN, 0xBA, 0x70},
{ADV7533_MAIN, 0xBA, 0x70, 0},
/* Fixed */
{ADV7533_MAIN, 0xDE, 0x82},
{ADV7533_MAIN, 0xDE, 0x82, 0},
/* V1P2 */
{ADV7533_MAIN, 0xE4, 0x40},
{ADV7533_MAIN, 0xE4, 0x40, 0},
/* Fixed */
{ADV7533_MAIN, 0xE5, 0x80},
{ADV7533_MAIN, 0xE5, 0x80, 0},
/* Fixed */
{ADV7533_CEC_DSI, 0x15, 0xD0},
{ADV7533_CEC_DSI, 0x15, 0xD0, 0},
/* Fixed */
{ADV7533_CEC_DSI, 0x17, 0xD0},
{ADV7533_CEC_DSI, 0x17, 0xD0, 0},
/* Fixed */
{ADV7533_CEC_DSI, 0x24, 0x20},
{ADV7533_CEC_DSI, 0x24, 0x20, 0},
/* Fixed */
{ADV7533_CEC_DSI, 0x57, 0x11},
{ADV7533_CEC_DSI, 0x57, 0x11, 0},
};
static struct adv7533_reg_cfg adv7533_video_setup[] = {
/* power up */
{ADV7533_MAIN, 0x41, 0x10},
{ADV7533_MAIN, 0x41, 0x10, 0},
/* hdmi enable */
{ADV7533_CEC_DSI, 0x03, 0x89},
{ADV7533_CEC_DSI, 0x03, 0x89, 0},
/* hdmi mode, hdcp */
{ADV7533_MAIN, 0xAF, 0x06},
{ADV7533_MAIN, 0xAF, 0x06, 0},
/* color depth */
{ADV7533_MAIN, 0x4C, 0x04},
{ADV7533_MAIN, 0x4C, 0x04, 0},
/* down dither */
{ADV7533_MAIN, 0x49, 0x02},
};
static struct adv7533_reg_cfg tg_cfg_1080p[] = {
/* 4 lanes */
{ADV7533_CEC_DSI, 0x1C, 0x40},
/* hsync and vsync active low */
{ADV7533_MAIN, 0x17, 0x02},
/* Control for Pixel Clock Divider */
{ADV7533_CEC_DSI, 0x16, 0x00},
/* Timing Generator Enable */
{ADV7533_CEC_DSI, 0x27, 0xCB},
/* h_width 0x898 2200*/
{ADV7533_CEC_DSI, 0x28, 0x89},
{ADV7533_CEC_DSI, 0x29, 0x80},
/* hsync_width 0x2C 44*/
{ADV7533_CEC_DSI, 0x2A, 0x02},
{ADV7533_CEC_DSI, 0x2B, 0xC0},
/* hfp 0x58 88 */
{ADV7533_CEC_DSI, 0x2C, 0x05},
{ADV7533_CEC_DSI, 0x2D, 0x80},
/* hbp 0x94 148 */
{ADV7533_CEC_DSI, 0x2E, 0x09},
{ADV7533_CEC_DSI, 0x2F, 0x40},
/* v_total 0x465 1125 */
{ADV7533_CEC_DSI, 0x30, 0x46},
{ADV7533_CEC_DSI, 0x31, 0x50},
/* vsync_width 0x05 5*/
{ADV7533_CEC_DSI, 0x32, 0x00},
{ADV7533_CEC_DSI, 0x33, 0x50},
/* vfp 0x04 4 */
{ADV7533_CEC_DSI, 0x34, 0x00},
{ADV7533_CEC_DSI, 0x35, 0x40},
/* vbp 0x24 36 */
{ADV7533_CEC_DSI, 0x36, 0x02},
{ADV7533_CEC_DSI, 0x37, 0x40},
/* Timing Generator Enable */
{ADV7533_CEC_DSI, 0x27, 0xCB},
{ADV7533_CEC_DSI, 0x27, 0x8B},
{ADV7533_CEC_DSI, 0x27, 0xCB},
/* Reset Internal Timing Generator */
{ADV7533_MAIN, 0xAF, 0x16},
/* HDMI Mode Select */
{ADV7533_CEC_DSI, 0x78, 0x03},
/* HDMI Output Enable */
{ADV7533_MAIN, 0x40, 0x80},
/* GC Packet Enable */
{ADV7533_MAIN, 0x4C, 0x04},
/* Colour Depth 24-bit per pixel */
{ADV7533_MAIN, 0x49, 0x00},
/* Down Dither Output 8-bit Colour Depth */
{ADV7533_CEC_DSI, 0x05, 0xC8},
/* ADI Required Write */
{ADV7533_CEC_DSI, 0xBE, 0x3D},
/* Test Pattern Disable (0x55[7] = 0) */
{ADV7533_CEC_DSI, 0x55, 0x00},
{ADV7533_MAIN, 0x49, 0x02, 0},
};
static struct adv7533_reg_cfg I2S_cfg[] = {
@ -287,9 +234,119 @@ w_err:
if (ret != 0)
pr_err("%s: Exiting with ret = %d after %d retries\n",
__func__, ret, i);
else
pr_debug("[%s,%d] I2C write(0x%02x) [0x%02x]=0x%02x\n",
__func__, __LINE__, addr, reg, val);
return ret;
}
static int adv7533_read_reg(struct msm_dba_device_info *dev, u32 reg, u32 *val)
{
int rc = 0;
u8 byte_val = 0, addr = 0;
struct adv7533_platform_data *pdata = NULL;
if (!dev) {
pr_err("%s: dev is NULL\n", __func__);
return -EINVAL;
}
pdata = container_of(dev, struct adv7533_platform_data, dev_info);
if (!pdata) {
pr_err("%s: pdata is NULL\n", __func__);
return -EINVAL;
}
addr = (reg & 0x0100)?(pdata->cec_dsi_i2c_addr):(pdata->main_i2c_addr);
rc = adv7533_read_byte(addr, (reg & 0xff), &byte_val);
if (rc) {
pr_err("%s: read reg=0x%02x failed @ addr=0x%02x\n",
__func__, reg, addr);
} else {
pr_debug("%s: read reg=0x%02x ok value=0x%02x @ addr=0x%02x\n",
__func__, reg, byte_val, addr);
*val = (u32)byte_val;
}
return rc;
}
static int adv7533_write_reg(struct msm_dba_device_info *dev, u32 reg, u32 val)
{
int rc = 0;
u8 addr = 0;
struct adv7533_platform_data *pdata = NULL;
if (!dev) {
pr_err("%s: dev is NULL\n", __func__);
return -EINVAL;
}
pdata = container_of(dev, struct adv7533_platform_data, dev_info);
if (!pdata) {
pr_err("%s: pdata is NULL\n", __func__);
return -EINVAL;
}
addr = (reg & 0x0100)?(pdata->cec_dsi_i2c_addr):(pdata->main_i2c_addr);
rc = adv7533_write_byte(addr, (reg & 0xff), val);
if (rc)
pr_err("%s: write reg=0x%02x failed @ addr=0x%02x\n",
__func__, reg, pdata->main_i2c_addr);
else
pr_debug("%s: write reg=0x%02x ok value=0x%02x @ addr=0x%02x\n",
__func__, reg, val, pdata->main_i2c_addr);
return rc;
}
static int adv7533_dump_debug_info(struct msm_dba_device_info *dev, u32 flags)
{
int rc = 0;
u8 byte_val = 0;
u16 addr = 0;
struct adv7533_platform_data *pdata = NULL;
if (!dev) {
pr_err("%s: dev is NULL\n", __func__);
return -EINVAL;
}
pdata = container_of(dev, struct adv7533_platform_data, dev_info);
if (!pdata) {
pr_err("%s: pdata is NULL\n", __func__);
return -EINVAL;
}
/* dump main addr*/
pr_err("========Main I2C=0x%02x Start==========\n",
pdata->main_i2c_addr);
for (addr = 0; addr <= 0xFF; addr++) {
rc = adv7533_read_byte(pdata->main_i2c_addr,
(u8)addr, &byte_val);
if (rc)
pr_err("%s: read reg=0x%02x failed @ addr=0x%02x\n",
__func__, addr, pdata->main_i2c_addr);
else
pr_err("0x%02x -> 0x%02X\n", addr, byte_val);
}
pr_err("========Main I2C=0x%02x End==========\n",
pdata->main_i2c_addr);
/* dump CEC addr*/
pr_err("=======CEC I2C=0x%02x Start=========\n",
pdata->cec_dsi_i2c_addr);
for (addr = 0; addr <= 0xFF; addr++) {
rc = adv7533_read_byte(pdata->cec_dsi_i2c_addr,
(u8)addr, &byte_val);
if (rc)
pr_err("%s: read reg=0x%02x failed @ addr=0x%02x\n",
__func__, addr, pdata->cec_dsi_i2c_addr);
else
pr_err("0x%02x -> 0x%02X\n", addr, byte_val);
}
pr_err("========CEC I2C=0x%02x End==========\n",
pdata->cec_dsi_i2c_addr);
return rc;
}
static int adv7533_write_regs(struct adv7533_platform_data *pdata,
struct adv7533_reg_cfg *cfg, int size)
{
@ -323,6 +380,8 @@ static int adv7533_write_regs(struct adv7533_platform_data *pdata,
cfg[i].val, cfg[i].reg);
goto w_regs_fail;
}
if (cfg[i].sleep_in_ms)
msleep(cfg[i].sleep_in_ms);
}
w_regs_fail:
@ -332,12 +391,12 @@ w_regs_fail:
return ret;
}
static int adv7533_read_device_rev(void)
static int adv7533_read_device_rev(struct adv7533_platform_data *pdata)
{
u8 rev = 0;
int ret;
ret = adv7533_read_byte(ADV7533_MAIN, ADV7533_REG_CHIP_REVISION,
ret = adv7533_read_byte(pdata->main_i2c_addr, ADV7533_REG_CHIP_REVISION,
&rev);
if (!ret)
@ -348,13 +407,39 @@ static int adv7533_read_device_rev(void)
return ret;
}
static int adv7533_program_i2c_addr(struct adv7533_platform_data *pdata)
{
u8 i2c_8bits = pdata->cec_dsi_i2c_addr << 1;
int ret = 0;
if (pdata->cec_dsi_i2c_addr != ADV7533_CEC_DSI) {
ret = adv7533_write_byte(pdata->main_i2c_addr,
ADV7533_DSI_CEC_I2C_ADDR_REG,
i2c_8bits);
if (ret)
pr_err("%s: write err CEC_ADDR[0x%02x] main_addr=0x%02x\n",
__func__, ADV7533_DSI_CEC_I2C_ADDR_REG,
pdata->main_i2c_addr);
}
return ret;
}
static int adv7533_parse_dt(struct device *dev,
struct adv7533_platform_data *pdata)
{
struct device_node *np = dev->of_node;
u32 temp_val;
u32 temp_val = 0;
int ret = 0;
ret = of_property_read_u32(np, "instance_id", &temp_val);
pr_debug("%s: DT property %s is %X\n", __func__, "instance_id",
temp_val);
if (ret)
goto end;
pdata->dev_info.instance_id = temp_val;
ret = of_property_read_u32(np, "adi,main-addr", &temp_val);
pr_debug("%s: DT property %s is %X\n", __func__, "adi,main-addr",
temp_val);
@ -433,8 +518,8 @@ static int adv7533_gpio_configure(struct adv7533_platform_data *pdata,
if (gpio_is_valid(pdata->irq_gpio)) {
ret = gpio_request(pdata->irq_gpio, "adv7533_irq_gpio");
if (ret) {
pr_err("unable to request gpio [%d]\n",
pdata->irq_gpio);
pr_err("%d unable to request gpio [%d] ret=%d\n",
__LINE__, pdata->irq_gpio, ret);
goto err_none;
}
ret = gpio_direction_input(pdata->irq_gpio);
@ -448,35 +533,16 @@ static int adv7533_gpio_configure(struct adv7533_platform_data *pdata,
goto err_none;
}
if (gpio_is_valid(pdata->hpd_irq_gpio)) {
ret = gpio_request(pdata->hpd_irq_gpio,
"adv7533_hpd_irq_gpio");
if (ret) {
pr_err("unable to request gpio [%d]\n",
pdata->hpd_irq_gpio);
goto err_irq_gpio;
}
ret = gpio_direction_input(pdata->hpd_irq_gpio);
if (ret) {
pr_err("unable to set dir for gpio[%d]\n",
pdata->hpd_irq_gpio);
goto err_hpd_irq_gpio;
}
} else {
pr_err("hpd irq gpio not provided\n");
goto err_irq_gpio;
}
if (gpio_is_valid(pdata->switch_gpio)) {
ret = gpio_request(pdata->switch_gpio,
"adv7533_switch_gpio");
if (ret) {
pr_err("unable to request gpio [%d]\n",
pdata->switch_gpio);
pr_err("%d unable to request gpio [%d] ret=%d\n",
__LINE__, pdata->irq_gpio, ret);
goto err_hpd_irq_gpio;
}
ret = gpio_direction_output(pdata->switch_gpio, 1);
ret = gpio_direction_output(pdata->switch_gpio, 0);
if (ret) {
pr_err("unable to set dir for gpio [%d]\n",
pdata->switch_gpio);
@ -496,7 +562,7 @@ static int adv7533_gpio_configure(struct adv7533_platform_data *pdata,
if (gpio_is_valid(pdata->switch_gpio))
gpio_free(pdata->switch_gpio);
return 0;
goto err_none;
}
err_switch_gpio:
@ -512,32 +578,8 @@ err_none:
return ret;
}
static void adv7533_get_cmdline_config(void)
{
int len = 0;
char *t;
len = strlen(mdss_mdp_panel);
if (len <= 0)
return;
t = strnstr(mdss_mdp_panel, "hdmi", MDSS_MAX_PANEL_LEN);
if (t)
pdata->adv_output = true;
else
pdata->adv_output = false;
t = strnstr(mdss_mdp_panel, "720", MDSS_MAX_PANEL_LEN);
if (t)
pdata->video_mode = ADV7533_VIDEO_720P;
t = strnstr(mdss_mdp_panel, "1080", MDSS_MAX_PANEL_LEN);
if (t)
pdata->video_mode = ADV7533_VIDEO_1080P;
}
u32 adv7533_read_edid(u32 size, char *edid_buf)
u32 adv7533_read_edid(struct adv7533_platform_data *pdata,
u32 size, char *edid_buf)
{
u32 ret = 0, ndx;
u8 edid_addr;
@ -548,7 +590,7 @@ u32 adv7533_read_edid(u32 size, char *edid_buf)
pr_debug("%s: size %d\n", __func__, size);
ret = adv7533_read(ADV7533_MAIN, 0x43, &edid_addr, 1);
ret = adv7533_read(pdata->main_i2c_addr, 0x43, &edid_addr, 1);
if (ret) {
pr_err("%s: Error reading edid addr\n", __func__);
goto end;
@ -594,8 +636,8 @@ static void adv7533_intr_work(struct work_struct *work)
}
/* READ Interrupt registers */
adv7533_read_byte(ADV7533_MAIN, 0x96, &int_status);
adv7533_read_byte(ADV7533_MAIN, 0x42, &int_state);
adv7533_read_byte(pdata->main_i2c_addr, 0x96, &int_status);
adv7533_read_byte(pdata->main_i2c_addr, 0x42, &int_state);
if (int_status & BIT(6)) {
if (int_state & BIT(5)) {
@ -623,7 +665,7 @@ static void adv7533_intr_work(struct work_struct *work)
if (int_status & BIT(2)) {
pr_info("%s: EDID READY\n", __func__);
ret = adv7533_read_edid(sizeof(pdata->edid_buf),
ret = adv7533_read_edid(pdata, sizeof(pdata->edid_buf),
pdata->edid_buf);
if (ret)
pr_err("%s: edid read failed\n", __func__);
@ -714,12 +756,86 @@ static int adv7533_power_on(void *client, bool on, u32 flags)
goto end;
}
queue_delayed_work(pdata->workq, &pdata->adv7533_intr_work_id, HZ/2);
if (pdata->workq)
queue_delayed_work(pdata->workq, &pdata->adv7533_intr_work_id,
HZ/2);
end:
return ret;
}
static void adv7533_video_timing_setup(struct adv7533_platform_data *pdata,
struct msm_dba_video_cfg *cfg)
{
u32 h_total, hpw, hfp, hbp;
u32 v_total, vpw, vfp, vbp;
u32 num_lanes;
u8 addr = 0;
if (!pdata || !cfg) {
pr_err("%s: invalid input\n", __func__);
return;
}
h_total = cfg->h_active + cfg->h_front_porch +
cfg->h_pulse_width + cfg->h_back_porch;
v_total = cfg->v_active + cfg->v_front_porch +
cfg->v_pulse_width + cfg->v_back_porch;
hpw = cfg->h_pulse_width;
hfp = cfg->h_front_porch;
hbp = cfg->h_back_porch;
vpw = cfg->v_pulse_width;
vfp = cfg->v_front_porch;
vbp = cfg->v_back_porch;
addr = pdata->cec_dsi_i2c_addr;
num_lanes = cfg->num_of_input_lanes;
pr_debug("h_total 0x%x, h_active 0x%x, hfp 0x%d, hpw 0x%x, hbp 0x%x\n",
h_total, cfg->h_active, cfg->h_front_porch,
cfg->h_pulse_width, cfg->h_back_porch);
pr_debug("v_total 0x%x, v_active 0x%x, vfp 0x%x, vpw 0x%x, vbp 0x%x\n",
v_total, cfg->v_active, cfg->v_front_porch,
cfg->v_pulse_width, cfg->v_back_porch);
/* lane setup */
adv7533_write_byte(addr, 0x1C, ((num_lanes & 0xF) << 4));
/* h_width */
adv7533_write_byte(addr, 0x28, ((h_total & 0xFF0) >> 4));
adv7533_write_byte(addr, 0x29, ((h_total & 0xF) << 4));
/* hsync_width */
adv7533_write_byte(addr, 0x2A, ((hpw & 0xFF0) >> 4));
adv7533_write_byte(addr, 0x2B, ((hpw & 0xF) << 4));
/* hfp */
adv7533_write_byte(addr, 0x2C, ((hfp & 0xFF0) >> 4));
adv7533_write_byte(addr, 0x2D, ((hfp & 0xF) << 4));
/* hbp */
adv7533_write_byte(addr, 0x2E, ((hbp & 0xFF0) >> 4));
adv7533_write_byte(addr, 0x2F, ((hbp & 0xF) << 4));
/* v_total */
adv7533_write_byte(addr, 0x30, ((v_total & 0xFF0) >> 4));
adv7533_write_byte(addr, 0x31, ((v_total & 0xF) << 4));
/* vsync_width */
adv7533_write_byte(addr, 0x32, ((vpw & 0xFF0) >> 4));
adv7533_write_byte(addr, 0x33, ((vpw & 0xF) << 4));
/* vfp */
adv7533_write_byte(addr, 0x34, ((vfp & 0xFF0) >> 4));
adv7533_write_byte(addr, 0x35, ((vfp & 0xF) << 4));
/* vbp */
adv7533_write_byte(addr, 0x36, ((vbp & 0xFF0) >> 4));
adv7533_write_byte(addr, 0x37, ((vbp & 0xF) << 4));
}
static int adv7533_video_on(void *client, bool on,
struct msm_dba_video_cfg *cfg, u32 flags)
{
@ -732,12 +848,7 @@ static int adv7533_video_on(void *client, bool on,
goto end;
}
ret = adv7533_write_regs(pdata, tg_cfg_1080p,
ARRAY_SIZE(tg_cfg_1080p));
if (ret) {
pr_err("%s: err config 1080p %d\n", __func__, ret);
goto end;
}
adv7533_video_timing_setup(pdata, cfg);
ret = adv7533_write_regs(pdata, adv7533_video_setup,
ARRAY_SIZE(adv7533_video_setup));
@ -812,11 +923,13 @@ static int adv7533_register_dba(struct adv7533_platform_data *pdata)
client_ops->video_on = adv7533_video_on;
client_ops->get_edid_size = adv7533_get_edid_size;
client_ops->get_raw_edid = adv7533_get_raw_edid;
pdata->dev_info.dev_ops.read_reg = adv7533_read_reg;
pdata->dev_info.dev_ops.write_reg = adv7533_write_reg;
pdata->dev_info.dev_ops.dump_debug_info = adv7533_dump_debug_info;
strlcpy(pdata->dev_info.chip_name, "adv7533",
sizeof(pdata->dev_info.chip_name));
pdata->dev_info.instance_id = 0;
pdata->dev_info.reg_fxn = adv7533_reg_fxn;
mutex_init(&pdata->dev_info.dev_mutex);
@ -826,13 +939,20 @@ static int adv7533_register_dba(struct adv7533_platform_data *pdata)
return msm_dba_add_probed_device(&pdata->dev_info);
}
static void adv7533_unregister_dba(struct adv7533_platform_data *pdata)
{
if (!pdata)
return;
msm_dba_remove_probed_device(&pdata->dev_info);
}
static int adv7533_probe(struct i2c_client *client_,
const struct i2c_device_id *id)
{
int ret = 0;
client = client_;
client = client_;
if (client->dev.of_node) {
pdata = devm_kzalloc(&client->dev,
sizeof(struct adv7533_platform_data), GFP_KERNEL);
@ -842,42 +962,51 @@ static int adv7533_probe(struct i2c_client *client_,
ret = adv7533_parse_dt(&client->dev, pdata);
if (ret) {
pr_err("%s: Failed to parse DT\n", __func__);
goto p_err;
goto err_dt_parse;
}
}
ret = adv7533_read_device_rev();
ret = adv7533_read_device_rev(pdata);
if (ret != 0) {
pr_err("%s: Failed to read revision\n", __func__);
goto p_err;
goto err_dt_parse;
}
ret = adv7533_program_i2c_addr(pdata);
if (ret != 0) {
pr_err("%s: Failed to program i2c addr\n", __func__);
goto err_dt_parse;
}
ret = adv7533_register_dba(pdata);
if (ret)
if (ret) {
pr_err("%s: Error registering with DBA %d\n",
__func__, ret);
goto err_dba_reg;
}
ret = pinctrl_select_state(pdata->ts_pinctrl,
pdata->pinctrl_state_active);
if (ret < 0)
if (ret < 0) {
pr_err("%s: Failed to select %s pinstate %d\n",
__func__, PINCTRL_STATE_ACTIVE, ret);
goto err_dba_reg;
}
pdata->adv_output = true;
adv7533_get_cmdline_config();
if (!(pdata->disable_gpios)) {
ret = adv7533_gpio_configure(pdata, true);
if (ret) {
pr_err("%s: Failed to configure GPIOs\n", __func__);
goto p_err;
goto err_gpio_cfg;
}
if (pdata->adv_output) {
gpio_set_value(pdata->switch_gpio, 0);
} else {
gpio_set_value(pdata->switch_gpio, 1);
goto p_err;
goto err_gpio_cfg;
}
}
@ -888,7 +1017,7 @@ static int adv7533_probe(struct i2c_client *client_,
if (ret) {
pr_err("%s: Failed to enable ADV7533 interrupt\n",
__func__);
goto p_err;
goto err_irq;
}
if (pdata->audio) {
@ -896,14 +1025,22 @@ static int adv7533_probe(struct i2c_client *client_,
if (ret != 0) {
pr_err("%s: I2S configuration fail = %d!\n",
__func__, ret);
goto p_err;
goto err_dba_helper;
}
}
dev_set_drvdata(&client->dev, &pdata->dev_info);
ret = msm_dba_helper_sysfs_init(&client->dev);
if (ret) {
pr_err("%s: sysfs init failed\n", __func__);
goto err_dba_helper;
}
pdata->workq = create_workqueue("adv7533_workq");
if (!pdata->workq) {
pr_err("%s: workqueue creation failed.\n", __func__);
return -EPERM;
ret = -EPERM;
goto err_workqueue;
}
INIT_DELAYED_WORK(&pdata->adv7533_intr_work_id, adv7533_intr_work);
@ -913,8 +1050,17 @@ static int adv7533_probe(struct i2c_client *client_,
return 0;
p_err:
err_workqueue:
msm_dba_helper_sysfs_remove(&client->dev);
err_dba_helper:
disable_irq(pdata->irq);
free_irq(pdata->irq, pdata);
err_irq:
adv7533_gpio_configure(pdata, false);
err_gpio_cfg:
adv7533_unregister_dba(pdata);
err_dba_reg:
err_dt_parse:
devm_kfree(&client->dev, pdata);
return ret;
}

View file

@ -26,6 +26,10 @@
static inline struct msm_dba_device_info *to_dba_dev(struct device *dev)
{
if (!dev) {
pr_err("%s: dev is NULL\n", __func__);
return NULL;
}
return dev_get_drvdata(dev);
}
@ -35,6 +39,11 @@ static ssize_t device_name_rda_attr(struct device *dev,
{
struct msm_dba_device_info *device = to_dba_dev(dev);
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE, "%s:%d\n", device->chip_name,
device->instance_id);
}
@ -48,6 +57,11 @@ static ssize_t client_list_rda_attr(struct device *dev,
struct list_head *pos = NULL;
ssize_t bytes = 0;
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&device->dev_mutex);
list_for_each(pos, &device->client_list) {
@ -70,6 +84,11 @@ static ssize_t power_status_rda_attr(struct device *dev,
struct list_head *pos = NULL;
ssize_t bytes = 0;
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&device->dev_mutex);
bytes = snprintf(buf, PAGE_SIZE, "power_status:%d\n",
device->power_status);
@ -94,6 +113,11 @@ static ssize_t video_status_rda_attr(struct device *dev,
struct list_head *pos = NULL;
ssize_t bytes = 0;
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&device->dev_mutex);
bytes = snprintf(buf, PAGE_SIZE, "video_status:%d\n",
device->video_status);
@ -118,6 +142,11 @@ static ssize_t audio_status_rda_attr(struct device *dev,
struct list_head *pos = NULL;
ssize_t bytes = 0;
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&device->dev_mutex);
bytes = snprintf(buf, PAGE_SIZE, "audio_status:%d\n",
device->audio_status);
@ -146,6 +175,11 @@ static ssize_t write_reg_wta_attr(struct device *dev,
int rc = 0;
int len;
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return -EINVAL;
}
len = strlen(buf);
strlcpy(str, buf, 20);
if (len < 20)
@ -195,6 +229,11 @@ static ssize_t read_reg_rda_attr(struct device *dev,
struct msm_dba_device_info *device = to_dba_dev(dev);
ssize_t bytes;
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&device->dev_mutex);
bytes = snprintf(buf, PAGE_SIZE, "0x%x\n", device->register_val);
@ -214,6 +253,11 @@ static ssize_t read_reg_wta_attr(struct device *dev,
int rc = 0;
u32 val = 0;
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return count;
}
rc = kstrtol(buf, 0, &reg);
if (rc) {
pr_err("%s: kstrol error %d\n", __func__, rc);
@ -249,9 +293,18 @@ static ssize_t dump_info_wta_attr(struct device *dev,
struct msm_dba_device_info *device = to_dba_dev(dev);
int rc;
rc = device->dev_ops.dump_debug_info(device, 0x00);
if (rc)
pr_err("%s: failed to dump debug data\n", __func__);
if (!device) {
pr_err("%s: device is NULL\n", __func__);
return -EINVAL;
}
if (device->dev_ops.dump_debug_info) {
rc = device->dev_ops.dump_debug_info(device, 0x00);
if (rc)
pr_err("%s: failed to dump debug data\n", __func__);
} else {
pr_err("%s: not supported\n", __func__);
}
return count;
}
@ -297,3 +350,13 @@ int msm_dba_helper_sysfs_init(struct device *dev)
return rc;
}
void msm_dba_helper_sysfs_remove(struct device *dev)
{
if (!dev) {
pr_err("%s: Invalid params\n", __func__);
return;
}
sysfs_remove_group(&dev->kobj, &msm_dba_sysfs_attr_grp);
}

View file

@ -53,9 +53,8 @@ int msm_dba_add_probed_device(struct msm_dba_device_info *dev)
node->dev = dev;
list_add(&node->list, &device_list);
pr_debug("%s: Added new device (%s, %d)", __func__, dev->chip_name,
pr_debug("%s: Added new device (%s, %d)\n", __func__, dev->chip_name,
dev->instance_id);
mutex_unlock(&init_mutex);
return 0;

View file

@ -305,6 +305,13 @@ int msm_dba_register_hdcp_monitor(struct msm_dba_device_info *dev, bool enable);
*/
int msm_dba_helper_sysfs_init(struct device *dev);
/**
* msm_dba_helper_sysfs_remove() - remove sysfs attributes
* @dev: pointer to struct device structure.
*
*/
void msm_dba_helper_sysfs_remove(struct device *dev);
/**
* msm_dba_helper_force_reset() - force reset bridge chip
* @client: client handle