brintos

brintos / linux-shallow public Read only

0
0
Text · 4.0 KiB · 39f412b Raw
171 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2019-2022, The Linux Foundation. All rights reserved.4 * Copyright (c) 2023, Linaro Ltd5 */6#include <linux/of_device.h>7#include <linux/module.h>8#include <linux/platform_device.h>9#include <linux/rpmsg.h>10#include <linux/slab.h>11#include <linux/soc/qcom/pdr.h>12#include <linux/debugfs.h>13 14#define CREATE_TRACE_POINTS15#include "pmic_pdcharger_ulog.h"16 17#define MSG_OWNER_CHG_ULOG		3277818#define MSG_TYPE_REQ_RESP		119 20#define GET_CHG_ULOG_REQ		0x1821#define SET_CHG_ULOG_PROP_REQ		0x1922 23#define LOG_DEFAULT_TIME_MS		100024 25#define MAX_ULOG_SIZE			819226 27struct pmic_pdcharger_ulog_hdr {28	__le32 owner;29	__le32 type;30	__le32 opcode;31};32 33struct pmic_pdcharger_ulog {34	struct rpmsg_device *rpdev;35	struct delayed_work ulog_work;36};37 38struct get_ulog_req_msg {39	struct pmic_pdcharger_ulog_hdr	hdr;40	u32				log_size;41};42 43struct get_ulog_resp_msg {44	struct pmic_pdcharger_ulog_hdr	hdr;45	u8				buf[MAX_ULOG_SIZE];46};47 48static int pmic_pdcharger_ulog_write_async(struct pmic_pdcharger_ulog *pg, void *data, size_t len)49{50	return rpmsg_send(pg->rpdev->ept, data, len);51}52 53static int pmic_pdcharger_ulog_request(struct pmic_pdcharger_ulog *pg)54{55	struct get_ulog_req_msg req_msg = {56		.hdr = {57			.owner = cpu_to_le32(MSG_OWNER_CHG_ULOG),58			.type = cpu_to_le32(MSG_TYPE_REQ_RESP),59			.opcode = cpu_to_le32(GET_CHG_ULOG_REQ)60		},61		.log_size = MAX_ULOG_SIZE62	};63 64	return pmic_pdcharger_ulog_write_async(pg, &req_msg, sizeof(req_msg));65}66 67static void pmic_pdcharger_ulog_work(struct work_struct *work)68{69	struct pmic_pdcharger_ulog *pg = container_of(work, struct pmic_pdcharger_ulog,70						      ulog_work.work);71	int rc;72 73	rc = pmic_pdcharger_ulog_request(pg);74	if (rc) {75		dev_err(&pg->rpdev->dev, "Error requesting ulog, rc=%d\n", rc);76		return;77	}78}79 80static void pmic_pdcharger_ulog_handle_message(struct pmic_pdcharger_ulog *pg,81					       struct get_ulog_resp_msg *resp_msg,82					       size_t len)83{84	char *token, *buf = resp_msg->buf;85 86	if (len != sizeof(*resp_msg)) {87		dev_err(&pg->rpdev->dev, "Expected data length: %zu, received: %zu\n",88			sizeof(*resp_msg), len);89		return;90	}91 92	buf[MAX_ULOG_SIZE - 1] = '\0';93 94	do {95		token = strsep((char **)&buf, "\n");96		if (token && strlen(token))97			trace_pmic_pdcharger_ulog_msg(token);98	} while (token);99}100 101static int pmic_pdcharger_ulog_rpmsg_callback(struct rpmsg_device *rpdev, void *data,102					      int len, void *priv, u32 addr)103{104	struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev);105	struct pmic_pdcharger_ulog_hdr *hdr = data;106	u32 opcode;107 108	opcode = le32_to_cpu(hdr->opcode);109 110	switch (opcode) {111	case GET_CHG_ULOG_REQ:112		schedule_delayed_work(&pg->ulog_work, msecs_to_jiffies(LOG_DEFAULT_TIME_MS));113		pmic_pdcharger_ulog_handle_message(pg, data, len);114		break;115	default:116		dev_err(&pg->rpdev->dev, "Unknown opcode %u\n", opcode);117		break;118	}119 120	return 0;121}122 123static int pmic_pdcharger_ulog_rpmsg_probe(struct rpmsg_device *rpdev)124{125	struct pmic_pdcharger_ulog *pg;126	struct device *dev = &rpdev->dev;127 128	pg = devm_kzalloc(dev, sizeof(*pg), GFP_KERNEL);129	if (!pg)130		return -ENOMEM;131 132	pg->rpdev = rpdev;133	INIT_DELAYED_WORK(&pg->ulog_work, pmic_pdcharger_ulog_work);134 135	dev_set_drvdata(dev, pg);136 137	pmic_pdcharger_ulog_request(pg);138 139	return 0;140}141 142static void pmic_pdcharger_ulog_rpmsg_remove(struct rpmsg_device *rpdev)143{144	struct pmic_pdcharger_ulog *pg = dev_get_drvdata(&rpdev->dev);145 146	cancel_delayed_work_sync(&pg->ulog_work);147}148 149static const struct rpmsg_device_id pmic_pdcharger_ulog_rpmsg_id_match[] = {150	{ "PMIC_LOGS_ADSP_APPS" },151	{}152};153/*154 * No MODULE_DEVICE_TABLE intentionally: that's a debugging module, to be155 * loaded manually only.156 */157 158static struct rpmsg_driver pmic_pdcharger_ulog_rpmsg_driver = {159	.probe = pmic_pdcharger_ulog_rpmsg_probe,160	.remove = pmic_pdcharger_ulog_rpmsg_remove,161	.callback = pmic_pdcharger_ulog_rpmsg_callback,162	.id_table = pmic_pdcharger_ulog_rpmsg_id_match,163	.drv  = {164		.name  = "qcom_pmic_pdcharger_ulog_rpmsg",165	},166};167 168module_rpmsg_driver(pmic_pdcharger_ulog_rpmsg_driver);169MODULE_DESCRIPTION("Qualcomm PMIC ChargerPD ULOG driver");170MODULE_LICENSE("GPL");171