msm: adv7533: register with dba (Display Bridge Abstract)
Register ADV7533 driver with DBA (Display Bridge-chip Abstraction) module so that interface drivers can utilize functionality exposed by this driver. Change-Id: Ife0b94acfc5d1c8108ffff8a320228224ab29eaf Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org> Signed-off-by: Siddharth Zaveri <szaveri@codeaurora.org>
This commit is contained in:
parent
2ff2acc7cf
commit
8303b9eb19
4 changed files with 592 additions and 283 deletions
|
@ -2051,6 +2051,249 @@ 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)
|
||||
{
|
||||
|
@ -2171,6 +2414,11 @@ 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);
|
||||
|
@ -2670,6 +2918,16 @@ 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)
|
||||
|
@ -3148,6 +3406,10 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,13 @@
|
|||
#include <linux/irqreturn.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/switch.h>
|
||||
#include <video/msm_dba.h>
|
||||
|
||||
#include "mdss_panel.h"
|
||||
#include "mdss_dsi_cmd.h"
|
||||
#include "mdss_dsi_clk.h"
|
||||
#include "mdss_hdmi_edid.h"
|
||||
|
||||
#define MMSS_SERDES_BASE_PHY 0x04f01000 /* mmss (De)Serializer CFG */
|
||||
|
||||
|
@ -508,6 +511,24 @@ struct mdss_dsi_ctrl_pdata {
|
|||
struct mdss_dsi_debugfs_info *debugfs_info;
|
||||
|
||||
struct dsi_err_container err_cont;
|
||||
|
||||
bool dfps_status; /* dynamic refresh status */
|
||||
struct switch_dev sdev;
|
||||
bool hpd_state;
|
||||
bool ds_registered;
|
||||
|
||||
struct msm_dba_reg_info dba_info;
|
||||
struct msm_dba_ops dba_ops;
|
||||
struct msm_dba_video_cfg dba_video_cfg;
|
||||
void *dba_data;
|
||||
|
||||
void *edid_data;
|
||||
u8 edid_buf[EDID_BLOCK_SIZE * 2];
|
||||
|
||||
struct fb_info *fbi;
|
||||
|
||||
struct workqueue_struct *workq;
|
||||
struct delayed_work dba_work;
|
||||
};
|
||||
|
||||
struct dsi_status_data {
|
||||
|
|
|
@ -678,6 +678,7 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
|
|||
struct mdss_dsi_ctrl_pdata *ctrl = NULL;
|
||||
struct mdss_panel_info *pinfo;
|
||||
struct dsi_panel_cmds *on_cmds;
|
||||
int ret = 0;
|
||||
|
||||
if (pdata == NULL) {
|
||||
pr_err("%s: Invalid input data\n", __func__);
|
||||
|
@ -710,10 +711,17 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
|
|||
if (pinfo->compression_mode == COMPRESSION_DSC)
|
||||
mdss_dsi_panel_dsc_pps_send(ctrl);
|
||||
|
||||
if (ctrl->ds_registered) {
|
||||
if (ctrl->dba_ops.video_on)
|
||||
ret = ctrl->dba_ops.video_on(
|
||||
ctrl->dba_data, true,
|
||||
&ctrl->dba_video_cfg, 0);
|
||||
}
|
||||
|
||||
end:
|
||||
pinfo->blank_state = MDSS_PANEL_BLANK_UNBLANK;
|
||||
pr_debug("%s:-\n", __func__);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata)
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include "msm_dba_internal.h"
|
||||
|
||||
#define ADV7533_REG_CHIP_REVISION (0x00)
|
||||
#define ADV7533_RESET_DELAY (100)
|
||||
|
@ -34,13 +35,17 @@
|
|||
#define PINCTRL_STATE_SUSPEND "pmx_adv7533_suspend"
|
||||
|
||||
#define MDSS_MAX_PANEL_LEN 256
|
||||
#define EDID_SEG_SIZE 0x100
|
||||
|
||||
#define HPD_INT_ENABLE BIT(7)
|
||||
#define MONITOR_SENSE_INT_ENABLE BIT(6)
|
||||
#define EDID_READY_INT_ENABLE BIT(2)
|
||||
|
||||
#define MAX_WAIT_TIME (100)
|
||||
#define MAX_RW_TRIES (3)
|
||||
|
||||
enum adv7533_i2c_addr {
|
||||
ADV7533_MAIN = 0x39, /* 7a main right shift 1 */
|
||||
ADV7533_MAIN = 0x39,
|
||||
ADV7533_CEC_DSI = 0x3C,
|
||||
};
|
||||
|
||||
|
@ -64,7 +69,6 @@ struct adv7533_platform_data {
|
|||
int irq;
|
||||
u32 irq_gpio;
|
||||
u32 irq_flags;
|
||||
int hpd_irq;
|
||||
u32 hpd_irq_gpio;
|
||||
u32 hpd_irq_flags;
|
||||
u32 switch_gpio;
|
||||
|
@ -76,30 +80,52 @@ struct adv7533_platform_data {
|
|||
bool disable_gpios;
|
||||
bool adv_output;
|
||||
void *edid_data;
|
||||
u8 edid_buf[EDID_SEG_SIZE];
|
||||
struct workqueue_struct *workq;
|
||||
struct work_struct adv7533_int_work_id;
|
||||
struct delayed_work adv7533_intr_work_id;
|
||||
struct msm_dba_device_info dev_info;
|
||||
msm_dba_cb client_cb;
|
||||
void *client_cb_data;
|
||||
};
|
||||
|
||||
static struct adv7533_reg_cfg setup_cfg[] = {
|
||||
{ADV7533_MAIN, 0x41, 0x10}, /* HDMI normal */
|
||||
{ADV7533_MAIN, 0xd6, 0x48}, /* HPD overridden */
|
||||
{ADV7533_CEC_DSI, 0x03, 0x89}, /* HDMI enabled */
|
||||
static struct adv7533_reg_cfg adv7533_init_setup[] = {
|
||||
/* power down */
|
||||
{ADV7533_MAIN, 0x41, 0x50},
|
||||
/* HPD override */
|
||||
{ADV7533_MAIN, 0xD6, 0x48},
|
||||
/* color space */
|
||||
{ADV7533_MAIN, 0x16, 0x20},
|
||||
/* Fixed */
|
||||
{ADV7533_MAIN, 0x9A, 0xE0},
|
||||
/* HDCP */
|
||||
{ADV7533_MAIN, 0xBA, 0x70},
|
||||
/* Fixed */
|
||||
{ADV7533_MAIN, 0xDE, 0x82},
|
||||
{ADV7533_MAIN, 0xE4, 0xC0},
|
||||
/* V1P2 */
|
||||
{ADV7533_MAIN, 0xE4, 0x40},
|
||||
/* Fixed */
|
||||
{ADV7533_MAIN, 0xE5, 0x80},
|
||||
/* Fixed */
|
||||
{ADV7533_CEC_DSI, 0x15, 0xD0},
|
||||
/* Fixed */
|
||||
{ADV7533_CEC_DSI, 0x17, 0xD0},
|
||||
/* Fixed */
|
||||
{ADV7533_CEC_DSI, 0x24, 0x20},
|
||||
/* Fixed */
|
||||
{ADV7533_CEC_DSI, 0x57, 0x11},
|
||||
/* hdmi or dvi mode: hdmi */
|
||||
};
|
||||
|
||||
static struct adv7533_reg_cfg adv7533_video_setup[] = {
|
||||
/* power up */
|
||||
{ADV7533_MAIN, 0x41, 0x10},
|
||||
/* hdmi enable */
|
||||
{ADV7533_CEC_DSI, 0x03, 0x89},
|
||||
/* hdmi mode, hdcp */
|
||||
{ADV7533_MAIN, 0xAF, 0x06},
|
||||
{ADV7533_MAIN, 0x40, 0x80},
|
||||
/* color depth */
|
||||
{ADV7533_MAIN, 0x4C, 0x04},
|
||||
/* down dither */
|
||||
{ADV7533_MAIN, 0x49, 0x02},
|
||||
{ADV7533_MAIN, 0x0D, 1 << 6},
|
||||
};
|
||||
|
||||
static struct adv7533_reg_cfg tg_cfg_1080p[] = {
|
||||
|
@ -157,144 +183,6 @@ static struct adv7533_reg_cfg tg_cfg_1080p[] = {
|
|||
{ADV7533_CEC_DSI, 0x55, 0x00},
|
||||
};
|
||||
|
||||
static struct adv7533_reg_cfg tg_cfg_pattern_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 Enable (0x55[7] = 1) */
|
||||
{ADV7533_CEC_DSI, 0x55, 0x80},
|
||||
};
|
||||
|
||||
static struct adv7533_reg_cfg tg_cfg_720p[] = {
|
||||
{ADV7533_CEC_DSI, 0x1C, 0x30},
|
||||
/* hsync and vsync active low */
|
||||
{ADV7533_MAIN, 0x17, 0x02},
|
||||
/* Control for Pixel Clock Divider */
|
||||
{ADV7533_CEC_DSI, 0x16, 0x24},
|
||||
/* h_width 0x898 2200*/
|
||||
{ADV7533_CEC_DSI, 0x28, 0x67},
|
||||
{ADV7533_CEC_DSI, 0x29, 0x20},
|
||||
/* hsync_width 0x2C 44*/
|
||||
{ADV7533_CEC_DSI, 0x2A, 0x02},
|
||||
{ADV7533_CEC_DSI, 0x2B, 0x80},
|
||||
/* hfp 0x58 88 */
|
||||
{ADV7533_CEC_DSI, 0x2C, 0x06},
|
||||
{ADV7533_CEC_DSI, 0x2D, 0xE0},
|
||||
/* hbp 0x94 148 */
|
||||
{ADV7533_CEC_DSI, 0x2E, 0x0D},
|
||||
{ADV7533_CEC_DSI, 0x2F, 0xC0},
|
||||
/* v_total 0x465 1125 */
|
||||
{ADV7533_CEC_DSI, 0x30, 0x2E},
|
||||
{ADV7533_CEC_DSI, 0x31, 0xE0},
|
||||
/* 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, 0x50},
|
||||
/* vbp 0x24 36 */
|
||||
{ADV7533_CEC_DSI, 0x36, 0x01},
|
||||
{ADV7533_CEC_DSI, 0x37, 0x40},
|
||||
/* Test Pattern Disable (0x55[7] = 0) */
|
||||
{ADV7533_CEC_DSI, 0x55, 0x00},
|
||||
/* HDMI disabled */
|
||||
{ADV7533_CEC_DSI, 0x03, 0x09},
|
||||
/* HDMI enabled */
|
||||
{ADV7533_CEC_DSI, 0x03, 0x89},
|
||||
};
|
||||
|
||||
static struct adv7533_reg_cfg tg_cfg_pattern_720p[] = {
|
||||
{ADV7533_CEC_DSI, 0x1C, 0x30},
|
||||
/* hsync and vsync active low */
|
||||
{ADV7533_MAIN, 0x17, 0x02},
|
||||
/* Control for Pixel Clock Divider */
|
||||
{ADV7533_CEC_DSI, 0x16, 0x24},
|
||||
/* h_width 0x898 2200*/
|
||||
{ADV7533_CEC_DSI, 0x28, 0x67},
|
||||
{ADV7533_CEC_DSI, 0x29, 0x20},
|
||||
/* hsync_width 0x2C 44*/
|
||||
{ADV7533_CEC_DSI, 0x2A, 0x02},
|
||||
{ADV7533_CEC_DSI, 0x2B, 0x80},
|
||||
/* hfp 0x58 88 */
|
||||
{ADV7533_CEC_DSI, 0x2C, 0x06},
|
||||
{ADV7533_CEC_DSI, 0x2D, 0xE0},
|
||||
/* hbp 0x94 148 */
|
||||
{ADV7533_CEC_DSI, 0x2E, 0x0D},
|
||||
{ADV7533_CEC_DSI, 0x2F, 0xC0},
|
||||
/* v_total 0x465 1125 */
|
||||
{ADV7533_CEC_DSI, 0x30, 0x2E},
|
||||
{ADV7533_CEC_DSI, 0x31, 0xE0},
|
||||
/* 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, 0x50},
|
||||
/* vbp 0x24 36 */
|
||||
{ADV7533_CEC_DSI, 0x36, 0x01},
|
||||
{ADV7533_CEC_DSI, 0x37, 0x40},
|
||||
/* DSI Internal Timing Generator Enable register bit (0x27[7] = 1) */
|
||||
{ADV7533_CEC_DSI, 0x27, 0x8B},
|
||||
/* Test Pattern Enable (0x55[7] = 1) */
|
||||
{ADV7533_CEC_DSI, 0x55, 0x80},
|
||||
/* DSI Internal Timing Generator Reset Enable
|
||||
register bit (0x27[6] = 0) */
|
||||
{ADV7533_CEC_DSI, 0x27, 0x8B},
|
||||
/* DSI Internal Timing Generator Reset Enable
|
||||
register bit (0x27[6] = 1) */
|
||||
{ADV7533_CEC_DSI, 0x27, 0xCB},
|
||||
|
||||
{ADV7533_CEC_DSI, 0x03, 0x09},/* HDMI disabled */
|
||||
{ADV7533_CEC_DSI, 0x03, 0x89},/* HDMI enabled */
|
||||
};
|
||||
|
||||
static struct adv7533_reg_cfg I2S_cfg[] = {
|
||||
{ADV7533_MAIN, 0x0D, 0x18}, /* Bit width = 16Bits*/
|
||||
{ADV7533_MAIN, 0x15, 0x20}, /* Sampling Frequency = 48kHz*/
|
||||
|
@ -310,25 +198,10 @@ static struct adv7533_reg_cfg irq_config[] = {
|
|||
EDID_READY_INT_ENABLE},
|
||||
};
|
||||
|
||||
static struct adv7533_reg_cfg irq_clear[] = {
|
||||
{ADV7533_CEC_DSI, 0x38, BIT(7)},
|
||||
{ADV7533_CEC_DSI, 0x38, BIT(3)},
|
||||
{ADV7533_MAIN, 0x96, HPD_INT_ENABLE |
|
||||
MONITOR_SENSE_INT_ENABLE |
|
||||
EDID_READY_INT_ENABLE},
|
||||
};
|
||||
|
||||
static struct i2c_client *client;
|
||||
static struct adv7533_platform_data *pdata;
|
||||
static char mdss_mdp_panel[MDSS_MAX_PANEL_LEN];
|
||||
|
||||
/*
|
||||
* If i2c read or write fails, wait for 100ms to try again, and try
|
||||
* max 3 times.
|
||||
*/
|
||||
#define MAX_WAIT_TIME (100)
|
||||
#define MAX_RW_TRIES (3)
|
||||
|
||||
static int adv7533_read(u8 addr, u8 reg, u8 *buf, u8 len)
|
||||
{
|
||||
int ret = 0, i = 0;
|
||||
|
@ -664,102 +537,122 @@ static void adv7533_get_cmdline_config(void)
|
|||
pdata->video_mode = ADV7533_VIDEO_1080P;
|
||||
}
|
||||
|
||||
static void adv7533_int_work(struct work_struct *work)
|
||||
u32 adv7533_read_edid(u32 size, char *edid_buf)
|
||||
{
|
||||
u32 ret = 0, ndx;
|
||||
u8 edid_addr;
|
||||
u32 read_size = size / 2;
|
||||
|
||||
if (!edid_buf)
|
||||
return 0;
|
||||
|
||||
pr_debug("%s: size %d\n", __func__, size);
|
||||
|
||||
ret = adv7533_read(ADV7533_MAIN, 0x43, &edid_addr, 1);
|
||||
if (ret) {
|
||||
pr_err("%s: Error reading edid addr\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
pr_debug("%s: edid address 0x%x\n", __func__, edid_addr);
|
||||
|
||||
ret = adv7533_read(edid_addr >> 1, 0x00, edid_buf, read_size);
|
||||
if (ret) {
|
||||
pr_err("%s: Error reading edid 0\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = adv7533_read(edid_addr >> 1, read_size,
|
||||
edid_buf + read_size, read_size);
|
||||
if (ret) {
|
||||
pr_err("%s: Error reading edid 1\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (ndx = 0; ndx < size; ndx += 4)
|
||||
pr_info("%s: EDID[%02x-%02x] %02x %02x %02x %02x\n",
|
||||
__func__, ndx, ndx + 3,
|
||||
edid_buf[ndx + 0], edid_buf[ndx + 1],
|
||||
edid_buf[ndx + 2], edid_buf[ndx + 3]);
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void adv7533_intr_work(struct work_struct *work)
|
||||
{
|
||||
u8 dsi_irq_status;
|
||||
u8 int_status;
|
||||
u8 int_state;
|
||||
u32 ret = 0;
|
||||
|
||||
int ret;
|
||||
struct adv7533_platform_data *pdata;
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
|
||||
pdata = container_of(work, struct adv7533_platform_data,
|
||||
adv7533_int_work_id);
|
||||
if (!pdata)
|
||||
pdata = container_of(dw, struct adv7533_platform_data,
|
||||
adv7533_intr_work_id);
|
||||
if (!pdata) {
|
||||
pr_err("%s: invalid input\n", __func__);
|
||||
return;
|
||||
|
||||
/* Read DSI RX Turn On Status */
|
||||
adv7533_read_byte(ADV7533_CEC_DSI, 0x40, &dsi_irq_status);
|
||||
if (dsi_irq_status & 0x10)
|
||||
pr_debug("%s DSI RX turned on\n", __func__);
|
||||
}
|
||||
|
||||
/* READ Interrupt registers */
|
||||
adv7533_read_byte(ADV7533_MAIN, 0x96, &int_status);
|
||||
adv7533_read_byte(ADV7533_MAIN, 0x42, &int_state);
|
||||
|
||||
if (int_status & BIT(7)) {
|
||||
pr_debug("%s: GOT HPD INTR\n", __func__);
|
||||
if (int_state & BIT(6)) {
|
||||
pr_debug("%s: CABLE CONNECTED\n", __func__);
|
||||
} else {
|
||||
pr_debug("%s: CABLE DISCONNECTED\n", __func__);
|
||||
goto p_err_regs;
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & BIT(6)) {
|
||||
pr_debug("%s: GOT Rx SENSE\n", __func__);
|
||||
if (int_state & BIT(5)) {
|
||||
pr_debug("%s: Rx SENSE CLK TERMINATION\n", __func__);
|
||||
ret = adv7533_write_regs(pdata, setup_cfg,
|
||||
ARRAY_SIZE(setup_cfg));
|
||||
if (ret != 0) {
|
||||
pr_err("%s: Failed to write common config\n",
|
||||
__func__);
|
||||
goto p_err_regs;
|
||||
pr_info("%s: Rx SENSE CABLE CONNECTED\n", __func__);
|
||||
|
||||
/* initiate edid read in adv7533 */
|
||||
ret = adv7533_write_byte(pdata->main_i2c_addr,
|
||||
0xC9, 0x13);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed: edid read adv %d\n",
|
||||
__func__, ret);
|
||||
pdata->client_cb(pdata->client_cb_data,
|
||||
MSM_DBA_CB_HPD_CONNECT);
|
||||
}
|
||||
|
||||
} else {
|
||||
pr_info("%s: NO Rx SENSE CABLE DISCONNECTED\n",
|
||||
__func__);
|
||||
pdata->client_cb(pdata->client_cb_data,
|
||||
MSM_DBA_CB_HPD_DISCONNECT);
|
||||
}
|
||||
}
|
||||
|
||||
/* EDID ready for read */
|
||||
if (int_status & BIT(2)) {
|
||||
pr_debug("%s: GOT EDID READY INTR\n", __func__);
|
||||
pr_info("%s: EDID READY\n", __func__);
|
||||
|
||||
switch (pdata->video_mode) {
|
||||
case ADV7533_VIDEO_PATTERN:
|
||||
ret = adv7533_write_regs(pdata, tg_cfg_pattern_1080p,
|
||||
ARRAY_SIZE(tg_cfg_pattern_1080p));
|
||||
if (ret != 0) {
|
||||
pr_err("%s: err config pattern 1080p %d\n",
|
||||
__func__, ret);
|
||||
goto p_err_regs;
|
||||
}
|
||||
break;
|
||||
case ADV7533_VIDEO_480P:
|
||||
case ADV7533_VIDEO_720P:
|
||||
ret = adv7533_write_regs(pdata, tg_cfg_pattern_720p,
|
||||
ARRAY_SIZE(tg_cfg_pattern_720p));
|
||||
ret = adv7533_write_regs(pdata, tg_cfg_720p,
|
||||
ARRAY_SIZE(tg_cfg_720p));
|
||||
if (ret != 0) {
|
||||
pr_err("%s: err config pattern 720p %d\n",
|
||||
__func__, ret);
|
||||
goto p_err_regs;
|
||||
}
|
||||
break;
|
||||
case ADV7533_VIDEO_1080P:
|
||||
default:
|
||||
ret = adv7533_write_regs(pdata, tg_cfg_1080p,
|
||||
ARRAY_SIZE(tg_cfg_1080p));
|
||||
if (ret != 0) {
|
||||
pr_err("%s: err config 1080p %d\n",
|
||||
__func__, ret);
|
||||
goto p_err_regs;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ret = adv7533_read_edid(sizeof(pdata->edid_buf),
|
||||
pdata->edid_buf);
|
||||
if (ret)
|
||||
pr_err("%s: edid read failed\n", __func__);
|
||||
|
||||
pdata->client_cb(pdata->client_cb_data,
|
||||
MSM_DBA_CB_HPD_CONNECT);
|
||||
}
|
||||
|
||||
p_err_regs:
|
||||
/* Clear and enable interrupts */
|
||||
adv7533_write_regs(pdata, irq_clear, ARRAY_SIZE(irq_clear));
|
||||
/*adv7533_write_regs(pdata, irq_config, ARRAY_SIZE(irq_config));*/
|
||||
/* Clear interrupts */
|
||||
ret = adv7533_write_byte(pdata->main_i2c_addr, 0x96, int_status);
|
||||
if (ret)
|
||||
pr_err("%s: Failed: clear interrupts %d\n", __func__, ret);
|
||||
|
||||
ret = adv7533_write_regs(pdata, irq_config, ARRAY_SIZE(irq_config));
|
||||
if (ret)
|
||||
pr_err("%s: Failed: irq config %d\n", __func__, ret);
|
||||
}
|
||||
|
||||
static irqreturn_t adv7533_irq(int irq, void *data)
|
||||
{
|
||||
queue_work(pdata->workq, &pdata->adv7533_int_work_id);
|
||||
int ret;
|
||||
|
||||
/* disable interrupts */
|
||||
ret = adv7533_write_byte(pdata->main_i2c_addr, 0x94, 0x00);
|
||||
if (ret)
|
||||
pr_err("%s: Failed: disable interrupts %d\n",
|
||||
__func__, ret);
|
||||
|
||||
queue_delayed_work(pdata->workq, &pdata->adv7533_intr_work_id, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -769,11 +662,175 @@ static struct i2c_device_id adv7533_id[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static struct adv7533_platform_data *adv7533_get_platform_data(void *client)
|
||||
{
|
||||
struct adv7533_platform_data *pdata = NULL;
|
||||
struct msm_dba_device_info *dev;
|
||||
struct msm_dba_client_info *cinfo =
|
||||
(struct msm_dba_client_info *)client;
|
||||
|
||||
if (!cinfo) {
|
||||
pr_err("%s: invalid client data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
dev = cinfo->dev;
|
||||
if (!dev) {
|
||||
pr_err("%s: invalid device data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
pdata = container_of(dev, struct adv7533_platform_data, dev_info);
|
||||
if (!pdata)
|
||||
pr_err("%s: invalid platform data\n", __func__);
|
||||
|
||||
end:
|
||||
return pdata;
|
||||
}
|
||||
|
||||
/* Device Operations */
|
||||
static int adv7533_power_on(void *client, bool on, u32 flags)
|
||||
{
|
||||
int ret = 0;
|
||||
struct adv7533_platform_data *pdata =
|
||||
adv7533_get_platform_data(client);
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s: invalid platform data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = adv7533_write_regs(pdata, adv7533_init_setup,
|
||||
ARRAY_SIZE(adv7533_init_setup));
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to write common config\n",
|
||||
__func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = adv7533_write_regs(pdata, irq_config, ARRAY_SIZE(irq_config));
|
||||
if (ret) {
|
||||
pr_err("%s: Failed: irq config %d\n", __func__, ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
queue_delayed_work(pdata->workq, &pdata->adv7533_intr_work_id, HZ/2);
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7533_video_on(void *client, bool on,
|
||||
struct msm_dba_video_cfg *cfg, u32 flags)
|
||||
{
|
||||
int ret = 0;
|
||||
struct adv7533_platform_data *pdata =
|
||||
adv7533_get_platform_data(client);
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s: invalid platform data\n", __func__);
|
||||
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;
|
||||
}
|
||||
|
||||
ret = adv7533_write_regs(pdata, adv7533_video_setup,
|
||||
ARRAY_SIZE(adv7533_video_setup));
|
||||
if (ret)
|
||||
pr_err("%s: Failed: video setup\n", __func__);
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7533_get_edid_size(void *client,
|
||||
u32 *size, u32 flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!size) {
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
*size = EDID_SEG_SIZE;
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7533_get_raw_edid(void *client,
|
||||
u32 size, char *buf, u32 flags)
|
||||
{
|
||||
struct adv7533_platform_data *pdata =
|
||||
adv7533_get_platform_data(client);
|
||||
|
||||
if (!pdata || !buf) {
|
||||
pr_err("%s: invalid data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
size = size > sizeof(pdata->edid_buf) ? sizeof(pdata->edid_buf) : size;
|
||||
|
||||
memcpy(buf, pdata->edid_buf, size);
|
||||
end:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7533_reg_fxn(struct msm_dba_client_info *cinfo)
|
||||
{
|
||||
int ret = 0;
|
||||
struct adv7533_platform_data *pdata =
|
||||
adv7533_get_platform_data((void *)cinfo);
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s: invalid platform data\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
pdata->client_cb = cinfo->cb;
|
||||
pdata->client_cb_data = cinfo->cb_data;
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7533_register_dba(struct adv7533_platform_data *pdata)
|
||||
{
|
||||
struct msm_dba_ops *client_ops;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
client_ops = &pdata->dev_info.client_ops;
|
||||
|
||||
client_ops->power_on = adv7533_power_on;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
INIT_LIST_HEAD(&pdata->dev_info.client_list);
|
||||
|
||||
return msm_dba_add_probed_device(&pdata->dev_info);
|
||||
}
|
||||
|
||||
|
||||
static int adv7533_probe(struct i2c_client *client_,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
client = client_;
|
||||
|
||||
if (client->dev.of_node) {
|
||||
|
@ -795,6 +852,11 @@ static int adv7533_probe(struct i2c_client *client_,
|
|||
goto p_err;
|
||||
}
|
||||
|
||||
ret = adv7533_register_dba(pdata);
|
||||
if (ret)
|
||||
pr_err("%s: Error registering with DBA %d\n",
|
||||
__func__, ret);
|
||||
|
||||
ret = pinctrl_select_state(pdata->ts_pinctrl,
|
||||
pdata->pinctrl_state_active);
|
||||
if (ret < 0)
|
||||
|
@ -829,46 +891,6 @@ static int adv7533_probe(struct i2c_client *client_,
|
|||
goto p_err;
|
||||
}
|
||||
|
||||
ret = adv7533_write_regs(pdata, setup_cfg, ARRAY_SIZE(setup_cfg));
|
||||
if (ret != 0) {
|
||||
pr_err("%s: Failed to write common config\n", __func__);
|
||||
goto p_err;
|
||||
}
|
||||
|
||||
switch (pdata->video_mode) {
|
||||
case ADV7533_VIDEO_PATTERN:
|
||||
ret = adv7533_write_regs(pdata, tg_cfg_pattern_1080p,
|
||||
ARRAY_SIZE(tg_cfg_pattern_1080p));
|
||||
if (ret != 0) {
|
||||
pr_err("%s: adv7533 pattern config i2c fails [%d]\n",
|
||||
__func__, ret);
|
||||
goto p_err;
|
||||
}
|
||||
break;
|
||||
case ADV7533_VIDEO_480P:
|
||||
case ADV7533_VIDEO_720P:
|
||||
ret = adv7533_write_regs(pdata, tg_cfg_pattern_720p,
|
||||
ARRAY_SIZE(tg_cfg_pattern_720p));
|
||||
ret = adv7533_write_regs(pdata, tg_cfg_720p,
|
||||
ARRAY_SIZE(tg_cfg_720p));
|
||||
if (ret != 0) {
|
||||
pr_err("%s: adv7533 pattern config i2c fails [%d]\n",
|
||||
__func__, ret);
|
||||
goto p_err;
|
||||
}
|
||||
break;
|
||||
case ADV7533_VIDEO_1080P:
|
||||
default:
|
||||
ret = adv7533_write_regs(pdata, tg_cfg_1080p,
|
||||
ARRAY_SIZE(tg_cfg_1080p));
|
||||
if (ret != 0) {
|
||||
pr_err("%s: adv7533 1080p config i2c fails [%d]\n",
|
||||
__func__, ret);
|
||||
goto p_err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pdata->audio) {
|
||||
ret = adv7533_write_regs(pdata, I2S_cfg, ARRAY_SIZE(I2S_cfg));
|
||||
if (ret != 0) {
|
||||
|
@ -884,14 +906,7 @@ static int adv7533_probe(struct i2c_client *client_,
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
INIT_WORK(&pdata->adv7533_int_work_id, adv7533_int_work);
|
||||
|
||||
ret = adv7533_write_regs(pdata, irq_config, ARRAY_SIZE(irq_config));
|
||||
if (ret) {
|
||||
pr_err("%s: intr config i2c fails with ret = %d!\n",
|
||||
__func__, ret);
|
||||
goto p_err;
|
||||
}
|
||||
INIT_DELAYED_WORK(&pdata->adv7533_intr_work_id, adv7533_intr_work);
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
pm_runtime_set_active(&client->dev);
|
||||
|
@ -909,6 +924,9 @@ static int adv7533_remove(struct i2c_client *client)
|
|||
int ret = 0;
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
disable_irq(pdata->irq);
|
||||
free_irq(pdata->irq, pdata);
|
||||
|
||||
ret = adv7533_gpio_configure(pdata, false);
|
||||
|
||||
devm_kfree(&client->dev, pdata);
|
||||
|
|
Loading…
Add table
Reference in a new issue