Merge "soc: qcom: altmode-glink: add SSR support"
This commit is contained in:
commit
d8b549ff22
@ -148,6 +148,8 @@ struct battery_chg_dev {
|
||||
u32 *thermal_levels;
|
||||
int curr_thermal_level;
|
||||
int num_thermal_levels;
|
||||
atomic_t state;
|
||||
struct work_struct subsys_up_work;
|
||||
};
|
||||
|
||||
static const int battery_prop_map[BATT_PROP_MAX] = {
|
||||
@ -198,6 +200,16 @@ static int battery_chg_write(struct battery_chg_dev *bcdev, void *data,
|
||||
{
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* When the subsystem goes down, it's better to return the last
|
||||
* known values until it comes back up. Hence, return 0 so that
|
||||
* pmic_glink_write() is not attempted until pmic glink is up.
|
||||
*/
|
||||
if (atomic_read(&bcdev->state) == PMIC_GLINK_STATE_DOWN) {
|
||||
pr_debug("glink state is down\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_lock(&bcdev->rw_lock);
|
||||
reinit_completion(&bcdev->ack);
|
||||
rc = pmic_glink_write(bcdev->client, data, len);
|
||||
@ -268,6 +280,40 @@ static int get_property_id(struct psy_state *pst,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void battery_chg_notify_enable(struct battery_chg_dev *bcdev)
|
||||
{
|
||||
struct battery_charger_set_notify_msg req_msg = { { 0 } };
|
||||
int rc;
|
||||
|
||||
/* Send request to enable notification */
|
||||
req_msg.hdr.owner = MSG_OWNER_BC;
|
||||
req_msg.hdr.type = MSG_TYPE_NOTIFY;
|
||||
req_msg.hdr.opcode = BC_SET_NOTIFY_REQ;
|
||||
|
||||
rc = battery_chg_write(bcdev, &req_msg, sizeof(req_msg));
|
||||
if (rc < 0)
|
||||
pr_err("Failed to enable notification rc=%d\n", rc);
|
||||
}
|
||||
|
||||
static void battery_chg_subsys_up_work(struct work_struct *work)
|
||||
{
|
||||
struct battery_chg_dev *bcdev = container_of(work,
|
||||
struct battery_chg_dev, subsys_up_work);
|
||||
|
||||
battery_chg_notify_enable(bcdev);
|
||||
}
|
||||
|
||||
static void battery_chg_state_cb(void *priv, enum pmic_glink_state state)
|
||||
{
|
||||
struct battery_chg_dev *bcdev = priv;
|
||||
|
||||
pr_debug("state: %d\n", state);
|
||||
|
||||
atomic_set(&bcdev->state, state);
|
||||
if (state == PMIC_GLINK_STATE_UP)
|
||||
schedule_work(&bcdev->subsys_up_work);
|
||||
}
|
||||
|
||||
/**
|
||||
* qti_battery_charger_get_prop() - Gets the property being requested
|
||||
*
|
||||
@ -977,7 +1023,6 @@ static int battery_chg_probe(struct platform_device *pdev)
|
||||
struct battery_chg_dev *bcdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pmic_glink_client_data client_data = { };
|
||||
struct battery_charger_set_notify_msg req_msg = { { 0 } };
|
||||
int rc, i;
|
||||
|
||||
bcdev = devm_kzalloc(&pdev->dev, sizeof(*bcdev), GFP_KERNEL);
|
||||
@ -1012,12 +1057,15 @@ static int battery_chg_probe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&bcdev->rw_lock);
|
||||
init_completion(&bcdev->ack);
|
||||
INIT_WORK(&bcdev->subsys_up_work, battery_chg_subsys_up_work);
|
||||
atomic_set(&bcdev->state, PMIC_GLINK_STATE_UP);
|
||||
bcdev->dev = dev;
|
||||
|
||||
client_data.id = MSG_OWNER_BC;
|
||||
client_data.name = "battery_charger";
|
||||
client_data.callback = battery_chg_callback;
|
||||
client_data.msg_cb = battery_chg_callback;
|
||||
client_data.priv = bcdev;
|
||||
client_data.state_cb = battery_chg_state_cb;
|
||||
|
||||
bcdev->client = pmic_glink_register_client(dev, &client_data);
|
||||
if (IS_ERR(bcdev->client)) {
|
||||
@ -1045,14 +1093,7 @@ static int battery_chg_probe(struct platform_device *pdev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Send request to enable notification */
|
||||
req_msg.hdr.owner = MSG_OWNER_BC;
|
||||
req_msg.hdr.type = MSG_TYPE_NOTIFY;
|
||||
req_msg.hdr.opcode = BC_SET_NOTIFY_REQ;
|
||||
|
||||
rc = battery_chg_write(bcdev, &req_msg, sizeof(req_msg));
|
||||
if (rc < 0)
|
||||
pr_err("Failed to enable notification rc=%d\n", rc);
|
||||
battery_chg_notify_enable(bcdev);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
|
@ -381,6 +381,28 @@ static int altmode_send_ack(struct altmode_dev *amdev, u8 port_index)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void altmode_state_cb(void *priv, enum pmic_glink_state state)
|
||||
{
|
||||
struct altmode_dev *amdev = priv;
|
||||
|
||||
pr_debug("state: %d\n", state);
|
||||
|
||||
switch (state) {
|
||||
case PMIC_GLINK_STATE_DOWN:
|
||||
/* As of now, nothing to do */
|
||||
break;
|
||||
case PMIC_GLINK_STATE_UP:
|
||||
mutex_lock(&amdev->client_lock);
|
||||
if (!list_empty(&amdev->client_list))
|
||||
schedule_delayed_work(&amdev->send_pan_en_work,
|
||||
msecs_to_jiffies(20));
|
||||
mutex_unlock(&amdev->client_lock);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#define USBC_NOTIFY_IND_MASK GENMASK(7, 0)
|
||||
#define GET_OP(opcode) (opcode & USBC_NOTIFY_IND_MASK)
|
||||
#define GET_SVID(opcode) (opcode >> 16)
|
||||
@ -495,10 +517,17 @@ static int altmode_probe(struct platform_device *pdev)
|
||||
|
||||
RAW_INIT_NOTIFIER_HEAD(&amdev->probe_notifier);
|
||||
|
||||
mutex_init(&amdev->client_lock);
|
||||
idr_init(&amdev->client_idr);
|
||||
INIT_DELAYED_WORK(&amdev->send_pan_en_work, altmode_send_pan_en);
|
||||
INIT_LIST_HEAD(&amdev->d_node);
|
||||
INIT_LIST_HEAD(&amdev->client_list);
|
||||
|
||||
pgclient_data.id = MSG_OWNER_USBC_PAN;
|
||||
pgclient_data.name = "altmode";
|
||||
pgclient_data.callback = altmode_callback;
|
||||
pgclient_data.msg_cb = altmode_callback;
|
||||
pgclient_data.priv = amdev;
|
||||
pgclient_data.state_cb = altmode_state_cb;
|
||||
|
||||
amdev->pgclient = pmic_glink_register_client(amdev->dev,
|
||||
&pgclient_data);
|
||||
@ -507,21 +536,19 @@ static int altmode_probe(struct platform_device *pdev)
|
||||
if (rc != -EPROBE_DEFER)
|
||||
dev_err(dev, "Error in pmic_glink registration: %d\n",
|
||||
rc);
|
||||
return rc;
|
||||
goto error_register;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, amdev);
|
||||
|
||||
mutex_init(&amdev->client_lock);
|
||||
idr_init(&amdev->client_idr);
|
||||
INIT_DELAYED_WORK(&amdev->send_pan_en_work, altmode_send_pan_en);
|
||||
INIT_LIST_HEAD(&amdev->d_node);
|
||||
INIT_LIST_HEAD(&amdev->client_list);
|
||||
|
||||
altmode_device_add(amdev);
|
||||
altmode_notify_clients(amdev, pdev);
|
||||
|
||||
return 0;
|
||||
|
||||
error_register:
|
||||
idr_destroy(&amdev->client_idr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void altmode_device_remove(struct altmode_dev *amdev)
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define pr_fmt(fmt) "PMIC_GLINK: %s: " fmt, __func__
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/list.h>
|
||||
@ -16,6 +17,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <soc/qcom/subsystem_notif.h>
|
||||
#include <linux/soc/qcom/pmic_glink.h>
|
||||
|
||||
/**
|
||||
@ -33,9 +35,16 @@
|
||||
* @rx_list: list for rx messages
|
||||
* @dev_list: list for pmic_glink_dev_list
|
||||
* @state: indicates when remote subsystem is up/down
|
||||
* @prev_state: previous state of remote subsystem
|
||||
* @child_probed: indicates when the children are probed
|
||||
* @log_filter: message owner filter for logging
|
||||
* @log_enable: enables message logging
|
||||
* @client_dev_list: list of client devices to be notified on state
|
||||
* transition during an SSR or PDR
|
||||
* @ssr_nb: notifier block for subsystem notifier
|
||||
* @subsys_name: subsystem name from which SSR notifications should
|
||||
* be handled and notified to the clients
|
||||
* @subsys_handle: handle to subsystem notifier
|
||||
*/
|
||||
struct pmic_glink_dev {
|
||||
struct rpmsg_device *rpdev;
|
||||
@ -51,9 +60,14 @@ struct pmic_glink_dev {
|
||||
struct list_head rx_list;
|
||||
struct list_head dev_list;
|
||||
atomic_t state;
|
||||
atomic_t prev_state;
|
||||
bool child_probed;
|
||||
u32 log_filter;
|
||||
bool log_enable;
|
||||
struct list_head client_dev_list;
|
||||
struct notifier_block ssr_nb;
|
||||
const char *subsys_name;
|
||||
void *subsys_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -63,7 +77,11 @@ struct pmic_glink_dev {
|
||||
* @id: Unique id for client for communication
|
||||
* @lock: lock for sending data
|
||||
* @priv: private data for client
|
||||
* @callback: callback function for client
|
||||
* @msg_cb: callback function for client to receive the messages that
|
||||
* are intended to be delivered to it over PMIC Glink
|
||||
* @node: list node to be added in client_dev_list of pmic_glink device
|
||||
* @state_cb: callback function to notify pmic glink state in the event of
|
||||
* a subsystem restart (SSR) or a protection domain restart (PDR)
|
||||
*/
|
||||
struct pmic_glink_client {
|
||||
struct pmic_glink_dev *pgdev;
|
||||
@ -71,7 +89,10 @@ struct pmic_glink_client {
|
||||
u32 id;
|
||||
struct mutex lock;
|
||||
void *priv;
|
||||
int (*callback)(void *priv, void *data, size_t len);
|
||||
int (*msg_cb)(void *priv, void *data, size_t len);
|
||||
struct list_head node;
|
||||
void (*state_cb)(void *priv,
|
||||
enum pmic_glink_state state);
|
||||
};
|
||||
|
||||
struct pmic_glink_buf {
|
||||
@ -83,6 +104,50 @@ struct pmic_glink_buf {
|
||||
static LIST_HEAD(pmic_glink_dev_list);
|
||||
static DEFINE_MUTEX(pmic_glink_dev_lock);
|
||||
|
||||
static void pmic_glink_notify_clients(struct pmic_glink_dev *pgdev,
|
||||
enum pmic_glink_state state)
|
||||
{
|
||||
struct pmic_glink_client *pos;
|
||||
|
||||
pm_stay_awake(pgdev->dev);
|
||||
|
||||
mutex_lock(&pgdev->client_lock);
|
||||
list_for_each_entry(pos, &pgdev->client_dev_list, node)
|
||||
pos->state_cb(pos->priv, state);
|
||||
mutex_unlock(&pgdev->client_lock);
|
||||
|
||||
pm_relax(pgdev->dev);
|
||||
|
||||
pr_debug("state_cb done %d\n", state);
|
||||
}
|
||||
|
||||
static int pmic_glink_ssr_notifier_cb(struct notifier_block *nb,
|
||||
unsigned long code, void *data)
|
||||
{
|
||||
struct pmic_glink_dev *pgdev = container_of(nb, struct pmic_glink_dev,
|
||||
ssr_nb);
|
||||
|
||||
pr_debug("code: %lu\n", code);
|
||||
|
||||
switch (code) {
|
||||
case SUBSYS_BEFORE_SHUTDOWN:
|
||||
atomic_set(&pgdev->prev_state, code);
|
||||
pmic_glink_notify_clients(pgdev, PMIC_GLINK_STATE_DOWN);
|
||||
break;
|
||||
case SUBSYS_AFTER_POWERUP:
|
||||
/*
|
||||
* Do not notify PMIC Glink clients here but rather from
|
||||
* pmic_glink_init_work which will be run only after rpmsg
|
||||
* driver is probed and Glink communication is up.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct pmic_glink_dev *get_pmic_glink_from_dev(struct device *dev)
|
||||
{
|
||||
struct pmic_glink_dev *tmp, *pos;
|
||||
@ -177,7 +242,7 @@ struct pmic_glink_client *pmic_glink_register_client(struct device *dev,
|
||||
if (!dev || !dev->parent)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
if (!client_data->id || !client_data->callback || !client_data->name)
|
||||
if (!client_data->id || !client_data->msg_cb || !client_data->name)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pgdev = get_pmic_glink_from_dev(dev->parent);
|
||||
@ -204,9 +269,10 @@ struct pmic_glink_client *pmic_glink_register_client(struct device *dev,
|
||||
|
||||
mutex_init(&client->lock);
|
||||
client->id = client_data->id;
|
||||
client->callback = client_data->callback;
|
||||
client->msg_cb = client_data->msg_cb;
|
||||
client->priv = client_data->priv;
|
||||
client->pgdev = pgdev;
|
||||
client->state_cb = client_data->state_cb;
|
||||
|
||||
mutex_lock(&pgdev->client_lock);
|
||||
rc = idr_alloc(&pgdev->client_idr, client, client->id, client->id + 1,
|
||||
@ -220,6 +286,10 @@ struct pmic_glink_client *pmic_glink_register_client(struct device *dev,
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
if (client->state_cb) {
|
||||
INIT_LIST_HEAD(&client->node);
|
||||
list_add_tail(&client->node, &pgdev->client_dev_list);
|
||||
}
|
||||
mutex_unlock(&pgdev->client_lock);
|
||||
|
||||
return client;
|
||||
@ -238,10 +308,17 @@ EXPORT_SYMBOL(pmic_glink_register_client);
|
||||
*/
|
||||
int pmic_glink_unregister_client(struct pmic_glink_client *client)
|
||||
{
|
||||
struct pmic_glink_client *pos, *tmp;
|
||||
|
||||
if (!client || !client->pgdev)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&client->pgdev->client_lock);
|
||||
list_for_each_entry_safe(pos, tmp, &client->pgdev->client_dev_list,
|
||||
node) {
|
||||
if (pos == client)
|
||||
list_del(&client->node);
|
||||
}
|
||||
idr_remove(&client->pgdev->client_idr, client->id);
|
||||
mutex_unlock(&client->pgdev->client_lock);
|
||||
|
||||
@ -263,7 +340,7 @@ static void pmic_glink_rx_callback(struct pmic_glink_dev *pgdev,
|
||||
client = idr_find(&pgdev->client_idr, hdr->owner);
|
||||
mutex_unlock(&pgdev->client_lock);
|
||||
|
||||
if (!client || !client->callback) {
|
||||
if (!client || !client->msg_cb) {
|
||||
pr_err("No client present for %u\n", hdr->owner);
|
||||
return;
|
||||
}
|
||||
@ -276,7 +353,7 @@ static void pmic_glink_rx_callback(struct pmic_glink_dev *pgdev,
|
||||
pbuf->buf);
|
||||
}
|
||||
|
||||
client->callback(client->priv, pbuf->buf, pbuf->len);
|
||||
client->msg_cb(client->priv, pbuf->buf, pbuf->len);
|
||||
}
|
||||
|
||||
static void pmic_glink_rx_work(struct work_struct *work)
|
||||
@ -411,6 +488,11 @@ static void pmic_glink_init_work(struct work_struct *work)
|
||||
struct device *dev = pgdev->dev;
|
||||
int rc;
|
||||
|
||||
if (atomic_read(&pgdev->prev_state) == SUBSYS_BEFORE_SHUTDOWN) {
|
||||
pmic_glink_notify_clients(pgdev, PMIC_GLINK_STATE_UP);
|
||||
atomic_set(&pgdev->prev_state, SUBSYS_AFTER_POWERUP);
|
||||
}
|
||||
|
||||
if (pgdev->child_probed)
|
||||
return;
|
||||
|
||||
@ -463,34 +545,60 @@ static int pmic_glink_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
of_property_read_string(dev->of_node, "qcom,subsys-name",
|
||||
&pgdev->subsys_name);
|
||||
|
||||
pgdev->rx_wq = create_singlethread_workqueue("pmic_glink_rx");
|
||||
if (!pgdev->rx_wq) {
|
||||
pr_err("Failed to create pmic_glink_rx wq\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, pgdev);
|
||||
|
||||
INIT_WORK(&pgdev->rx_work, pmic_glink_rx_work);
|
||||
INIT_WORK(&pgdev->init_work, pmic_glink_init_work);
|
||||
INIT_LIST_HEAD(&pgdev->client_dev_list);
|
||||
INIT_LIST_HEAD(&pgdev->rx_list);
|
||||
INIT_LIST_HEAD(&pgdev->dev_list);
|
||||
spin_lock_init(&pgdev->rx_lock);
|
||||
mutex_init(&pgdev->client_lock);
|
||||
idr_init(&pgdev->client_idr);
|
||||
atomic_set(&pgdev->prev_state, SUBSYS_BEFORE_POWERUP);
|
||||
|
||||
if (pgdev->subsys_name) {
|
||||
pgdev->ssr_nb.notifier_call = pmic_glink_ssr_notifier_cb;
|
||||
pgdev->subsys_handle = subsys_notif_register_notifier(
|
||||
pgdev->subsys_name,
|
||||
&pgdev->ssr_nb);
|
||||
if (IS_ERR(pgdev->subsys_handle)) {
|
||||
rc = PTR_ERR(pgdev->subsys_handle);
|
||||
pr_err("Failed in subsys_notif_register_notifier %d\n",
|
||||
rc);
|
||||
goto error_subsys;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, pgdev);
|
||||
pgdev->dev = dev;
|
||||
|
||||
pmic_glink_dev_add(pgdev);
|
||||
pmic_glink_add_debugfs(pgdev);
|
||||
device_init_wakeup(pgdev->dev, true);
|
||||
|
||||
pr_debug("%s probed successfully\n", pgdev->channel_name);
|
||||
return 0;
|
||||
|
||||
error_subsys:
|
||||
idr_destroy(&pgdev->client_idr);
|
||||
destroy_workqueue(pgdev->rx_wq);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic_glink_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pmic_glink_dev *pgdev = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
subsys_notif_unregister_notifier(pgdev->subsys_handle, &pgdev->ssr_nb);
|
||||
device_init_wakeup(pgdev->dev, false);
|
||||
debugfs_remove_recursive(pgdev->debugfs_dir);
|
||||
flush_workqueue(pgdev->rx_wq);
|
||||
destroy_workqueue(pgdev->rx_wq);
|
||||
|
@ -683,7 +683,7 @@ static int battery_dbg_probe(struct platform_device *pdev)
|
||||
bd->dev = &pdev->dev;
|
||||
client_data.id = MSG_OWNER_BD;
|
||||
client_data.name = "battery_debug";
|
||||
client_data.callback = battery_dbg_callback;
|
||||
client_data.msg_cb = battery_dbg_callback;
|
||||
client_data.priv = bd;
|
||||
|
||||
bd->client = pmic_glink_register_client(bd->dev, &client_data);
|
||||
|
@ -321,7 +321,7 @@ static int spmi_glink_probe(struct platform_device *pdev)
|
||||
|
||||
client_data.id = MSG_OWNER_REG_DUMP;
|
||||
client_data.name = "spmi_register_debug";
|
||||
client_data.callback = spmi_glink_callback;
|
||||
client_data.msg_cb = spmi_glink_callback;
|
||||
client_data.priv = gd;
|
||||
|
||||
gd->client = pmic_glink_register_client(&pdev->dev, &client_data);
|
||||
|
@ -84,6 +84,8 @@ struct ucsi_dev {
|
||||
unsigned long cmd_requested_flags;
|
||||
struct ucsi_glink_constat_info constat_info;
|
||||
struct work_struct notify_work;
|
||||
struct work_struct setup_work;
|
||||
atomic_t state;
|
||||
};
|
||||
|
||||
static void *ucsi_ipc_log;
|
||||
@ -267,6 +269,9 @@ static int ucsi_qti_glink_write(struct ucsi_dev *udev, unsigned int offset,
|
||||
if (!validate_ucsi_msg(offset, val_len))
|
||||
return -EINVAL;
|
||||
|
||||
if (atomic_read(&udev->state) == PMIC_GLINK_STATE_DOWN)
|
||||
return 0;
|
||||
|
||||
ucsi_buf.hdr.owner = MSG_OWNER_UC;
|
||||
ucsi_buf.hdr.type = MSG_TYPE_REQ_RESP;
|
||||
ucsi_buf.hdr.opcode = UC_UCSI_WRITE_BUF_REQ;
|
||||
@ -395,6 +400,9 @@ static int ucsi_qti_read(struct ucsi *ucsi, unsigned int offset,
|
||||
if (!validate_ucsi_msg(offset, val_len))
|
||||
return -EINVAL;
|
||||
|
||||
if (atomic_read(&udev->state) == PMIC_GLINK_STATE_DOWN)
|
||||
return 0;
|
||||
|
||||
ucsi_buf.hdr.owner = MSG_OWNER_UC;
|
||||
ucsi_buf.hdr.type = MSG_TYPE_REQ_RESP;
|
||||
ucsi_buf.hdr.opcode = UC_UCSI_READ_BUF_REQ;
|
||||
@ -442,6 +450,71 @@ static const struct ucsi_operations ucsi_qti_ops = {
|
||||
.async_write = ucsi_qti_async_write
|
||||
};
|
||||
|
||||
static int ucsi_setup(struct ucsi_dev *udev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (udev->ucsi) {
|
||||
dev_err(udev->dev, "ucsi is not NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
udev->ucsi = ucsi_create(udev->dev, &ucsi_qti_ops);
|
||||
if (IS_ERR(udev->ucsi)) {
|
||||
rc = PTR_ERR(udev->ucsi);
|
||||
dev_err(udev->dev, "ucsi_create failed rc=%d\n", rc);
|
||||
udev->ucsi = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
ucsi_set_drvdata(udev->ucsi, udev);
|
||||
|
||||
rc = ucsi_register(udev->ucsi);
|
||||
if (rc) {
|
||||
dev_err(udev->dev, "ucsi_register failed rc=%d\n", rc);
|
||||
ucsi_destroy(udev->ucsi);
|
||||
udev->ucsi = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ucsi_qti_setup_work(struct work_struct *work)
|
||||
{
|
||||
struct ucsi_dev *udev = container_of(work, struct ucsi_dev,
|
||||
setup_work);
|
||||
|
||||
ucsi_setup(udev);
|
||||
}
|
||||
|
||||
static void ucsi_qti_state_cb(void *priv, enum pmic_glink_state state)
|
||||
{
|
||||
struct ucsi_dev *udev = priv;
|
||||
|
||||
dev_dbg(udev->dev, "state: %d\n", state);
|
||||
|
||||
atomic_set(&udev->state, state);
|
||||
|
||||
switch (state) {
|
||||
case PMIC_GLINK_STATE_DOWN:
|
||||
if (!udev->ucsi) {
|
||||
dev_err(udev->dev, "ucsi is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ucsi_unregister(udev->ucsi);
|
||||
ucsi_destroy(udev->ucsi);
|
||||
udev->ucsi = NULL;
|
||||
break;
|
||||
case PMIC_GLINK_STATE_UP:
|
||||
schedule_work(&udev->setup_work);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ucsi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -454,6 +527,7 @@ static int ucsi_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&udev->notify_work, ucsi_qti_notify_work);
|
||||
INIT_WORK(&udev->setup_work, ucsi_qti_setup_work);
|
||||
mutex_init(&udev->read_lock);
|
||||
mutex_init(&udev->write_lock);
|
||||
mutex_init(&udev->notify_lock);
|
||||
@ -461,11 +535,13 @@ static int ucsi_probe(struct platform_device *pdev)
|
||||
init_completion(&udev->write_ack);
|
||||
init_completion(&udev->sync_write_ack);
|
||||
atomic_set(&udev->rx_valid, 0);
|
||||
atomic_set(&udev->state, PMIC_GLINK_STATE_UP);
|
||||
|
||||
client_data.id = MSG_OWNER_UC;
|
||||
client_data.name = "ucsi";
|
||||
client_data.callback = ucsi_callback;
|
||||
client_data.msg_cb = ucsi_callback;
|
||||
client_data.priv = udev;
|
||||
client_data.state_cb = ucsi_qti_state_cb;
|
||||
|
||||
udev->client = pmic_glink_register_client(dev, &client_data);
|
||||
if (IS_ERR(udev->client)) {
|
||||
@ -477,34 +553,19 @@ static int ucsi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, udev);
|
||||
udev->dev = dev;
|
||||
|
||||
udev->ucsi = ucsi_create(dev, &ucsi_qti_ops);
|
||||
if (IS_ERR(udev->ucsi)) {
|
||||
rc = PTR_ERR(udev->ucsi);
|
||||
dev_err(dev, "ucsi_create failed rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ucsi_set_drvdata(udev->ucsi, udev);
|
||||
ucsi_ipc_log = ipc_log_context_create(NUM_LOG_PAGES, "ucsi", 0);
|
||||
if (!ucsi_ipc_log)
|
||||
dev_warn(dev, "Error in creating ipc_log_context\n");
|
||||
|
||||
rc = ucsi_register(udev->ucsi);
|
||||
rc = ucsi_setup(udev);
|
||||
if (rc) {
|
||||
dev_err(dev, "ucsi_register failed rc=%d\n", rc);
|
||||
goto out;
|
||||
ipc_log_context_destroy(ucsi_ipc_log);
|
||||
ucsi_ipc_log = NULL;
|
||||
pmic_glink_unregister_client(udev->client);
|
||||
}
|
||||
|
||||
pr_debug("driver probed\n");
|
||||
|
||||
return 0;
|
||||
out:
|
||||
ipc_log_context_destroy(ucsi_ipc_log);
|
||||
ucsi_ipc_log = NULL;
|
||||
ucsi_destroy(udev->ucsi);
|
||||
pmic_glink_unregister_client(udev->client);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _PMIC_GLINK_H
|
||||
@ -11,18 +11,27 @@
|
||||
struct pmic_glink_client;
|
||||
struct device;
|
||||
|
||||
enum pmic_glink_state {
|
||||
PMIC_GLINK_STATE_DOWN,
|
||||
PMIC_GLINK_STATE_UP,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pmic_glink_client_data - pmic_glink client data
|
||||
* @name: Client name
|
||||
* @id: Unique id for client for communication
|
||||
* @priv: private data for client
|
||||
* @callback: callback function for client
|
||||
* @msg_cb: callback function for client to receive the messages that
|
||||
* are intended to be delivered to it over PMIC Glink
|
||||
* @state_cb: callback function to notify pmic glink state in the event of
|
||||
* a subsystem restart (SSR) or a protection domain restart (PDR)
|
||||
*/
|
||||
struct pmic_glink_client_data {
|
||||
const char *name;
|
||||
u32 id;
|
||||
void *priv;
|
||||
int (*callback)(void *priv, void *data, size_t len);
|
||||
int (*msg_cb)(void *priv, void *data, size_t len);
|
||||
void (*state_cb)(void *priv, enum pmic_glink_state state);
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user