mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-25 22:23:14 -04:00
Merge "soc: qcom: add initial version of qti_battery_debug driver"
This commit is contained in:
commit
16f01462b8
3 changed files with 243 additions and 0 deletions
|
|
@ -546,6 +546,16 @@ config QTI_PMIC_GLINK
|
|||
charging and gauging.
|
||||
This enables clients to read and write battery charging parameters.
|
||||
|
||||
config QTI_BATTERY_GLINK_DEBUG
|
||||
tristate "Enable support for QTI battery glink debug driver"
|
||||
depends on QTI_PMIC_GLINK
|
||||
depends on DEBUG_FS
|
||||
help
|
||||
Qualcomm Technologies, Inc. battery glink debug driver helps to
|
||||
obtain debug information for battery charging and gauging over PMIC
|
||||
Glink from charger and gauging firmware running on a remote subsystem
|
||||
(e.g. DSP).
|
||||
|
||||
config MSM_CDSP_LOADER
|
||||
tristate "CDSP loader support"
|
||||
help
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ obj-$(CONFIG_QSEE_IPC_IRQ) += qsee_ipc_irq.o
|
|||
obj-$(CONFIG_QCOM_GLINK) += glink_probe.o
|
||||
obj-$(CONFIG_MSM_GLINK_SSR) += msm_glink_ssr.o
|
||||
obj-$(CONFIG_QTI_PMIC_GLINK) += pmic_glink.o
|
||||
obj-$(CONFIG_QTI_BATTERY_GLINK_DEBUG) += qti_battery_debug.o
|
||||
obj-$(CONFIG_QTI_DDR_STATS_LOG) += ddr_stats.o
|
||||
obj-$(CONFIG_QTI_SYSTEM_PM) += system_pm.o
|
||||
obj-$(CONFIG_MSM_REMOTEQDSS) += remoteqdss.o
|
||||
|
|
|
|||
232
drivers/soc/qcom/qti_battery_debug.c
Normal file
232
drivers/soc/qcom/qti_battery_debug.c
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "BATTERY_DBG: %s: " fmt, __func__
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rpmsg.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/qcom/pmic_glink.h>
|
||||
|
||||
/* owner/type/opcode for battery debug */
|
||||
#define MSG_OWNER_BD 32781
|
||||
#define MSG_TYPE_REQ_RESP 1
|
||||
#define BD_QBG_DUMP_REQ 0x36
|
||||
|
||||
/* Generic definitions */
|
||||
#define MAX_BUF_LEN (560 * sizeof(u32))
|
||||
#define BD_WAIT_TIME_MS 1000
|
||||
|
||||
struct qbg_context_req_msg {
|
||||
struct pmic_glink_hdr hdr;
|
||||
};
|
||||
|
||||
struct qbg_context_resp_msg {
|
||||
struct pmic_glink_hdr hdr;
|
||||
u32 length;
|
||||
u8 buf[MAX_BUF_LEN];
|
||||
};
|
||||
|
||||
struct battery_dbg_dev {
|
||||
struct device *dev;
|
||||
struct pmic_glink_client *client;
|
||||
struct mutex lock;
|
||||
struct completion ack;
|
||||
struct qbg_context_resp_msg qbg_dump;
|
||||
struct dentry *debugfs_dir;
|
||||
struct debugfs_blob_wrapper qbg_blob;
|
||||
};
|
||||
|
||||
static int battery_dbg_write(struct battery_dbg_dev *bd, void *data, size_t len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&bd->lock);
|
||||
reinit_completion(&bd->ack);
|
||||
rc = pmic_glink_write(bd->client, data, len);
|
||||
if (!rc) {
|
||||
rc = wait_for_completion_timeout(&bd->ack,
|
||||
msecs_to_jiffies(BD_WAIT_TIME_MS));
|
||||
if (!rc) {
|
||||
pr_err("Error, timed out sending message\n");
|
||||
mutex_unlock(&bd->lock);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
}
|
||||
mutex_unlock(&bd->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void handle_qbg_dump_message(struct battery_dbg_dev *bd,
|
||||
struct qbg_context_resp_msg *resp_msg,
|
||||
size_t len)
|
||||
{
|
||||
u32 buf_len;
|
||||
|
||||
if (len > sizeof(bd->qbg_dump)) {
|
||||
pr_err("Incorrect length received: %zu expected: %u\n", len,
|
||||
sizeof(bd->qbg_dump));
|
||||
return;
|
||||
}
|
||||
|
||||
buf_len = resp_msg->length;
|
||||
if (buf_len > sizeof(bd->qbg_dump.buf)) {
|
||||
pr_err("Incorrect buffer length: %u\n", buf_len);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("buf length: %u\n", buf_len);
|
||||
memcpy(bd->qbg_dump.buf, resp_msg->buf, buf_len);
|
||||
bd->qbg_blob.size = buf_len;
|
||||
|
||||
complete(&bd->ack);
|
||||
}
|
||||
|
||||
static int battery_dbg_callback(void *priv, void *data, size_t len)
|
||||
{
|
||||
struct pmic_glink_hdr *hdr = data;
|
||||
struct battery_dbg_dev *bd = priv;
|
||||
|
||||
pr_debug("owner: %u type: %u opcode: %#x len: %zu\n", hdr->owner,
|
||||
hdr->type, hdr->opcode, len);
|
||||
|
||||
switch (hdr->opcode) {
|
||||
case BD_QBG_DUMP_REQ:
|
||||
handle_qbg_dump_message(bd, data, len);
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown opcode %u\n", hdr->opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_qbg_context_write(void *data, u64 val)
|
||||
{
|
||||
struct battery_dbg_dev *bd = data;
|
||||
struct qbg_context_req_msg req_msg = { { 0 } };
|
||||
|
||||
req_msg.hdr.owner = MSG_OWNER_BD;
|
||||
req_msg.hdr.type = MSG_TYPE_REQ_RESP;
|
||||
req_msg.hdr.opcode = BD_QBG_DUMP_REQ;
|
||||
|
||||
return battery_dbg_write(bd, &req_msg, sizeof(req_msg));
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(get_qbg_context_debugfs_ops, NULL,
|
||||
get_qbg_context_write, "%llu\n");
|
||||
|
||||
static int battery_dbg_add_debugfs(struct battery_dbg_dev *bd)
|
||||
{
|
||||
struct dentry *bd_dir, *file;
|
||||
|
||||
bd_dir = debugfs_create_dir("battery_debug", NULL);
|
||||
if (!bd_dir) {
|
||||
pr_err("Failed to create battery debugfs directory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
file = debugfs_create_file_unsafe("get_qbg_context", 0200, bd_dir, bd,
|
||||
&get_qbg_context_debugfs_ops);
|
||||
if (!file) {
|
||||
pr_err("Failed to create get_qbg_context debugfs file\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
bd->qbg_blob.data = bd->qbg_dump.buf;
|
||||
bd->qbg_blob.size = 0;
|
||||
file = debugfs_create_blob("qbg_context", 0444, bd_dir, &bd->qbg_blob);
|
||||
if (!file) {
|
||||
pr_err("Failed to create qbg_context debugfs file\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
bd->debugfs_dir = bd_dir;
|
||||
|
||||
return 0;
|
||||
error:
|
||||
debugfs_remove_recursive(bd_dir);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int battery_dbg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct battery_dbg_dev *bd;
|
||||
struct pmic_glink_client_data client_data = { };
|
||||
int rc;
|
||||
|
||||
bd = devm_kzalloc(&pdev->dev, sizeof(*bd), GFP_KERNEL);
|
||||
if (!bd)
|
||||
return -ENOMEM;
|
||||
|
||||
bd->dev = &pdev->dev;
|
||||
client_data.id = MSG_OWNER_BD;
|
||||
client_data.name = "battery_debug";
|
||||
client_data.callback = battery_dbg_callback;
|
||||
client_data.priv = bd;
|
||||
|
||||
bd->client = pmic_glink_register_client(bd->dev, &client_data);
|
||||
if (IS_ERR(bd->client)) {
|
||||
rc = PTR_ERR(bd->client);
|
||||
if (rc != -EPROBE_DEFER)
|
||||
dev_err(bd->dev, "Error in registering with pmic_glink %d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
mutex_init(&bd->lock);
|
||||
init_completion(&bd->ack);
|
||||
platform_set_drvdata(pdev, bd);
|
||||
|
||||
rc = battery_dbg_add_debugfs(bd);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
pmic_glink_unregister_client(bd->client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int battery_dbg_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct battery_dbg_dev *bd = platform_get_drvdata(pdev);
|
||||
int rc;
|
||||
|
||||
debugfs_remove_recursive(bd->debugfs_dir);
|
||||
rc = pmic_glink_unregister_client(bd->client);
|
||||
if (rc < 0) {
|
||||
pr_err("Error unregistering from pmic_glink, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id battery_dbg_match_table[] = {
|
||||
{ .compatible = "qcom,battery-debug" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver battery_dbg_driver = {
|
||||
.driver = {
|
||||
.name = "qti_battery_debug",
|
||||
.of_match_table = battery_dbg_match_table,
|
||||
},
|
||||
.probe = battery_dbg_probe,
|
||||
.remove = battery_dbg_remove,
|
||||
};
|
||||
module_platform_driver(battery_dbg_driver);
|
||||
|
||||
MODULE_DESCRIPTION("QTI Glink battery debug driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Loading…
Reference in a new issue