mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
77706838f8
Qualcomm PMIC ChargerPD ULOG and RPM Master Statistics drivers are solely for debugging purposes and should not be autoloaded as modules. Add comments to annotate missing MODULE_DEVICE_TABLE. Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org> Link: https://lore.kernel.org/r/20240410184522.271889-1-krzk@kernel.org Signed-off-by: Bjorn Andersson <andersson@kernel.org>
171 lines
4.0 KiB
C
171 lines
4.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2019-2022, The Linux Foundation. All rights reserved.
|
|
* Copyright (c) 2023, Linaro Ltd
|
|
*/
|
|
#include <linux/of_device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/rpmsg.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/soc/qcom/pdr.h>
|
|
#include <linux/debugfs.h>
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
#include "pmic_pdcharger_ulog.h"
|
|
|
|
#define MSG_OWNER_CHG_ULOG 32778
|
|
#define MSG_TYPE_REQ_RESP 1
|
|
|
|
#define GET_CHG_ULOG_REQ 0x18
|
|
#define SET_CHG_ULOG_PROP_REQ 0x19
|
|
|
|
#define LOG_DEFAULT_TIME_MS 1000
|
|
|
|
#define MAX_ULOG_SIZE 8192
|
|
|
|
struct pmic_pdcharger_ulog_hdr {
|
|
__le32 owner;
|
|
__le32 type;
|
|
__le32 opcode;
|
|
};
|
|
|
|
struct pmic_pdcharger_ulog {
|
|
struct rpmsg_device *rpdev;
|
|
struct delayed_work ulog_work;
|
|
};
|
|
|
|
struct get_ulog_req_msg {
|
|
struct pmic_pdcharger_ulog_hdr hdr;
|
|
u32 log_size;
|
|
};
|
|
|
|
struct get_ulog_resp_msg {
|
|
struct pmic_pdcharger_ulog_hdr hdr;
|
|
u8 buf[MAX_ULOG_SIZE];
|
|
};
|
|
|
|
static int pmic_pdcharger_ulog_write_async(struct pmic_pdcharger_ulog *pg, void *data, size_t len)
|
|
{
|
|
return rpmsg_send(pg->rpdev->ept, data, len);
|
|
}
|
|
|
|
static int pmic_pdcharger_ulog_request(struct pmic_pdcharger_ulog *pg)
|
|
{
|
|
struct get_ulog_req_msg req_msg = {
|
|
.hdr = {
|
|
.owner = cpu_to_le32(MSG_OWNER_CHG_ULOG),
|
|
.type = cpu_to_le32(MSG_TYPE_REQ_RESP),
|
|
.opcode = cpu_to_le32(GET_CHG_ULOG_REQ)
|
|
},
|
|
.log_size = MAX_ULOG_SIZE
|
|
};
|
|
|
|
return pmic_pdcharger_ulog_write_async(pg, &req_msg, sizeof(req_msg));
|
|
}
|
|
|
|
static void pmic_pdcharger_ulog_work(struct work_struct *work)
|
|
{
|
|
struct pmic_pdcharger_ulog *pg = container_of(work, struct pmic_pdcharger_ulog,
|
|
ulog_work.work);
|
|
int rc;
|
|
|
|
rc = pmic_pdcharger_ulog_request(pg);
|
|
if (rc) {
|
|
dev_err(&pg->rpdev->dev, "Error requesting ulog, rc=%d\n", rc);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void pmic_pdcharger_ulog_handle_message(struct pmic_pdcharger_ulog *pg,
|
|
struct get_ulog_resp_msg *resp_msg,
|
|
size_t len)
|
|
{
|
|
char *token, *buf = resp_msg->buf;
|
|
|
|
if (len != sizeof(*resp_msg)) {
|
|
dev_err(&pg->rpdev->dev, "Expected data length: %zu, received: %zu\n",
|
|
sizeof(*resp_msg), len);
|
|
return;
|
|
}
|
|
|
|
buf[MAX_ULOG_SIZE - 1] = '\0';
|
|
|
|
do {
|
|
token = strsep((char **)&buf, "\n");
|
|
if (token && strlen(token))
|
|
trace_pmic_pdcharger_ulog_msg(token);
|
|
} while (token);
|
|
}
|
|
|
|
static int pmic_pdcharger_ulog_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
|
|
int len, void *priv, u32 addr)
|
|
{
|
|
struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev);
|
|
struct pmic_pdcharger_ulog_hdr *hdr = data;
|
|
u32 opcode;
|
|
|
|
opcode = le32_to_cpu(hdr->opcode);
|
|
|
|
switch (opcode) {
|
|
case GET_CHG_ULOG_REQ:
|
|
schedule_delayed_work(&pg->ulog_work, msecs_to_jiffies(LOG_DEFAULT_TIME_MS));
|
|
pmic_pdcharger_ulog_handle_message(pg, data, len);
|
|
break;
|
|
default:
|
|
dev_err(&pg->rpdev->dev, "Unknown opcode %u\n", opcode);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pmic_pdcharger_ulog_rpmsg_probe(struct rpmsg_device *rpdev)
|
|
{
|
|
struct pmic_pdcharger_ulog *pg;
|
|
struct device *dev = &rpdev->dev;
|
|
|
|
pg = devm_kzalloc(dev, sizeof(*pg), GFP_KERNEL);
|
|
if (!pg)
|
|
return -ENOMEM;
|
|
|
|
pg->rpdev = rpdev;
|
|
INIT_DELAYED_WORK(&pg->ulog_work, pmic_pdcharger_ulog_work);
|
|
|
|
dev_set_drvdata(dev, pg);
|
|
|
|
pmic_pdcharger_ulog_request(pg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void pmic_pdcharger_ulog_rpmsg_remove(struct rpmsg_device *rpdev)
|
|
{
|
|
struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev);
|
|
|
|
cancel_delayed_work_sync(&pg->ulog_work);
|
|
}
|
|
|
|
static const struct rpmsg_device_id pmic_pdcharger_ulog_rpmsg_id_match[] = {
|
|
{ "PMIC_LOGS_ADSP_APPS" },
|
|
{}
|
|
};
|
|
/*
|
|
* No MODULE_DEVICE_TABLE intentionally: that's a debugging module, to be
|
|
* loaded manually only.
|
|
*/
|
|
|
|
static struct rpmsg_driver pmic_pdcharger_ulog_rpmsg_driver = {
|
|
.probe = pmic_pdcharger_ulog_rpmsg_probe,
|
|
.remove = pmic_pdcharger_ulog_rpmsg_remove,
|
|
.callback = pmic_pdcharger_ulog_rpmsg_callback,
|
|
.id_table = pmic_pdcharger_ulog_rpmsg_id_match,
|
|
.drv = {
|
|
.name = "qcom_pmic_pdcharger_ulog_rpmsg",
|
|
},
|
|
};
|
|
|
|
module_rpmsg_driver(pmic_pdcharger_ulog_rpmsg_driver);
|
|
MODULE_DESCRIPTION("Qualcomm PMIC ChargerPD ULOG driver");
|
|
MODULE_LICENSE("GPL");
|