mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 03:27:03 +02:00
soc: qcom: panel_event_notifier: add panel_event_notifier driver
Add a notification frameowrk to notify all clients interested in getting various display panel events like power on, power off, FPS change, etc. Clients can use these notifications for power saving or align its operations with display panel power state. Change-Id: Ic4ed7f3207111824a5da84ed2a5a2e0e50e925f0 Signed-off-by: Shashank Babu Chinta Venkata <sbchin@codeaurora.org>
This commit is contained in:
parent
4a001b7ca3
commit
31960cf250
184
drivers/soc/qcom/panel_event_notifier.c
Normal file
184
drivers/soc/qcom/panel_event_notifier.c
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/soc/qcom/panel_event_notifier.h>
|
||||
|
||||
struct panel_event_notifier_entry {
|
||||
panel_event_notifier_handler handler;
|
||||
void *pvt_data;
|
||||
struct drm_panel *panel;
|
||||
enum panel_event_notifier_tag tag;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(panel_event_notifier_entries_lock);
|
||||
static struct panel_event_notifier_entry
|
||||
panel_event_notifier_entries[PANEL_EVENT_NOTIFIER_CLIENT_MAX];
|
||||
|
||||
static bool panel_event_notifier_tag_valid(enum panel_event_notifier_tag tag)
|
||||
{
|
||||
return tag > PANEL_EVENT_NOTIFICATION_NONE &&
|
||||
tag < PANEL_EVENT_NOTIFICATION_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* panel_event_notifier_register: responsible for registering clients
|
||||
* interested in panel event notifications.
|
||||
* clients register with a client handle and tag
|
||||
* suggesting the notifications they are
|
||||
* interested in and a callback which is
|
||||
* triggered when the interested panel
|
||||
* notifications are received.
|
||||
*
|
||||
* @tag: The tag for which the caller would like to receive panel events for.
|
||||
*
|
||||
* @client_handle: handle to recongnize the client registering for
|
||||
* notifications.
|
||||
*
|
||||
* @panel: struct drm_panel for which the panel events are requested for.
|
||||
*
|
||||
* @handler: The handler that will be invoked when a panel event notification is
|
||||
* received pertaining to @tag. The handler will be invoked with a
|
||||
* pointer to private data registered by the client that is needed
|
||||
* for servicing the notification.
|
||||
*
|
||||
* @pvt_data: The data that should be passed to @handler when a notification
|
||||
* occurs
|
||||
*
|
||||
* On success, the function will return a cookie.
|
||||
*
|
||||
*/
|
||||
void *panel_event_notifier_register(enum panel_event_notifier_tag tag,
|
||||
enum panel_event_notifier_client client_handle,
|
||||
struct drm_panel *panel,
|
||||
panel_event_notifier_handler handler, void *pvt_data)
|
||||
{
|
||||
struct panel_event_notifier_entry *entry;
|
||||
|
||||
if (!panel_event_notifier_tag_valid(tag) || !handler) {
|
||||
pr_err("Invalid tag or handler found while registering\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (client_handle < 0 ||
|
||||
client_handle >= PANEL_EVENT_NOTIFIER_CLIENT_MAX) {
|
||||
pr_err("Invalid client handle used for registering\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
mutex_lock(&panel_event_notifier_entries_lock);
|
||||
entry = &panel_event_notifier_entries[client_handle];
|
||||
if (entry->handler) {
|
||||
mutex_unlock(&panel_event_notifier_entries_lock);
|
||||
return ERR_PTR(-EEXIST);
|
||||
}
|
||||
entry->panel = panel;
|
||||
entry->handler = handler;
|
||||
entry->pvt_data = pvt_data;
|
||||
entry->tag = tag;
|
||||
mutex_unlock(&panel_event_notifier_entries_lock);
|
||||
|
||||
pr_debug("client %d registered successfully\n", client_handle);
|
||||
return entry;
|
||||
}
|
||||
EXPORT_SYMBOL(panel_event_notifier_register);
|
||||
|
||||
/**
|
||||
* panel_event_notifier_unregister: responsible for unregistering clients.
|
||||
*
|
||||
* @cookie: cookie used for unregistering client.
|
||||
*/
|
||||
void panel_event_notifier_unregister(void *cookie)
|
||||
{
|
||||
struct panel_event_notifier_entry *entry = cookie;
|
||||
|
||||
if (!cookie)
|
||||
return;
|
||||
|
||||
mutex_lock(&panel_event_notifier_entries_lock);
|
||||
entry->panel = NULL;
|
||||
entry->handler = NULL;
|
||||
entry->pvt_data = NULL;
|
||||
entry->tag = PANEL_EVENT_NOTIFICATION_NONE;
|
||||
mutex_unlock(&panel_event_notifier_entries_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(panel_event_notifier_unregister);
|
||||
|
||||
/**
|
||||
* panel_event_notifion_trigger: responsible for triggering notifications.
|
||||
* Contains tag which notifies the panel
|
||||
* notification is on premiary or secondary
|
||||
* display and a notifcation carrying necessary
|
||||
* data for clients to consume while servicing the
|
||||
* notification. A handler registered by the
|
||||
* client will be triggered to notify the event.
|
||||
*
|
||||
* @tag: tag suggesting the panel on which notification is triggered whether
|
||||
*I primary or secondary display panel.
|
||||
*
|
||||
* @notification: contains data required for client to address the notification.
|
||||
*/
|
||||
void panel_event_notification_trigger(enum panel_event_notifier_tag tag,
|
||||
struct panel_event_notification *notification)
|
||||
{
|
||||
struct panel_event_notifier_entry *entry;
|
||||
panel_event_notifier_handler handler = NULL;
|
||||
void *pvt_data;
|
||||
int i;
|
||||
|
||||
if (!panel_event_notifier_tag_valid(tag)) {
|
||||
pr_err("Invalid panel notifier tag\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < PANEL_EVENT_NOTIFIER_CLIENT_MAX; i++) {
|
||||
mutex_lock(&panel_event_notifier_entries_lock);
|
||||
entry = &panel_event_notifier_entries[i];
|
||||
if (notification->panel != entry->panel) {
|
||||
pr_debug("invalid panel found notification_panel:0x%x entry_panel:0x%x\n",
|
||||
notification->panel, entry->panel);
|
||||
mutex_unlock(&panel_event_notifier_entries_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip client entries not subscribed to tag */
|
||||
if (entry->tag != tag) {
|
||||
pr_err("tag mismatch entry->tag:%d tag:%d\n", entry->tag, tag);
|
||||
mutex_unlock(&panel_event_notifier_entries_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
handler = entry->handler;
|
||||
pvt_data = entry->pvt_data;
|
||||
mutex_unlock(&panel_event_notifier_entries_lock);
|
||||
|
||||
pr_debug("triggering notification for tag:%d, type:%d\n",
|
||||
tag, notification->notif_type);
|
||||
|
||||
if (handler)
|
||||
handler(tag, notification, pvt_data);
|
||||
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(panel_event_notification_trigger);
|
||||
|
||||
static int __init panel_event_notifier_init(void)
|
||||
{
|
||||
pr_debug("Panel event notifier initialized\n");
|
||||
return 0;
|
||||
}
|
||||
module_init(panel_event_notifier_init);
|
||||
|
||||
static void __exit panel_event_notifier_exit(void)
|
||||
{
|
||||
pr_debug("Panel event notifier exited\n");
|
||||
}
|
||||
module_exit(panel_event_notifier_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Panel event notifier");
|
||||
81
include/linux/soc/qcom/panel_event_notifier.h
Normal file
81
include/linux/soc/qcom/panel_event_notifier.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PANEL_EVENT_NOTIFIER_H
|
||||
#define __PANEL_EVENT_NOTIFIER_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
enum panel_event_notifier_tag {
|
||||
PANEL_EVENT_NOTIFICATION_NONE,
|
||||
PANEL_EVENT_NOTIFICATION_PRIMARY,
|
||||
PANEL_EVENT_NOTIFICATION_SECONDARY,
|
||||
PANEL_EVENT_NOTIFICATION_MAX
|
||||
};
|
||||
|
||||
enum panel_event_notifier_client {
|
||||
PANEL_EVENT_NOTIFIER_CLIENT_PRIMARY_TOUCH,
|
||||
PANEL_EVENT_NOTIFIER_CLIENT_SECONDARY_TOUCH,
|
||||
PANEL_EVENT_NOTIFIER_CLIENT_ECM,
|
||||
PANEL_EVENT_NOTIFIER_CLIENT_MAX
|
||||
};
|
||||
|
||||
enum panel_event_notification_type {
|
||||
DRM_PANEL_EVENT_NONE,
|
||||
DRM_PANEL_EVENT_BLANK,
|
||||
DRM_PANEL_EVENT_UNBLANK,
|
||||
DRM_PANEL_EVENT_BLANK_LP,
|
||||
DRM_PANEL_EVENT_FPS_CHANGE,
|
||||
DRM_PANEL_EVENT_MAX
|
||||
};
|
||||
|
||||
struct panel_event_notification_data {
|
||||
u32 old_fps;
|
||||
u32 new_fps;
|
||||
bool early_trigger;
|
||||
};
|
||||
|
||||
struct panel_event_notification {
|
||||
enum panel_event_notification_type notif_type;
|
||||
struct panel_event_notification_data notif_data;
|
||||
struct drm_panel *panel;
|
||||
};
|
||||
|
||||
typedef void (*panel_event_notifier_handler)(enum panel_event_notifier_tag tag,
|
||||
struct panel_event_notification *notification,
|
||||
void *pvt_data);
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_PANEL_EVENT_NOTIFIER)
|
||||
void *panel_event_notifier_register(enum panel_event_notifier_tag tag,
|
||||
enum panel_event_notifier_client client_handle,
|
||||
struct drm_panel *panel,
|
||||
panel_event_notifier_handler notif_handler, void *pvt_data);
|
||||
void panel_event_notifier_unregister(void *cookie);
|
||||
void panel_event_notification_trigger(enum panel_event_notifier_tag tag,
|
||||
struct panel_event_notification *notification);
|
||||
|
||||
#else
|
||||
static inline void *panel_event_notifier_register(enum panel_event_notifier_tag tag,
|
||||
enum panel_event_notifier_client client_handle,
|
||||
struct drm_panel *panel,
|
||||
panel_event_notifier_handler notif_handler, void *pvt_data)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void panel_event_notifier_unregister(void *cookie)
|
||||
{
|
||||
}
|
||||
static inline void panel_event_notification_trigger(
|
||||
enum panel_event_notifier_tag tag,
|
||||
struct panel_event_notification *notification)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user