mirror of
https://github.com/torvalds/linux.git
synced 2026-08-01 03:59:40 +02:00
Merge "soc: qcom: add QTI charger-ulog-glink driver"
This commit is contained in:
commit
9b66754069
|
|
@ -248,6 +248,15 @@ config QTI_BATTERY_GLINK_DEBUG
|
|||
Glink from charger and gauging firmware running on a remote subsystem
|
||||
(e.g. DSP).
|
||||
|
||||
config QTI_CHARGER_ULOG_GLINK
|
||||
tristate "Enable support for QTI charger ulog glink driver"
|
||||
depends on QTI_PMIC_GLINK && DEBUG_FS
|
||||
help
|
||||
Qualcomm Technologies, Inc. charger ulog glink driver helps to
|
||||
obtain ulogs from battery charging and gauging stack over PMIC
|
||||
Glink from the charger firmware running on a remote subsystem
|
||||
(e.g. DSP).
|
||||
|
||||
config QTI_ALTMODE_GLINK
|
||||
tristate "Type-C alternate mode over GLINK"
|
||||
depends on QTI_PMIC_GLINK
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
|
|||
obj-$(CONFIG_QCOM_SMSM) += smsm.o
|
||||
obj-$(CONFIG_QTI_PMIC_GLINK) += pmic_glink.o
|
||||
obj-$(CONFIG_QTI_BATTERY_GLINK_DEBUG) += qti_battery_debug.o
|
||||
obj-$(CONFIG_QTI_CHARGER_ULOG_GLINK) += charger-ulog-glink.o
|
||||
obj-$(CONFIG_QTI_ALTMODE_GLINK) += altmode-glink.o
|
||||
obj-$(CONFIG_QCOM_SECURE_BUFFER) += secure_buffer.o
|
||||
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "altmode-glink: %s: " fmt, __func__
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/ipc_logging.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
|
@ -27,10 +28,18 @@
|
|||
|
||||
#define MAX_NUM_PORTS 4
|
||||
|
||||
#define NUM_LOG_PAGES 10
|
||||
|
||||
#define IDR_KEY_GEN(svid, ind) (((svid) << 8) | (ind))
|
||||
#define IDR_KEY(client) \
|
||||
IDR_KEY_GEN((client)->data.svid, (client)->port_index)
|
||||
|
||||
#define altmode_dbg(fmt, ...) \
|
||||
do { \
|
||||
ipc_log_string(altmode_ipc_log, fmt, ##__VA_ARGS__); \
|
||||
pr_debug(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
struct usbc_notify_ind_msg {
|
||||
struct pmic_glink_hdr hdr;
|
||||
u8 payload[NOTIFY_PAYLOAD_SIZE];
|
||||
|
|
@ -125,6 +134,7 @@ static LIST_HEAD(probe_notify_list);
|
|||
static DEFINE_MUTEX(notify_lock);
|
||||
|
||||
static void altmode_send_pan_ack(struct work_struct *work);
|
||||
static void *altmode_ipc_log;
|
||||
|
||||
static struct altmode_dev *to_altmode_device(struct device_node *amdev_node)
|
||||
{
|
||||
|
|
@ -462,7 +472,7 @@ static void altmode_send_pan_en(struct work_struct *work)
|
|||
}
|
||||
|
||||
atomic_set(&amdev->pan_en_sent, 1);
|
||||
pr_debug("Sent PAN EN\n");
|
||||
altmode_dbg("Sent PAN EN\n");
|
||||
}
|
||||
|
||||
static int altmode_send_ack(struct altmode_dev *amdev, u8 port_index)
|
||||
|
|
@ -479,7 +489,7 @@ static int altmode_send_ack(struct altmode_dev *amdev, u8 port_index)
|
|||
return rc;
|
||||
}
|
||||
|
||||
pr_debug("port %u: Sent PAN ACK\n", port_index);
|
||||
altmode_dbg("port %u: Sent PAN ACK\n", port_index);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -488,7 +498,7 @@ static void altmode_state_cb(void *priv, enum pmic_glink_state state)
|
|||
{
|
||||
struct altmode_dev *amdev = priv;
|
||||
|
||||
pr_debug("state: %d\n", state);
|
||||
altmode_dbg("state: %d\n", state);
|
||||
|
||||
switch (state) {
|
||||
case PMIC_GLINK_STATE_DOWN:
|
||||
|
|
@ -527,7 +537,7 @@ static int altmode_callback(void *priv, void *data, size_t len)
|
|||
struct altmode_client *amclient;
|
||||
u8 port_index;
|
||||
|
||||
pr_debug("len: %zu owner: %u type: %u opcode %04x\n", len, hdr->owner,
|
||||
altmode_dbg("len: %zu owner: %u type: %u opcode %04x\n", len, hdr->owner,
|
||||
hdr->type, hdr->opcode);
|
||||
|
||||
/*
|
||||
|
|
@ -544,7 +554,7 @@ static int altmode_callback(void *priv, void *data, size_t len)
|
|||
break;
|
||||
case USBC_NOTIFY_IND:
|
||||
if (len != sizeof(*notify_msg)) {
|
||||
pr_debug("Expected length %u, got: %zu\n",
|
||||
altmode_dbg("Expected length %u, got: %zu\n",
|
||||
sizeof(*notify_msg), len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -558,7 +568,7 @@ static int altmode_callback(void *priv, void *data, size_t len)
|
|||
mutex_unlock(&amdev->client_lock);
|
||||
|
||||
if (!amclient) {
|
||||
pr_debug("No client associated with SVID %#x port %u\n",
|
||||
altmode_dbg("No client associated with SVID %#x port %u\n",
|
||||
svid, port_index);
|
||||
amdev->ack_port_index = port_index;
|
||||
schedule_delayed_work(&amdev->send_pan_ack_work,
|
||||
|
|
@ -566,7 +576,7 @@ static int altmode_callback(void *priv, void *data, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
pr_debug("Payload: %*ph\n", NOTIFY_PAYLOAD_SIZE,
|
||||
altmode_dbg("Payload: %*ph\n", NOTIFY_PAYLOAD_SIZE,
|
||||
notify_msg->payload);
|
||||
|
||||
cancel_work_sync(&amclient->client_cb_work);
|
||||
|
|
@ -727,6 +737,10 @@ static int altmode_probe(struct platform_device *pdev)
|
|||
goto unreg_pmic_glink;
|
||||
}
|
||||
|
||||
altmode_ipc_log = ipc_log_context_create(NUM_LOG_PAGES, "altmode", 0);
|
||||
if (!altmode_ipc_log)
|
||||
dev_warn(dev, "Error in creating ipc_log_context\n");
|
||||
|
||||
altmode_notify_clients(amdev);
|
||||
|
||||
return 0;
|
||||
|
|
@ -765,6 +779,9 @@ static int altmode_remove(struct platform_device *pdev)
|
|||
list_del(&client->c_node);
|
||||
mutex_unlock(&amdev->client_lock);
|
||||
|
||||
ipc_log_context_destroy(altmode_ipc_log);
|
||||
altmode_ipc_log = NULL;
|
||||
|
||||
rc = pmic_glink_unregister_client(amdev->pgclient);
|
||||
if (rc < 0)
|
||||
dev_err(amdev->dev, "Error in pmic_glink de-registration: %d\n",
|
||||
|
|
|
|||
469
drivers/soc/qcom/charger-ulog-glink.c
Normal file
469
drivers/soc/qcom/charger-ulog-glink.c
Normal file
|
|
@ -0,0 +1,469 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "CHARGER_ULOG: %s: " fmt, __func__
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ipc_logging.h>
|
||||
#include <linux/ktime.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>
|
||||
|
||||
#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 GET_CHG_INIT_ULOG_REQ 0x23
|
||||
|
||||
#define LOG_CATEGORY_INIT (1ULL << 32)
|
||||
#define LOG_MIN_TIME_MS 500
|
||||
#define LOG_DEFAULT_TIME_MS 1000
|
||||
|
||||
#define MAX_ULOG_SIZE 8192
|
||||
#define NUM_LOG_PAGES 10
|
||||
#define NUM_INIT_LOG_PAGES 4
|
||||
|
||||
struct set_ulog_prop_req_msg {
|
||||
struct pmic_glink_hdr hdr;
|
||||
u64 log_category;
|
||||
u32 log_level;
|
||||
};
|
||||
|
||||
struct get_ulog_req_msg {
|
||||
struct pmic_glink_hdr hdr;
|
||||
u32 log_size;
|
||||
};
|
||||
|
||||
struct get_ulog_resp_msg {
|
||||
struct pmic_glink_hdr hdr;
|
||||
u8 buf[MAX_ULOG_SIZE];
|
||||
};
|
||||
|
||||
struct chg_ulog_glink_dev {
|
||||
struct device *dev;
|
||||
struct pmic_glink_client *client;
|
||||
struct dentry *debugfs_dir;
|
||||
void *ipc_log;
|
||||
void *ipc_init_log;
|
||||
struct mutex lock;
|
||||
struct completion ack;
|
||||
struct delayed_work ulog_work;
|
||||
u8 ulog_buf[MAX_ULOG_SIZE];
|
||||
u64 log_category;
|
||||
u32 log_level;
|
||||
u32 log_time_ms;
|
||||
bool log_enable;
|
||||
bool init_log_enable;
|
||||
};
|
||||
|
||||
#define WAIT_TIME_MS 1000
|
||||
static int chg_ulog_write(struct chg_ulog_glink_dev *cd, void *data,
|
||||
size_t len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
mutex_lock(&cd->lock);
|
||||
reinit_completion(&cd->ack);
|
||||
rc = pmic_glink_write(cd->client, data, len);
|
||||
if (!rc) {
|
||||
rc = wait_for_completion_timeout(&cd->ack,
|
||||
msecs_to_jiffies(WAIT_TIME_MS));
|
||||
if (!rc) {
|
||||
pr_err("Error, timed out sending message\n");
|
||||
mutex_unlock(&cd->lock);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
}
|
||||
mutex_unlock(&cd->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int chg_ulog_request(struct chg_ulog_glink_dev *cd, bool init)
|
||||
{
|
||||
struct get_ulog_req_msg req_msg = { { 0 } };
|
||||
|
||||
req_msg.hdr.owner = MSG_OWNER_CHG_ULOG;
|
||||
req_msg.hdr.type = MSG_TYPE_REQ_RESP;
|
||||
req_msg.hdr.opcode = init ? GET_CHG_INIT_ULOG_REQ : GET_CHG_ULOG_REQ;
|
||||
req_msg.log_size = MAX_ULOG_SIZE;
|
||||
|
||||
return chg_ulog_write(cd, &req_msg, sizeof(req_msg));
|
||||
}
|
||||
|
||||
static int chg_ulog_set_log_type(struct chg_ulog_glink_dev *cd, u64 category,
|
||||
u32 level)
|
||||
{
|
||||
struct set_ulog_prop_req_msg req_msg = { { 0 } };
|
||||
int rc;
|
||||
|
||||
req_msg.hdr.owner = MSG_OWNER_CHG_ULOG;
|
||||
req_msg.hdr.type = MSG_TYPE_REQ_RESP;
|
||||
req_msg.hdr.opcode = SET_CHG_ULOG_PROP_REQ;
|
||||
req_msg.log_category = category;
|
||||
req_msg.log_level = level;
|
||||
|
||||
rc = chg_ulog_write(cd, &req_msg, sizeof(req_msg));
|
||||
if (!rc)
|
||||
pr_debug("Set log category %llu log level %u\n", category,
|
||||
level);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void chg_ulog_work(struct work_struct *work)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd = container_of(work,
|
||||
struct chg_ulog_glink_dev,
|
||||
ulog_work.work);
|
||||
int rc;
|
||||
|
||||
rc = chg_ulog_request(cd, cd->init_log_enable);
|
||||
if (rc)
|
||||
pr_err("Error requesting ulog, rc=%d\n", rc);
|
||||
else if (cd->log_enable || cd->init_log_enable)
|
||||
schedule_delayed_work(&cd->ulog_work,
|
||||
msecs_to_jiffies(cd->log_time_ms));
|
||||
}
|
||||
|
||||
static void ulog_store(struct chg_ulog_glink_dev *cd, void *ipc_ctxt,
|
||||
size_t len)
|
||||
{
|
||||
char *buf = cd->ulog_buf, *token = NULL;
|
||||
|
||||
if (buf[0] == '\0') {
|
||||
pr_debug("buffer is NULL\n");
|
||||
if (cd->init_log_enable)
|
||||
cd->init_log_enable = false;
|
||||
return;
|
||||
}
|
||||
|
||||
buf[len - 1] = '\0';
|
||||
if (len >= MAX_MSG_SIZE) {
|
||||
do {
|
||||
token = strsep((char **)&buf, "\n");
|
||||
if (token)
|
||||
ipc_log_string(ipc_ctxt, "%s", token);
|
||||
} while (token);
|
||||
} else {
|
||||
ipc_log_string(ipc_ctxt, "%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_ulog_message(struct chg_ulog_glink_dev *cd,
|
||||
struct get_ulog_resp_msg *resp_msg,
|
||||
size_t len)
|
||||
{
|
||||
void *ipc_ctxt;
|
||||
|
||||
if (len != sizeof(*resp_msg)) {
|
||||
pr_err("Expected data length: %zu, received: %zu\n",
|
||||
sizeof(*resp_msg), len);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(cd->ulog_buf, resp_msg->buf, sizeof(cd->ulog_buf));
|
||||
ipc_ctxt = (resp_msg->hdr.opcode == GET_CHG_INIT_ULOG_REQ)
|
||||
? cd->ipc_init_log : cd->ipc_log;
|
||||
|
||||
ulog_store(cd, ipc_ctxt, len - sizeof(resp_msg->hdr));
|
||||
}
|
||||
|
||||
static int chg_ulog_callback(void *priv, void *data, size_t len)
|
||||
{
|
||||
struct pmic_glink_hdr *hdr = data;
|
||||
struct chg_ulog_glink_dev *cd = priv;
|
||||
|
||||
pr_debug("owner: %u type: %u opcode: %#x len: %zu\n", hdr->owner,
|
||||
hdr->type, hdr->opcode, len);
|
||||
|
||||
switch (hdr->opcode) {
|
||||
case SET_CHG_ULOG_PROP_REQ:
|
||||
complete(&cd->ack);
|
||||
break;
|
||||
case GET_CHG_ULOG_REQ:
|
||||
case GET_CHG_INIT_ULOG_REQ:
|
||||
handle_ulog_message(cd, data, len);
|
||||
complete(&cd->ack);
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown opcode %u\n", hdr->opcode);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ulog_cat_get(void *data, u64 *val)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd = data;
|
||||
|
||||
*val = cd->log_category;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ulog_cat_set(void *data, u64 val)
|
||||
{
|
||||
int rc;
|
||||
struct chg_ulog_glink_dev *cd = data;
|
||||
|
||||
if (cd->log_enable) {
|
||||
pr_err("Disable ulog before changing log category\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (val == cd->log_category)
|
||||
return 0;
|
||||
|
||||
rc = chg_ulog_set_log_type(cd, val, cd->log_level);
|
||||
if (rc)
|
||||
pr_err("Couldn't set log_category rc=%d\n", rc);
|
||||
else
|
||||
cd->log_category = val;
|
||||
|
||||
return rc;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(ulog_cat_fops, ulog_cat_get, ulog_cat_set,
|
||||
"%llu\n");
|
||||
|
||||
static int ulog_level_get(void *data, u64 *val)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd = data;
|
||||
|
||||
*val = cd->log_level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ulog_level_set(void *data, u64 val)
|
||||
{
|
||||
int rc;
|
||||
struct chg_ulog_glink_dev *cd = data;
|
||||
u32 level = val;
|
||||
|
||||
if (cd->log_enable) {
|
||||
pr_err("Disable ulog before changing log level\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (level == cd->log_level)
|
||||
return 0;
|
||||
|
||||
rc = chg_ulog_set_log_type(cd, cd->log_category, level);
|
||||
if (rc)
|
||||
pr_err("Couldn't set log_level rc=%d\n", rc);
|
||||
else
|
||||
cd->log_level = level;
|
||||
|
||||
return rc;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(ulog_level_fops, ulog_level_get, ulog_level_set,
|
||||
"%llu\n");
|
||||
|
||||
static int ulog_en_get(void *data, u64 *val)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd = data;
|
||||
|
||||
*val = cd->log_enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ulog_en_set(void *data, u64 val)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd = data;
|
||||
bool en = val;
|
||||
|
||||
if (en == cd->log_enable)
|
||||
return 0;
|
||||
|
||||
if (cd->log_category == LOG_CATEGORY_INIT)
|
||||
cd->init_log_enable = en;
|
||||
else
|
||||
cd->log_enable = en;
|
||||
|
||||
if (en)
|
||||
schedule_delayed_work(&cd->ulog_work,
|
||||
msecs_to_jiffies(cd->log_time_ms));
|
||||
else
|
||||
cancel_delayed_work_sync(&cd->ulog_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(ulog_en_fops, ulog_en_get, ulog_en_set, "%llu\n");
|
||||
|
||||
static int ulog_time_get(void *data, u64 *val)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd = data;
|
||||
|
||||
*val = cd->log_time_ms;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ulog_time_set(void *data, u64 val)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd = data;
|
||||
|
||||
if (val == cd->log_time_ms)
|
||||
return 0;
|
||||
|
||||
if (val < LOG_MIN_TIME_MS)
|
||||
return -EINVAL;
|
||||
|
||||
cd->log_time_ms = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(ulog_time_fops, ulog_time_get, ulog_time_set,
|
||||
"%llu\n");
|
||||
|
||||
static int chg_ulog_add_debugfs(struct chg_ulog_glink_dev *cd)
|
||||
{
|
||||
struct dentry *dir, *file;
|
||||
int rc;
|
||||
|
||||
dir = debugfs_create_dir("charger_ulog", NULL);
|
||||
if (IS_ERR(dir)) {
|
||||
rc = PTR_ERR(dir);
|
||||
pr_err("Failed to create charger_ulog debugfs directory: %d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
file = debugfs_create_file_unsafe("category", 0600, dir, cd,
|
||||
&ulog_cat_fops);
|
||||
if (IS_ERR(file)) {
|
||||
rc = PTR_ERR(file);
|
||||
pr_err("Failed to create category %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
file = debugfs_create_file_unsafe("level", 0600, dir, cd,
|
||||
&ulog_level_fops);
|
||||
if (IS_ERR(file)) {
|
||||
rc = PTR_ERR(file);
|
||||
pr_err("Failed to create level %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
file = debugfs_create_file_unsafe("enable", 0600, dir, cd,
|
||||
&ulog_en_fops);
|
||||
if (IS_ERR(file)) {
|
||||
rc = PTR_ERR(file);
|
||||
pr_err("Failed to create enable %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
file = debugfs_create_file_unsafe("time_ms", 0600, dir, cd,
|
||||
&ulog_time_fops);
|
||||
if (IS_ERR(file)) {
|
||||
rc = PTR_ERR(file);
|
||||
pr_err("Failed to create time_ms %d\n", rc);
|
||||
goto out;
|
||||
}
|
||||
cd->debugfs_dir = dir;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
debugfs_remove_recursive(dir);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int chg_ulog_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd;
|
||||
struct pmic_glink_client_data client_data = { };
|
||||
int rc;
|
||||
|
||||
cd = devm_kzalloc(&pdev->dev, sizeof(*cd), GFP_KERNEL);
|
||||
if (!cd)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&cd->lock);
|
||||
init_completion(&cd->ack);
|
||||
INIT_DELAYED_WORK(&cd->ulog_work, chg_ulog_work);
|
||||
cd->log_time_ms = LOG_DEFAULT_TIME_MS;
|
||||
platform_set_drvdata(pdev, cd);
|
||||
|
||||
cd->dev = &pdev->dev;
|
||||
client_data.id = MSG_OWNER_CHG_ULOG;
|
||||
client_data.name = "chg_ulog";
|
||||
client_data.msg_cb = chg_ulog_callback;
|
||||
client_data.priv = cd;
|
||||
|
||||
cd->client = pmic_glink_register_client(cd->dev, &client_data);
|
||||
if (IS_ERR(cd->client))
|
||||
return dev_err_probe(cd->dev, PTR_ERR(cd->client),
|
||||
"Error in registering with pmic_glink %d\n");
|
||||
|
||||
rc = chg_ulog_add_debugfs(cd);
|
||||
if (rc) {
|
||||
pmic_glink_unregister_client(cd->client);
|
||||
return dev_err_probe(cd->dev, -EINVAL, "Error in creating debugfs\n");
|
||||
}
|
||||
|
||||
cd->ipc_log = ipc_log_context_create(NUM_LOG_PAGES, "charger_ulog", 0);
|
||||
if (!cd->ipc_log) {
|
||||
pmic_glink_unregister_client(cd->client);
|
||||
debugfs_remove_recursive(cd->debugfs_dir);
|
||||
return dev_err_probe(cd->dev, -ENODEV, "Error in creating charger_ulog\n");
|
||||
}
|
||||
|
||||
cd->ipc_init_log = ipc_log_context_create(NUM_INIT_LOG_PAGES,
|
||||
"charger_ulog_init", 0);
|
||||
if (!cd->ipc_init_log) {
|
||||
pmic_glink_unregister_client(cd->client);
|
||||
ipc_log_context_destroy(cd->ipc_log);
|
||||
debugfs_remove_recursive(cd->debugfs_dir);
|
||||
return dev_err_probe(cd->dev, -ENODEV, "Error in creating charger_ulog_init\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chg_ulog_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct chg_ulog_glink_dev *cd = platform_get_drvdata(pdev);
|
||||
int rc;
|
||||
|
||||
debugfs_remove_recursive(cd->debugfs_dir);
|
||||
cancel_delayed_work_sync(&cd->ulog_work);
|
||||
|
||||
rc = pmic_glink_unregister_client(cd->client);
|
||||
if (rc < 0)
|
||||
pr_err("Error unregistering from pmic_glink, rc=%d\n", rc);
|
||||
|
||||
ipc_log_context_destroy(cd->ipc_log);
|
||||
ipc_log_context_destroy(cd->ipc_init_log);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id chg_ulog_match_table[] = {
|
||||
{ .compatible = "qcom,charger-ulog-glink" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver chg_ulog_driver = {
|
||||
.driver = {
|
||||
.name = "charger_ulog_glink",
|
||||
.of_match_table = chg_ulog_match_table,
|
||||
},
|
||||
.probe = chg_ulog_probe,
|
||||
.remove = chg_ulog_remove,
|
||||
};
|
||||
module_platform_driver(chg_ulog_driver);
|
||||
|
||||
MODULE_DESCRIPTION("QTI charger ulog glink driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Loading…
Reference in New Issue
Block a user