You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
drm/rockchip: panel-notifier: add panel notifier for panel-related device
Type: Function Redmine ID: N/A Associated modifications: N/A Test: N/A Signed-off-by: Zhibin Huang <zhibin.huang@rock-chips.com> Change-Id: I22fb562772fcbf3808d61c7419407bf50d947e0d
This commit is contained in:
@@ -129,6 +129,14 @@ config ROCKCHIP_LVDS
|
||||
support LVDS, rgb, dual LVDS output mode. say Y to enable its
|
||||
driver.
|
||||
|
||||
config ROCKCHIP_PANEL_NOTIFIER
|
||||
tristate "Rockchip panel notifier"
|
||||
depends on OF
|
||||
help
|
||||
Say Y here if you want to enable support for the panel notifier. The
|
||||
notifier is used to notify other devices (such as TP) to perform the
|
||||
corresponding action when the panel is in different actions.
|
||||
|
||||
config ROCKCHIP_RGB
|
||||
bool "Rockchip RGB support"
|
||||
depends on PINCTRL
|
||||
|
||||
@@ -28,6 +28,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o
|
||||
rockchipdrm-$(CONFIG_ROCKCHIP_VCONN) += rockchip_drm_vconn.o
|
||||
rockchipdrm-$(CONFIG_DRM_ROCKCHIP_VVOP) += rockchip_drm_vvop.o
|
||||
|
||||
obj-$(CONFIG_ROCKCHIP_PANEL_NOTIFIER) += rockchip_panel_notifier.o
|
||||
obj-$(CONFIG_ROCKCHIP_DW_HDCP2) += dw_hdcp2.o
|
||||
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
|
||||
obj-$(CONFIG_DRM_ROCKCHIP_RK618) += rk618/
|
||||
|
||||
223
drivers/gpu/drm/rockchip/rockchip_panel_notifier.c
Normal file
223
drivers/gpu/drm/rockchip/rockchip_panel_notifier.c
Normal file
@@ -0,0 +1,223 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
|
||||
* Author: Zhibin Huang <zhibin.huang@rock-chips.com>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/rockchip-panel-notifier.h>
|
||||
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
struct rockchip_panel_notifier_client {
|
||||
struct list_head list;
|
||||
struct rockchip_panel_notifier *pn;
|
||||
struct notifier_block *nb;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(notifier_list_lock);
|
||||
static LIST_HEAD(notifier_list);
|
||||
static DEFINE_MUTEX(notifier_client_list_lock);
|
||||
static LIST_HEAD(notifier_client_list);
|
||||
|
||||
static int
|
||||
rockchip_panel_notifier_register_client(struct device *dev,
|
||||
struct rockchip_panel_notifier_client **client)
|
||||
{
|
||||
struct rockchip_panel_notifier_client *this = *client;
|
||||
struct rockchip_panel_notifier *pn;
|
||||
struct device_node *node;
|
||||
struct drm_panel *panel;
|
||||
int ret;
|
||||
|
||||
if (!dev || !dev->of_node || !this->nb)
|
||||
return -EINVAL;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "rockchip,panel-notifier", 0);
|
||||
if (!node)
|
||||
return -ENODEV;
|
||||
|
||||
panel = of_drm_find_panel(node);
|
||||
if (IS_ERR(panel)) {
|
||||
of_node_put(node);
|
||||
return PTR_ERR(panel);
|
||||
}
|
||||
|
||||
of_node_put(node);
|
||||
|
||||
mutex_lock(¬ifier_list_lock);
|
||||
list_for_each_entry(pn, ¬ifier_list, list) {
|
||||
if (pn->panel == panel)
|
||||
goto find;
|
||||
}
|
||||
pn = NULL;
|
||||
find:
|
||||
mutex_unlock(¬ifier_list_lock);
|
||||
if (!pn)
|
||||
return -ENODEV;
|
||||
|
||||
ret = blocking_notifier_chain_register(&pn->nh, this->nb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
this->pn = pn;
|
||||
|
||||
mutex_lock(¬ifier_client_list_lock);
|
||||
list_add_tail(&this->list, ¬ifier_client_list);
|
||||
mutex_unlock(¬ifier_client_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rockchip_panel_notifier_unregister_client(struct rockchip_panel_notifier_client *client)
|
||||
{
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
blocking_notifier_chain_unregister(&client->pn->nh, client->nb);
|
||||
}
|
||||
|
||||
static void
|
||||
devm_rockchip_panel_notifier_unreg_client(struct device *dev, void *res)
|
||||
{
|
||||
struct rockchip_panel_notifier_client *pn_client, *next, *client = res;
|
||||
|
||||
mutex_lock(¬ifier_client_list_lock);
|
||||
list_for_each_entry_safe(pn_client, next, ¬ifier_client_list, list) {
|
||||
if (pn_client != client)
|
||||
continue;
|
||||
|
||||
rockchip_panel_notifier_unregister_client(pn_client);
|
||||
list_del_init(&pn_client->list);
|
||||
}
|
||||
mutex_unlock(¬ifier_client_list_lock);
|
||||
}
|
||||
|
||||
int devm_rockchip_panel_notifier_register_client(struct device *dev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
int ret;
|
||||
struct rockchip_panel_notifier_client *pn_client;
|
||||
|
||||
if (!dev || !nb)
|
||||
return -EINVAL;
|
||||
|
||||
pn_client = devres_alloc(devm_rockchip_panel_notifier_unreg_client,
|
||||
sizeof(*pn_client), GFP_KERNEL);
|
||||
if (!pn_client)
|
||||
return -ENOMEM;
|
||||
|
||||
pn_client->nb = nb;
|
||||
|
||||
ret = rockchip_panel_notifier_register_client(dev, &pn_client);
|
||||
if (ret) {
|
||||
devres_free(pn_client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
devres_add(dev, pn_client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_rockchip_panel_notifier_register_client);
|
||||
|
||||
void devm_rockchip_panel_notifier_unregister_client(struct device *dev)
|
||||
{
|
||||
WARN_ON(devres_release(dev, devm_rockchip_panel_notifier_unreg_client,
|
||||
NULL, NULL));
|
||||
}
|
||||
EXPORT_SYMBOL(devm_rockchip_panel_notifier_unregister_client);
|
||||
|
||||
static int rockchip_panel_notifier_register(struct drm_panel *panel,
|
||||
struct rockchip_panel_notifier *pn)
|
||||
{
|
||||
if (!panel || !pn)
|
||||
return -EINVAL;
|
||||
|
||||
pn->panel = panel;
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&pn->nh);
|
||||
|
||||
mutex_lock(¬ifier_list_lock);
|
||||
list_add_tail(&pn->list, ¬ifier_list);
|
||||
mutex_unlock(¬ifier_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_panel_notifier_unregister(struct rockchip_panel_notifier *pn)
|
||||
{
|
||||
struct rockchip_panel_notifier_client *pn_client, *next;
|
||||
|
||||
if (!pn)
|
||||
return;
|
||||
|
||||
mutex_lock(¬ifier_client_list_lock);
|
||||
list_for_each_entry_safe(pn_client, next, ¬ifier_client_list, list) {
|
||||
if (pn_client->pn != pn)
|
||||
continue;
|
||||
|
||||
rockchip_panel_notifier_unregister_client(pn_client);
|
||||
list_del_init(&pn_client->list);
|
||||
}
|
||||
mutex_unlock(¬ifier_client_list_lock);
|
||||
|
||||
mutex_lock(¬ifier_list_lock);
|
||||
list_del_init(&pn->list);
|
||||
mutex_unlock(¬ifier_list_lock);
|
||||
}
|
||||
|
||||
static void devm_rockchip_panel_notifier_unreg(struct device *dev, void *res)
|
||||
{
|
||||
rockchip_panel_notifier_unregister(*(struct rockchip_panel_notifier **)res);
|
||||
}
|
||||
|
||||
void devm_rockchip_panel_notifier_unregister(struct device *dev)
|
||||
{
|
||||
WARN_ON(devres_release(dev, devm_rockchip_panel_notifier_unreg,
|
||||
NULL, NULL));
|
||||
}
|
||||
EXPORT_SYMBOL(devm_rockchip_panel_notifier_unregister);
|
||||
|
||||
int devm_rockchip_panel_notifier_register(struct device *dev,
|
||||
struct drm_panel *panel,
|
||||
struct rockchip_panel_notifier *pn)
|
||||
{
|
||||
int ret;
|
||||
struct rockchip_panel_notifier **ptr;
|
||||
|
||||
ptr = devres_alloc(devm_rockchip_panel_notifier_unreg, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = rockchip_panel_notifier_register(panel, pn);
|
||||
if (ret) {
|
||||
devres_free(ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*ptr = pn;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(devm_rockchip_panel_notifier_register);
|
||||
|
||||
int rockchip_panel_notifier_call_chain(struct rockchip_panel_notifier *pn,
|
||||
enum rockchip_panel_event panel_event,
|
||||
struct rockchip_panel_edata *panel_edata)
|
||||
{
|
||||
if (!pn)
|
||||
return -EINVAL;
|
||||
|
||||
return blocking_notifier_call_chain(&pn->nh, (unsigned long)panel_event,
|
||||
(void *)panel_edata);
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_panel_notifier_call_chain);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Zhibin Huang <zhibin.huang@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("rockchip panel notifier");
|
||||
74
include/linux/rockchip-panel-notifier.h
Normal file
74
include/linux/rockchip-panel-notifier.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2024 Rockchip Electronics Co. Ltd.
|
||||
* Author: Zhibin Huang <zhibin.huang@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_ROCKCHIP_PANEL_NOTIFIER_H__
|
||||
#define __LINUX_ROCKCHIP_PANEL_NOTIFIER_H__
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
struct rockchip_panel_notifier {
|
||||
struct list_head list;
|
||||
struct drm_panel *panel;
|
||||
struct blocking_notifier_head nh;
|
||||
};
|
||||
|
||||
enum rockchip_panel_event {
|
||||
PANEL_PRE_ENABLE,
|
||||
PANEL_ENABLED,
|
||||
PANEL_PRE_DISABLE,
|
||||
PANEL_DISABLED,
|
||||
};
|
||||
|
||||
struct rockchip_panel_edata {
|
||||
void *data;
|
||||
};
|
||||
|
||||
#if IS_REACHABLE(CONFIG_ROCKCHIP_PANEL_NOTIFIER)
|
||||
int devm_rockchip_panel_notifier_register(struct device *dev,
|
||||
struct drm_panel *panel,
|
||||
struct rockchip_panel_notifier *pn);
|
||||
void devm_rockchip_panel_notifier_unregister(struct device *dev);
|
||||
int rockchip_panel_notifier_call_chain(struct rockchip_panel_notifier *pn,
|
||||
enum rockchip_panel_event panel_event,
|
||||
struct rockchip_panel_edata *panel_edata);
|
||||
int devm_rockchip_panel_notifier_register_client(struct device *dev, struct notifier_block *nb);
|
||||
void devm_rockchip_panel_notifier_unregister_client(struct device *dev);
|
||||
#else
|
||||
static inline int
|
||||
devm_rockchip_panel_notifier_register(struct device *dev,
|
||||
struct drm_panel *panel,
|
||||
struct rockchip_panel_notifier *pn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void devm_rockchip_panel_notifier_unregister(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int
|
||||
rockchip_panel_notifier_call_chain(struct rockchip_panel_notifier *pn,
|
||||
enum rockchip_panel_event panel_event,
|
||||
struct rockchip_panel_edata *panel_edata)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
devm_rockchip_panel_notifier_register_client(struct device *dev,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
devm_rockchip_panel_notifier_unregister_client(struct device *dev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ROCKCHIP_PANEL_NOTIFIER */
|
||||
|
||||
#endif /* __LINUX_ROCKCHIP_PANEL_NOTIFIER_H__ */
|
||||
Reference in New Issue
Block a user