mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
misc: rk628: enable/disable display by fb .notifier_call helper
Change-Id: I485d374d1441f6e04a9adc20f4d5fab77782059e Signed-off-by: Guochun Huang <hero.huang@rock-chips.com>
This commit is contained in:
@@ -357,6 +357,25 @@ static const struct regmap_config rk628_regmap_config[RK628_DEV_MAX] = {
|
||||
},
|
||||
};
|
||||
|
||||
static void rk628_power_on(struct rk628 *rk628, bool on)
|
||||
{
|
||||
if (!rk628->display_enabled && on) {
|
||||
gpiod_set_value(rk628->enable_gpio, 1);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 0);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 1);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 0);
|
||||
usleep_range(10000, 11000);
|
||||
}
|
||||
|
||||
if (!on) {
|
||||
gpiod_set_value(rk628->reset_gpio, 1);
|
||||
gpiod_set_value(rk628->enable_gpio, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void rk628_display_disable(struct rk628 *rk628)
|
||||
{
|
||||
if (!rk628->display_enabled)
|
||||
@@ -374,6 +393,9 @@ static void rk628_display_disable(struct rk628 *rk628)
|
||||
if (rk628->output_mode == OUTPUT_MODE_DSI)
|
||||
rk628_dsi_disable(rk628);
|
||||
|
||||
if (rk628->output_mode == OUTPUT_MODE_RGB)
|
||||
rk628_rgb_tx_disable(rk628);
|
||||
|
||||
rk628_post_process_disable(rk628);
|
||||
|
||||
if (rk628->input_mode == INPUT_MODE_HDMI)
|
||||
@@ -382,52 +404,6 @@ static void rk628_display_disable(struct rk628 *rk628)
|
||||
rk628->display_enabled = false;
|
||||
}
|
||||
|
||||
static void rk628_display_resume(struct rk628 *rk628)
|
||||
{
|
||||
u8 ret = 0;
|
||||
|
||||
if (rk628->display_enabled)
|
||||
return;
|
||||
|
||||
if (rk628->input_mode == INPUT_MODE_HDMI) {
|
||||
ret = rk628_hdmirx_enable(rk628);
|
||||
if ((ret == HDMIRX_PLUGOUT) || (ret & HDMIRX_NOSIGNAL)) {
|
||||
rk628_display_disable(rk628);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (rk628->input_mode == INPUT_MODE_RGB)
|
||||
rk628_rgb_rx_enable(rk628);
|
||||
|
||||
if (rk628->input_mode == INPUT_MODE_BT1120)
|
||||
rk628_bt1120_rx_enable(rk628);
|
||||
|
||||
rk628_post_process_init(rk628);
|
||||
rk628_post_process_enable(rk628);
|
||||
|
||||
if (rk628->output_mode == OUTPUT_MODE_DSI) {
|
||||
rk628_mipi_dsi_pre_enable(rk628);
|
||||
rk628_mipi_dsi_enable(rk628);
|
||||
}
|
||||
|
||||
if (rk628->output_mode == OUTPUT_MODE_LVDS)
|
||||
rk628_lvds_enable(rk628);
|
||||
|
||||
if (rk628->output_mode == OUTPUT_MODE_GVI)
|
||||
rk628_gvi_enable(rk628);
|
||||
|
||||
if (rk628->output_mode == OUTPUT_MODE_CSI)
|
||||
rk628_csi_enable(rk628);
|
||||
|
||||
#ifdef CONFIG_RK628_MISC_HDMITX
|
||||
if (rk628->output_mode == OUTPUT_MODE_HDMI)
|
||||
rk628_hdmitx_enable(rk628);
|
||||
#endif
|
||||
|
||||
rk628->display_enabled = true;
|
||||
}
|
||||
|
||||
static void rk628_display_enable(struct rk628 *rk628)
|
||||
{
|
||||
u8 ret = 0;
|
||||
@@ -441,8 +417,8 @@ static void rk628_display_enable(struct rk628 *rk628)
|
||||
if (rk628->input_mode == INPUT_MODE_BT1120)
|
||||
rk628_bt1120_rx_enable(rk628);
|
||||
|
||||
if (rk628->output_mode == OUTPUT_MODE_BT1120)
|
||||
rk628_bt1120_tx_enable(rk628);
|
||||
if (rk628->output_mode == OUTPUT_MODE_RGB)
|
||||
rk628_rgb_tx_enable(rk628);
|
||||
|
||||
if (rk628->output_mode == OUTPUT_MODE_DSI)
|
||||
queue_delayed_work(rk628->dsi_wq, &rk628->dsi_delay_work, msecs_to_jiffies(10));
|
||||
@@ -455,6 +431,9 @@ static void rk628_display_enable(struct rk628 *rk628)
|
||||
}
|
||||
}
|
||||
|
||||
if (rk628->output_mode == OUTPUT_MODE_BT1120)
|
||||
rk628_bt1120_tx_enable(rk628);
|
||||
|
||||
if (rk628->output_mode != OUTPUT_MODE_HDMI) {
|
||||
rk628_post_process_init(rk628);
|
||||
rk628_post_process_enable(rk628);
|
||||
@@ -477,6 +456,60 @@ static void rk628_display_enable(struct rk628 *rk628)
|
||||
rk628->display_enabled = true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FB
|
||||
static int rk628_fb_notifier_callback(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct rk628 *rk628 = container_of(nb, struct rk628, fb_nb);
|
||||
struct fb_event *ev_data = data;
|
||||
int *blank;
|
||||
|
||||
if ((event != FB_EVENT_BLANK) || (!ev_data) || (!ev_data->data))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
blank = ev_data->data;
|
||||
|
||||
switch (*blank) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
rk628_power_on(rk628, true);
|
||||
/* select int io function */
|
||||
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x30002000);
|
||||
rk628_cru_init(rk628);
|
||||
|
||||
if (rk628->input_mode == INPUT_MODE_HDMI) {
|
||||
rk628_i2c_write(rk628, GRF_INTR0_EN, 0x01000100);
|
||||
/*
|
||||
* make hdmi rx register domain polling
|
||||
* access to be normal by setting hdmi in
|
||||
*/
|
||||
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
|
||||
SW_INPUT_MODE_MASK,
|
||||
SW_INPUT_MODE(INPUT_MODE_HDMI));
|
||||
|
||||
queue_delayed_work(rk628->monitor_wq,
|
||||
&rk628->delay_work,
|
||||
msecs_to_jiffies(50));
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
rk628_display_enable(rk628);
|
||||
|
||||
return NOTIFY_OK;
|
||||
case FB_BLANK_POWERDOWN:
|
||||
if (rk628->input_mode == INPUT_MODE_HDMI)
|
||||
cancel_delayed_work_sync(&rk628->delay_work);
|
||||
|
||||
rk628_display_disable(rk628);
|
||||
rk628_power_on(rk628, false);
|
||||
|
||||
return NOTIFY_OK;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rk628_display_work(struct work_struct *work)
|
||||
{
|
||||
u8 ret = 0;
|
||||
@@ -486,6 +519,7 @@ static void rk628_display_work(struct work_struct *work)
|
||||
|
||||
if (rk628->input_mode == INPUT_MODE_HDMI) {
|
||||
ret = rk628_hdmirx_detect(rk628);
|
||||
dev_info(rk628->dev, "%s: hdmirx detect status:0x%x\n", __func__, ret);
|
||||
if (!(ret & (HDMIRX_CHANGED | HDMIRX_NOLOCK))) {
|
||||
if (!rk628->plugin_det_gpio)
|
||||
queue_delayed_work(rk628->monitor_wq,
|
||||
@@ -572,13 +606,17 @@ static int rk628_display_route_info_parse(struct rk628 *rk628)
|
||||
} else if (of_find_node_by_name(rk628->dev->of_node, "rk628-gvi")) {
|
||||
np = of_find_node_by_name(rk628->dev->of_node, "rk628-gvi");
|
||||
ret = rk628_gvi_parse(rk628, np);
|
||||
} else if (of_find_node_by_name(rk628->dev->of_node, "rk628-bt1120")) {
|
||||
} else if (of_property_read_bool(rk628->dev->of_node, "rk628-bt1120")) {
|
||||
rk628->output_mode = OUTPUT_MODE_BT1120;
|
||||
} else if (of_property_read_bool(rk628->dev->of_node, "rk628,hdmi-out")) {
|
||||
rk628->output_mode = OUTPUT_MODE_HDMI;
|
||||
} else if (of_property_read_bool(rk628->dev->of_node, "rk628,csi-out")) {
|
||||
rk628->output_mode = OUTPUT_MODE_CSI;
|
||||
} else if (of_property_read_bool(rk628->dev->of_node, "rk628-rgb")) {
|
||||
ret = rk628_rgb_parse(rk628, NULL);
|
||||
rk628->output_mode = OUTPUT_MODE_RGB;
|
||||
} else {
|
||||
if (of_property_read_bool(rk628->dev->of_node, "rk628,hdmi-out"))
|
||||
rk628->output_mode = OUTPUT_MODE_HDMI;
|
||||
else if (of_property_read_bool(rk628->dev->of_node, "rk628,csi-out"))
|
||||
rk628->output_mode = OUTPUT_MODE_CSI;
|
||||
rk628->output_mode = OUTPUT_MODE_RGB;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(rk628->dev->of_node, "mode-sync-pol", &val) < 0)
|
||||
@@ -613,7 +651,7 @@ rk628_display_mode_from_videomode(const struct rk628_videomode *vm,
|
||||
static void
|
||||
of_parse_rk628_display_timing(struct device_node *np, struct rk628_videomode *vm)
|
||||
{
|
||||
u8 val;
|
||||
u32 val;
|
||||
|
||||
of_property_read_u32(np, "clock-frequency", &vm->pixelclock);
|
||||
of_property_read_u32(np, "hactive", &vm->hactive);
|
||||
@@ -627,10 +665,10 @@ of_parse_rk628_display_timing(struct device_node *np, struct rk628_videomode *vm
|
||||
of_property_read_u32(np, "vsync-len", &vm->vsync_len);
|
||||
|
||||
vm->flags = 0;
|
||||
of_property_read_u8(np, "hsync-active", &val);
|
||||
of_property_read_u32(np, "hsync-active", &val);
|
||||
vm->flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
|
||||
|
||||
of_property_read_u8(np, "vsync-active", &val);
|
||||
of_property_read_u32(np, "vsync-active", &val);
|
||||
vm->flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
|
||||
}
|
||||
|
||||
@@ -1076,10 +1114,9 @@ rk628_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rk628->output_mode != OUTPUT_MODE_HDMI &&
|
||||
rk628->output_mode != OUTPUT_MODE_CSI) {
|
||||
if (rk628->output_mode != OUTPUT_MODE_CSI) {
|
||||
ret = rk628_display_timings_get(rk628);
|
||||
if (ret) {
|
||||
if (ret && rk628->output_mode != OUTPUT_MODE_HDMI) {
|
||||
dev_info(dev, "display timings err\n");
|
||||
return ret;
|
||||
}
|
||||
@@ -1120,14 +1157,7 @@ rk628_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiod_set_value(rk628->enable_gpio, 1);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 0);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 1);
|
||||
usleep_range(10000, 11000);
|
||||
gpiod_set_value(rk628->reset_gpio, 0);
|
||||
usleep_range(10000, 11000);
|
||||
rk628_power_on(rk628, true);
|
||||
|
||||
for (i = 0; i < RK628_DEV_MAX; i++) {
|
||||
const struct regmap_config *config = &rk628_regmap_config[i];
|
||||
@@ -1151,6 +1181,10 @@ rk628_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FB
|
||||
rk628->fb_nb.notifier_call = rk628_fb_notifier_callback;
|
||||
fb_register_client(&rk628->fb_nb);
|
||||
#endif
|
||||
rk628->monitor_wq = alloc_ordered_workqueue("%s",
|
||||
WQ_MEM_RECLAIM | WQ_FREEZABLE, "rk628-monitor-wq");
|
||||
INIT_DELAYED_WORK(&rk628->delay_work, rk628_display_work);
|
||||
@@ -1231,6 +1265,9 @@ static int rk628_i2c_remove(struct i2c_client *client)
|
||||
destroy_workqueue(rk628->dsi_wq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FB
|
||||
fb_unregister_client(&rk628->fb_nb);
|
||||
#endif
|
||||
cancel_delayed_work_sync(&rk628->delay_work);
|
||||
destroy_workqueue(rk628->monitor_wq);
|
||||
pm_runtime_disable(dev);
|
||||
@@ -1238,12 +1275,14 @@ static int rk628_i2c_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_FB
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int rk628_suspend(struct device *dev)
|
||||
{
|
||||
struct rk628 *rk628 = dev_get_drvdata(dev);
|
||||
|
||||
rk628_display_disable(rk628);
|
||||
rk628_power_on(rk628, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1252,18 +1291,40 @@ static int rk628_resume(struct device *dev)
|
||||
{
|
||||
struct rk628 *rk628 = dev_get_drvdata(dev);
|
||||
|
||||
rk628_display_resume(rk628);
|
||||
rk628_power_on(rk628, true);
|
||||
/* select int io function */
|
||||
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x30002000);
|
||||
rk628_cru_init(rk628);
|
||||
|
||||
if (rk628->input_mode == INPUT_MODE_HDMI) {
|
||||
rk628_i2c_write(rk628, GRF_INTR0_EN, 0x01000100);
|
||||
/*
|
||||
* make hdmi rx register domain polling
|
||||
* access to be normal by setting hdmi in
|
||||
*/
|
||||
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
|
||||
SW_INPUT_MODE_MASK,
|
||||
SW_INPUT_MODE(INPUT_MODE_HDMI));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
rk628_display_enable(rk628);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops rk628_pm_ops = {
|
||||
#ifndef CONFIG_FB
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend = rk628_suspend,
|
||||
.resume = rk628_resume,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct of_device_id rk628_of_match[] = {
|
||||
{ .compatible = "rockchip,rk628", },
|
||||
{}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/of.h>
|
||||
@@ -452,6 +453,7 @@ struct rk628 {
|
||||
struct rk628_combtxphy combtxphy;
|
||||
int sync_pol;
|
||||
void *csi;
|
||||
struct notifier_block fb_nb;
|
||||
};
|
||||
|
||||
static inline int rk628_i2c_write(struct rk628 *rk628, u32 reg, u32 val)
|
||||
|
||||
Reference in New Issue
Block a user