Loading drivers/soc/qcom/fsa4480-i2c.c +33 −64 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/power_supply.h> #include <linux/regmap.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/usb/typec.h> #include <linux/usb/ucsi_glink.h> #include <linux/soc/qcom/fsa4480-i2c.h> #define FSA4480_I2C_NAME "fsa4480-driver" Loading @@ -29,8 +30,7 @@ struct fsa4480_priv { struct regmap *regmap; struct device *dev; struct power_supply *usb_psy; struct notifier_block psy_nb; struct notifier_block ucsi_nb; atomic_t usbc_mode; struct work_struct usbc_analog_work; struct blocking_notifier_head fsa4480_notifier; Loading Loading @@ -79,11 +79,10 @@ static void fsa4480_usbc_update_settings(struct fsa4480_priv *fsa_priv, static int fsa4480_usbc_event_changed(struct notifier_block *nb, unsigned long evt, void *ptr) { int ret; union power_supply_propval mode; struct fsa4480_priv *fsa_priv = container_of(nb, struct fsa4480_priv, psy_nb); container_of(nb, struct fsa4480_priv, ucsi_nb); struct device *dev; enum typec_accessory acc = ((struct ucsi_glink_constat_info *)ptr)->acc; if (!fsa_priv) return -EINVAL; Loading @@ -92,28 +91,16 @@ static int fsa4480_usbc_event_changed(struct notifier_block *nb, if (!dev) return -EINVAL; if ((struct power_supply *)ptr != fsa_priv->usb_psy || evt != PSY_EVENT_PROP_CHANGED) return 0; ret = power_supply_get_property(fsa_priv->usb_psy, POWER_SUPPLY_PROP_TYPEC_MODE, &mode); if (ret) { dev_err(dev, "%s: Unable to read USB TYPEC_MODE: %d\n", __func__, ret); return ret; } dev_dbg(dev, "%s: USB change event received, supply mode %d, usbc mode %ld, expected %d\n", __func__, acc, fsa_priv->usbc_mode.counter, TYPEC_ACCESSORY_AUDIO); dev_dbg(dev, "%s: USB change event received, supply mode %d, usbc mode %d, expected %d\n", __func__, mode.intval, fsa_priv->usbc_mode.counter, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER); switch (mode.intval) { case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: case POWER_SUPPLY_TYPEC_NONE: if (atomic_read(&(fsa_priv->usbc_mode)) == mode.intval) switch (acc) { case TYPEC_ACCESSORY_AUDIO: case TYPEC_ACCESSORY_NONE: if (atomic_read(&(fsa_priv->usbc_mode)) == acc) break; /* filter notifications received before */ atomic_set(&(fsa_priv->usbc_mode), mode.intval); atomic_set(&(fsa_priv->usbc_mode), acc); dev_dbg(dev, "%s: queueing usbc_analog_work\n", __func__); Loading @@ -123,13 +110,14 @@ static int fsa4480_usbc_event_changed(struct notifier_block *nb, default: break; } return ret; return 0; } static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv) { int rc = 0; union power_supply_propval mode; int mode; struct device *dev; if (!fsa_priv) Loading @@ -140,30 +128,25 @@ static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv) mutex_lock(&fsa_priv->notification_lock); /* get latest mode again within locked context */ rc = power_supply_get_property(fsa_priv->usb_psy, POWER_SUPPLY_PROP_TYPEC_MODE, &mode); if (rc) { dev_err(dev, "%s: Unable to read USB TYPEC_MODE: %d\n", __func__, rc); goto done; } mode = atomic_read(&(fsa_priv->usbc_mode)); dev_dbg(dev, "%s: setting GPIOs active = %d\n", __func__, mode.intval != POWER_SUPPLY_TYPEC_NONE); __func__, mode != TYPEC_ACCESSORY_NONE); switch (mode.intval) { switch (mode) { /* add all modes FSA should notify for in here */ case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: case TYPEC_ACCESSORY_AUDIO: /* activate switches */ fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F); /* notify call chain on event */ blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier, mode.intval, NULL); mode, NULL); break; case POWER_SUPPLY_TYPEC_NONE: case TYPEC_ACCESSORY_NONE: /* notify call chain on event */ blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier, POWER_SUPPLY_TYPEC_NONE, NULL); TYPEC_ACCESSORY_NONE, NULL); /* deactivate switches */ fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); Loading @@ -173,7 +156,6 @@ static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv) break; } done: mutex_unlock(&fsa_priv->notification_lock); return rc; } Loading Loading @@ -344,36 +326,27 @@ static int fsa4480_probe(struct i2c_client *i2c, fsa_priv->dev = &i2c->dev; fsa_priv->usb_psy = power_supply_get_by_name("usb"); if (!fsa_priv->usb_psy) { rc = -EPROBE_DEFER; dev_dbg(fsa_priv->dev, "%s: could not get USB psy info: %d\n", __func__, rc); goto err_data; } fsa_priv->regmap = devm_regmap_init_i2c(i2c, &fsa4480_regmap_config); if (IS_ERR_OR_NULL(fsa_priv->regmap)) { dev_err(fsa_priv->dev, "%s: Failed to initialize regmap: %d\n", __func__, rc); if (!fsa_priv->regmap) { rc = -EINVAL; goto err_supply; goto err_data; } rc = PTR_ERR(fsa_priv->regmap); goto err_supply; goto err_data; } fsa4480_update_reg_defaults(fsa_priv->regmap); fsa_priv->psy_nb.notifier_call = fsa4480_usbc_event_changed; fsa_priv->psy_nb.priority = 0; rc = power_supply_reg_notifier(&fsa_priv->psy_nb); fsa_priv->ucsi_nb.notifier_call = fsa4480_usbc_event_changed; fsa_priv->ucsi_nb.priority = 0; rc = register_ucsi_glink_notifier(&fsa_priv->ucsi_nb); if (rc) { dev_err(fsa_priv->dev, "%s: power supply reg failed: %d\n", dev_err(fsa_priv->dev, "%s: ucsi glink notifier registration failed: %d\n", __func__, rc); goto err_supply; goto err_data; } mutex_init(&fsa_priv->notification_lock); Loading @@ -389,8 +362,6 @@ static int fsa4480_probe(struct i2c_client *i2c, return 0; err_supply: power_supply_put(fsa_priv->usb_psy); err_data: devm_kfree(&i2c->dev, fsa_priv); return rc; Loading @@ -404,12 +375,10 @@ static int fsa4480_remove(struct i2c_client *i2c) if (!fsa_priv) return -EINVAL; unregister_ucsi_glink_notifier(&fsa_priv->ucsi_nb); fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); cancel_work_sync(&fsa_priv->usbc_analog_work); pm_relax(fsa_priv->dev); /* deregister from PMI */ power_supply_unreg_notifier(&fsa_priv->psy_nb); power_supply_put(fsa_priv->usb_psy); mutex_destroy(&fsa_priv->notification_lock); dev_set_drvdata(&i2c->dev, NULL); Loading drivers/usb/typec/ucsi/ucsi_glink.c +74 −1 Original line number Diff line number Diff line // 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. */ #define pr_fmt(fmt) "UCSI: %s: " fmt, __func__ Loading @@ -8,9 +8,12 @@ #include <linux/device.h> #include <linux/ipc_logging.h> #include <linux/module.h> #include <linux/notifier.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/soc/qcom/pmic_glink.h> #include <linux/usb/typec.h> #include <linux/usb/ucsi_glink.h> #include "ucsi.h" Loading Loading @@ -74,12 +77,29 @@ struct ucsi_dev { struct completion sync_write_ack; struct mutex read_lock; struct mutex write_lock; struct mutex notify_lock; struct ucsi_read_buf_resp_msg rx_buf; unsigned long flags; atomic_t rx_valid; unsigned long cmd_requested_flags; struct ucsi_glink_constat_info constat_info; struct work_struct notify_work; }; static void *ucsi_ipc_log; static RAW_NOTIFIER_HEAD(ucsi_glink_notifier); int register_ucsi_glink_notifier(struct notifier_block *nb) { return raw_notifier_chain_register(&ucsi_glink_notifier, nb); } EXPORT_SYMBOL(register_ucsi_glink_notifier); int unregister_ucsi_glink_notifier(struct notifier_block *nb) { return raw_notifier_chain_unregister(&ucsi_glink_notifier, nb); } EXPORT_SYMBOL(unregister_ucsi_glink_notifier); static char *offset_to_name(unsigned int offset) { Loading Loading @@ -237,6 +257,7 @@ static bool validate_ucsi_msg(unsigned int offset, size_t len) return true; } #define CONN_STAT_REQD 1 static int ucsi_qti_glink_write(struct ucsi_dev *udev, unsigned int offset, const void *val, size_t val_len, bool sync) { Loading Loading @@ -291,6 +312,13 @@ static int ucsi_qti_glink_write(struct ucsi_dev *udev, unsigned int offset, ucsi_log(sync ? "sync_write:" : "async_write:", offset, (u8 *)val, val_len); if (((u8 *)val)[0] == UCSI_GET_CONNECTOR_STATUS) { mutex_lock(&udev->notify_lock); set_bit(CONN_STAT_REQD, &udev->cmd_requested_flags); mutex_unlock(&udev->notify_lock); } out: if (sync) clear_bit(CMD_PENDING, &udev->flags); Loading @@ -316,6 +344,47 @@ static int ucsi_qti_sync_write(struct ucsi *ucsi, unsigned int offset, return ucsi_qti_glink_write(udev, offset, val, val_len, true); } static void ucsi_qti_notify_work(struct work_struct *work) { struct ucsi_dev *udev = container_of(work, struct ucsi_dev, notify_work); raw_notifier_call_chain(&ucsi_glink_notifier, 0, &udev->constat_info); mutex_lock(&udev->notify_lock); clear_bit(CONN_STAT_REQD, &udev->cmd_requested_flags); mutex_unlock(&udev->notify_lock); } static void ucsi_qti_notify(struct ucsi_dev *udev, unsigned int offset, struct ucsi_connector_status *status) { u8 conn_partner_type; bool cmd_requested; mutex_lock(&udev->notify_lock); cmd_requested = test_bit(CONN_STAT_REQD, &udev->cmd_requested_flags); mutex_unlock(&udev->notify_lock); if (cmd_requested && offset == UCSI_MESSAGE_IN) { cancel_work_sync(&udev->notify_work); conn_partner_type = UCSI_CONSTAT_PARTNER_TYPE(status->flags); switch (conn_partner_type) { case UCSI_CONSTAT_PARTNER_TYPE_AUDIO: udev->constat_info.acc = TYPEC_ACCESSORY_AUDIO; break; case UCSI_CONSTAT_PARTNER_TYPE_DEBUG: udev->constat_info.acc = TYPEC_ACCESSORY_DEBUG; break; default: udev->constat_info.acc = TYPEC_ACCESSORY_NONE; break; } schedule_work(&udev->notify_work); } } static int ucsi_qti_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len) { Loading Loading @@ -359,6 +428,7 @@ static int ucsi_qti_read(struct ucsi *ucsi, unsigned int offset, memcpy((u8 *)val, &udev->rx_buf.buf[offset], val_len); atomic_set(&udev->rx_valid, 0); ucsi_log("read:", offset, (u8 *)val, val_len); ucsi_qti_notify(udev, offset, val); out: mutex_unlock(&udev->read_lock); Loading @@ -383,8 +453,10 @@ static int ucsi_probe(struct platform_device *pdev) if (!udev) return -ENOMEM; INIT_WORK(&udev->notify_work, ucsi_qti_notify_work); mutex_init(&udev->read_lock); mutex_init(&udev->write_lock); mutex_init(&udev->notify_lock); init_completion(&udev->read_ack); init_completion(&udev->write_ack); init_completion(&udev->sync_write_ack); Loading Loading @@ -442,6 +514,7 @@ static int ucsi_remove(struct platform_device *pdev) struct ucsi_dev *udev = dev_get_drvdata(dev); int rc; cancel_work_sync(&udev->notify_work); ucsi_unregister(udev->ucsi); ucsi_destroy(udev->ucsi); Loading include/linux/usb/ucsi_glink.h 0 → 100644 +31 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #ifndef __UCSI_GLINK_H__ #define __UCSI_GLINK_H__ struct ucsi_glink_constat_info { enum typec_accessory acc; }; #if IS_ENABLED(CONFIG_UCSI_QTI_GLINK) int register_ucsi_glink_notifier(struct notifier_block *nb); int unregister_ucsi_glink_notifier(struct notifier_block *nb); #else static inline int register_ucsi_glink_notifier(struct notifier_block *nb) { return -ENODEV; } static inline int unregister_ucsi_glink_notifier(struct notifier_block *nb); { return -ENODEV; } #endif #endif Loading
drivers/soc/qcom/fsa4480-i2c.c +33 −64 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/power_supply.h> #include <linux/regmap.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <linux/usb/typec.h> #include <linux/usb/ucsi_glink.h> #include <linux/soc/qcom/fsa4480-i2c.h> #define FSA4480_I2C_NAME "fsa4480-driver" Loading @@ -29,8 +30,7 @@ struct fsa4480_priv { struct regmap *regmap; struct device *dev; struct power_supply *usb_psy; struct notifier_block psy_nb; struct notifier_block ucsi_nb; atomic_t usbc_mode; struct work_struct usbc_analog_work; struct blocking_notifier_head fsa4480_notifier; Loading Loading @@ -79,11 +79,10 @@ static void fsa4480_usbc_update_settings(struct fsa4480_priv *fsa_priv, static int fsa4480_usbc_event_changed(struct notifier_block *nb, unsigned long evt, void *ptr) { int ret; union power_supply_propval mode; struct fsa4480_priv *fsa_priv = container_of(nb, struct fsa4480_priv, psy_nb); container_of(nb, struct fsa4480_priv, ucsi_nb); struct device *dev; enum typec_accessory acc = ((struct ucsi_glink_constat_info *)ptr)->acc; if (!fsa_priv) return -EINVAL; Loading @@ -92,28 +91,16 @@ static int fsa4480_usbc_event_changed(struct notifier_block *nb, if (!dev) return -EINVAL; if ((struct power_supply *)ptr != fsa_priv->usb_psy || evt != PSY_EVENT_PROP_CHANGED) return 0; ret = power_supply_get_property(fsa_priv->usb_psy, POWER_SUPPLY_PROP_TYPEC_MODE, &mode); if (ret) { dev_err(dev, "%s: Unable to read USB TYPEC_MODE: %d\n", __func__, ret); return ret; } dev_dbg(dev, "%s: USB change event received, supply mode %d, usbc mode %ld, expected %d\n", __func__, acc, fsa_priv->usbc_mode.counter, TYPEC_ACCESSORY_AUDIO); dev_dbg(dev, "%s: USB change event received, supply mode %d, usbc mode %d, expected %d\n", __func__, mode.intval, fsa_priv->usbc_mode.counter, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER); switch (mode.intval) { case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: case POWER_SUPPLY_TYPEC_NONE: if (atomic_read(&(fsa_priv->usbc_mode)) == mode.intval) switch (acc) { case TYPEC_ACCESSORY_AUDIO: case TYPEC_ACCESSORY_NONE: if (atomic_read(&(fsa_priv->usbc_mode)) == acc) break; /* filter notifications received before */ atomic_set(&(fsa_priv->usbc_mode), mode.intval); atomic_set(&(fsa_priv->usbc_mode), acc); dev_dbg(dev, "%s: queueing usbc_analog_work\n", __func__); Loading @@ -123,13 +110,14 @@ static int fsa4480_usbc_event_changed(struct notifier_block *nb, default: break; } return ret; return 0; } static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv) { int rc = 0; union power_supply_propval mode; int mode; struct device *dev; if (!fsa_priv) Loading @@ -140,30 +128,25 @@ static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv) mutex_lock(&fsa_priv->notification_lock); /* get latest mode again within locked context */ rc = power_supply_get_property(fsa_priv->usb_psy, POWER_SUPPLY_PROP_TYPEC_MODE, &mode); if (rc) { dev_err(dev, "%s: Unable to read USB TYPEC_MODE: %d\n", __func__, rc); goto done; } mode = atomic_read(&(fsa_priv->usbc_mode)); dev_dbg(dev, "%s: setting GPIOs active = %d\n", __func__, mode.intval != POWER_SUPPLY_TYPEC_NONE); __func__, mode != TYPEC_ACCESSORY_NONE); switch (mode.intval) { switch (mode) { /* add all modes FSA should notify for in here */ case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: case TYPEC_ACCESSORY_AUDIO: /* activate switches */ fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F); /* notify call chain on event */ blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier, mode.intval, NULL); mode, NULL); break; case POWER_SUPPLY_TYPEC_NONE: case TYPEC_ACCESSORY_NONE: /* notify call chain on event */ blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier, POWER_SUPPLY_TYPEC_NONE, NULL); TYPEC_ACCESSORY_NONE, NULL); /* deactivate switches */ fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); Loading @@ -173,7 +156,6 @@ static int fsa4480_usbc_analog_setup_switches(struct fsa4480_priv *fsa_priv) break; } done: mutex_unlock(&fsa_priv->notification_lock); return rc; } Loading Loading @@ -344,36 +326,27 @@ static int fsa4480_probe(struct i2c_client *i2c, fsa_priv->dev = &i2c->dev; fsa_priv->usb_psy = power_supply_get_by_name("usb"); if (!fsa_priv->usb_psy) { rc = -EPROBE_DEFER; dev_dbg(fsa_priv->dev, "%s: could not get USB psy info: %d\n", __func__, rc); goto err_data; } fsa_priv->regmap = devm_regmap_init_i2c(i2c, &fsa4480_regmap_config); if (IS_ERR_OR_NULL(fsa_priv->regmap)) { dev_err(fsa_priv->dev, "%s: Failed to initialize regmap: %d\n", __func__, rc); if (!fsa_priv->regmap) { rc = -EINVAL; goto err_supply; goto err_data; } rc = PTR_ERR(fsa_priv->regmap); goto err_supply; goto err_data; } fsa4480_update_reg_defaults(fsa_priv->regmap); fsa_priv->psy_nb.notifier_call = fsa4480_usbc_event_changed; fsa_priv->psy_nb.priority = 0; rc = power_supply_reg_notifier(&fsa_priv->psy_nb); fsa_priv->ucsi_nb.notifier_call = fsa4480_usbc_event_changed; fsa_priv->ucsi_nb.priority = 0; rc = register_ucsi_glink_notifier(&fsa_priv->ucsi_nb); if (rc) { dev_err(fsa_priv->dev, "%s: power supply reg failed: %d\n", dev_err(fsa_priv->dev, "%s: ucsi glink notifier registration failed: %d\n", __func__, rc); goto err_supply; goto err_data; } mutex_init(&fsa_priv->notification_lock); Loading @@ -389,8 +362,6 @@ static int fsa4480_probe(struct i2c_client *i2c, return 0; err_supply: power_supply_put(fsa_priv->usb_psy); err_data: devm_kfree(&i2c->dev, fsa_priv); return rc; Loading @@ -404,12 +375,10 @@ static int fsa4480_remove(struct i2c_client *i2c) if (!fsa_priv) return -EINVAL; unregister_ucsi_glink_notifier(&fsa_priv->ucsi_nb); fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); cancel_work_sync(&fsa_priv->usbc_analog_work); pm_relax(fsa_priv->dev); /* deregister from PMI */ power_supply_unreg_notifier(&fsa_priv->psy_nb); power_supply_put(fsa_priv->usb_psy); mutex_destroy(&fsa_priv->notification_lock); dev_set_drvdata(&i2c->dev, NULL); Loading
drivers/usb/typec/ucsi/ucsi_glink.c +74 −1 Original line number Diff line number Diff line // 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. */ #define pr_fmt(fmt) "UCSI: %s: " fmt, __func__ Loading @@ -8,9 +8,12 @@ #include <linux/device.h> #include <linux/ipc_logging.h> #include <linux/module.h> #include <linux/notifier.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/soc/qcom/pmic_glink.h> #include <linux/usb/typec.h> #include <linux/usb/ucsi_glink.h> #include "ucsi.h" Loading Loading @@ -74,12 +77,29 @@ struct ucsi_dev { struct completion sync_write_ack; struct mutex read_lock; struct mutex write_lock; struct mutex notify_lock; struct ucsi_read_buf_resp_msg rx_buf; unsigned long flags; atomic_t rx_valid; unsigned long cmd_requested_flags; struct ucsi_glink_constat_info constat_info; struct work_struct notify_work; }; static void *ucsi_ipc_log; static RAW_NOTIFIER_HEAD(ucsi_glink_notifier); int register_ucsi_glink_notifier(struct notifier_block *nb) { return raw_notifier_chain_register(&ucsi_glink_notifier, nb); } EXPORT_SYMBOL(register_ucsi_glink_notifier); int unregister_ucsi_glink_notifier(struct notifier_block *nb) { return raw_notifier_chain_unregister(&ucsi_glink_notifier, nb); } EXPORT_SYMBOL(unregister_ucsi_glink_notifier); static char *offset_to_name(unsigned int offset) { Loading Loading @@ -237,6 +257,7 @@ static bool validate_ucsi_msg(unsigned int offset, size_t len) return true; } #define CONN_STAT_REQD 1 static int ucsi_qti_glink_write(struct ucsi_dev *udev, unsigned int offset, const void *val, size_t val_len, bool sync) { Loading Loading @@ -291,6 +312,13 @@ static int ucsi_qti_glink_write(struct ucsi_dev *udev, unsigned int offset, ucsi_log(sync ? "sync_write:" : "async_write:", offset, (u8 *)val, val_len); if (((u8 *)val)[0] == UCSI_GET_CONNECTOR_STATUS) { mutex_lock(&udev->notify_lock); set_bit(CONN_STAT_REQD, &udev->cmd_requested_flags); mutex_unlock(&udev->notify_lock); } out: if (sync) clear_bit(CMD_PENDING, &udev->flags); Loading @@ -316,6 +344,47 @@ static int ucsi_qti_sync_write(struct ucsi *ucsi, unsigned int offset, return ucsi_qti_glink_write(udev, offset, val, val_len, true); } static void ucsi_qti_notify_work(struct work_struct *work) { struct ucsi_dev *udev = container_of(work, struct ucsi_dev, notify_work); raw_notifier_call_chain(&ucsi_glink_notifier, 0, &udev->constat_info); mutex_lock(&udev->notify_lock); clear_bit(CONN_STAT_REQD, &udev->cmd_requested_flags); mutex_unlock(&udev->notify_lock); } static void ucsi_qti_notify(struct ucsi_dev *udev, unsigned int offset, struct ucsi_connector_status *status) { u8 conn_partner_type; bool cmd_requested; mutex_lock(&udev->notify_lock); cmd_requested = test_bit(CONN_STAT_REQD, &udev->cmd_requested_flags); mutex_unlock(&udev->notify_lock); if (cmd_requested && offset == UCSI_MESSAGE_IN) { cancel_work_sync(&udev->notify_work); conn_partner_type = UCSI_CONSTAT_PARTNER_TYPE(status->flags); switch (conn_partner_type) { case UCSI_CONSTAT_PARTNER_TYPE_AUDIO: udev->constat_info.acc = TYPEC_ACCESSORY_AUDIO; break; case UCSI_CONSTAT_PARTNER_TYPE_DEBUG: udev->constat_info.acc = TYPEC_ACCESSORY_DEBUG; break; default: udev->constat_info.acc = TYPEC_ACCESSORY_NONE; break; } schedule_work(&udev->notify_work); } } static int ucsi_qti_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len) { Loading Loading @@ -359,6 +428,7 @@ static int ucsi_qti_read(struct ucsi *ucsi, unsigned int offset, memcpy((u8 *)val, &udev->rx_buf.buf[offset], val_len); atomic_set(&udev->rx_valid, 0); ucsi_log("read:", offset, (u8 *)val, val_len); ucsi_qti_notify(udev, offset, val); out: mutex_unlock(&udev->read_lock); Loading @@ -383,8 +453,10 @@ static int ucsi_probe(struct platform_device *pdev) if (!udev) return -ENOMEM; INIT_WORK(&udev->notify_work, ucsi_qti_notify_work); mutex_init(&udev->read_lock); mutex_init(&udev->write_lock); mutex_init(&udev->notify_lock); init_completion(&udev->read_ack); init_completion(&udev->write_ack); init_completion(&udev->sync_write_ack); Loading Loading @@ -442,6 +514,7 @@ static int ucsi_remove(struct platform_device *pdev) struct ucsi_dev *udev = dev_get_drvdata(dev); int rc; cancel_work_sync(&udev->notify_work); ucsi_unregister(udev->ucsi); ucsi_destroy(udev->ucsi); Loading
include/linux/usb/ucsi_glink.h 0 → 100644 +31 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #ifndef __UCSI_GLINK_H__ #define __UCSI_GLINK_H__ struct ucsi_glink_constat_info { enum typec_accessory acc; }; #if IS_ENABLED(CONFIG_UCSI_QTI_GLINK) int register_ucsi_glink_notifier(struct notifier_block *nb); int unregister_ucsi_glink_notifier(struct notifier_block *nb); #else static inline int register_ucsi_glink_notifier(struct notifier_block *nb) { return -ENODEV; } static inline int unregister_ucsi_glink_notifier(struct notifier_block *nb); { return -ENODEV; } #endif #endif