kernel-brax3-ubuntu-touch/drivers/misc/mediatek/tinysys_scmi/tinysys-scmi-drv.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

207 lines
5.1 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 MediaTek Inc.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/scmi_protocol.h>
#include "tinysys-scmi.h"
static struct scmi_tinysys_info_st *t_info;
static const struct scmi_tinysys_proto_ops *tinysys_ops;
f_handler_t cb_array[SCMI_TINYSYS_CB_MAX];
struct scmi_tinysys_info_st *get_scmi_tinysys_info(void)
{
return t_info;
}
EXPORT_SYMBOL(get_scmi_tinysys_info);
int scmi_tinysys_common_set(const struct scmi_protocol_handle *ph, u32 feature_id,
u32 p1, u32 p2, u32 p3, u32 p4, u32 p5)
{
return tinysys_ops->common_set(ph, feature_id, p1, p2, p3, p4, p5);
}
EXPORT_SYMBOL(scmi_tinysys_common_set);
int scmi_tinysys_common_get(const struct scmi_protocol_handle *ph, u32 feature_id,
u32 p1, struct scmi_tinysys_status *rvalue)
{
return tinysys_ops->common_get(ph, feature_id, p1, rvalue);
}
EXPORT_SYMBOL(scmi_tinysys_common_get);
int scmi_tinysys_notifier_fn(struct notifier_block *nb,
unsigned long action, void *data)
{
struct scmi_tinysys_notifier_report *r = data;
scmi_tinysys_report *report = (scmi_tinysys_report *)&(r->f_id);
f_handler_t func;
/*
pr_notice("scmi notify report ktime:%ld f_id:%d p1:%d %d %d %d\n",
r->timestamp, r->f_id, r->p1_status, r->p2_status, r->p3_status,
r->p4_status);
*/
if (r->f_id < SCMI_TINYSYS_CB_MAX) {
func = cb_array[r->f_id];
if (func)
func(r->f_id, report);
}
return NOTIFY_OK;
}
static struct notifier_block tinysys_nb = {
.notifier_call = scmi_tinysys_notifier_fn,
};
int scmi_tinysys_event_notify(u32 feature_id, u32 notify_enable)
{
int ret = 0;
int f_id = feature_id;
struct scmi_device *sdev = t_info->sdev;
if (notify_enable) {
ret = sdev->handle->notify_ops->devm_event_notifier_register(sdev,
SCMI_PROTOCOL_TINYSYS, SCMI_EVENT_TINYSYS_NOTIFIER, &f_id, &tinysys_nb);
if (ret)
pr_notice("scmi register_event_notifier f_id:%d ret:%d\n", f_id, ret);
} else {
ret = sdev->handle->notify_ops->devm_event_notifier_unregister(sdev,
SCMI_PROTOCOL_TINYSYS, SCMI_EVENT_TINYSYS_NOTIFIER, &f_id, &tinysys_nb);
if (ret)
pr_notice("scmi unregister_event_notifier f_id:%d ret:%d\n", f_id, ret);
}
return ret;
}
EXPORT_SYMBOL(scmi_tinysys_event_notify);
void scmi_tinysys_register_event_notifier(u32 feature_id, f_handler_t hand)
{
if (feature_id < SCMI_TINYSYS_CB_MAX)
cb_array[feature_id] = hand;
else
pr_notice("feature_id %d >= SCMI_TINYSYS_CB_MAX\n", feature_id);
}
EXPORT_SYMBOL(scmi_tinysys_register_event_notifier);
#ifdef TINYSYS_SCMI_DEBUG
void test_callback(u32 feature_id, scmi_tinysys_report *r)
{
pr_notice("scmi %s: %d, %x %x %x %x %x\n", __func__,
feature_id, r->feature_id, r->p1, r->p2, r->p3, r->p4);
}
static ssize_t tinysys_scmi_debug_store(struct device *kobj,
struct device_attribute *attr, const char *buf, size_t n)
{
int ret;
int pro_id, f_id, p1, p2, p3, p4, p5;
struct scmi_tinysys_info_st *tt;
struct scmi_tinysys_status rvalue;
char *prompt = "SCMI:";
if (sscanf(buf, "%d %d %d %d %d %d %d", &pro_id, &f_id, &p1, &p2, &p3, &p4, &p5) != 7)
return -EINVAL;
pr_notice("%s pro_id:%d f_id:%d para:%d %d %d %d %d\n", prompt,
pro_id, f_id, p1, p2, p3, p4, p5);
tt = get_scmi_tinysys_info();
switch (pro_id) {
case 0:
ret = scmi_tinysys_common_set(tt->ph, f_id, p1, p2, p3, p4, p5);
if (ret)
pr_notice("%s ret = %d\n", prompt, ret);
break;
case 1:
ret = scmi_tinysys_common_get(tt->ph, f_id, p1, &rvalue);
if (ret)
pr_notice("%s scmi_tinysys_common_get error ret = %d\n", prompt, ret);
else
pr_notice("%s scmi_tinysys_common_get r1:%d r2:%d r3:%d\n", prompt,
rvalue.r1, rvalue.r2, rvalue.r3);
break;
case 2:
scmi_tinysys_register_event_notifier(f_id, (f_handler_t)test_callback);
ret = scmi_tinysys_event_notify(f_id, 1);
break;
case 3:
ret = scmi_tinysys_event_notify(f_id, 0);
break;
default:
break;
}
return n;
}
static ssize_t tinysys_scmi_debug_show(struct device *dev
, struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%s\n", __func__);
}
DEVICE_ATTR_RW(tinysys_scmi_debug);
#endif
static int scmi_tinysys_probe(struct scmi_device *sdev)
{
struct device *dev = &sdev->dev;
const struct scmi_handle *handle = sdev->handle;
struct scmi_protocol_handle *ph;
if (!handle)
return -ENODEV;
scmi_tinysys_register();
tinysys_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_TINYSYS, &ph);
if (IS_ERR(tinysys_ops))
return PTR_ERR(tinysys_ops);
t_info = devm_kzalloc(dev, sizeof(*t_info), GFP_KERNEL);
if (!t_info)
return -ENOMEM;
t_info->sdev = sdev;
t_info->ph = ph;
#ifdef TINYSYS_SCMI_DEBUG
if (device_create_file(dev, &dev_attr_tinysys_scmi_debug))
pr_notice("tinysys scmi debug ret fail\n");
#endif
return 0;
}
static const struct scmi_device_id scmi_id_table[] = {
{ SCMI_PROTOCOL_TINYSYS, "tinysys" },
{ },
};
MODULE_DEVICE_TABLE(scmi, scmi_id_table);
static struct scmi_driver scmi_tinysys_driver = {
.name = "scmi-tinysys",
.probe = scmi_tinysys_probe,
.id_table = scmi_id_table,
};
module_scmi_driver(scmi_tinysys_driver);
MODULE_DESCRIPTION("SCMI tinysys driver");
MODULE_LICENSE("GPL v2");