diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index b5874cd35e3a..e02364f5fafe 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -92,5 +92,6 @@ obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o obj-$(CONFIG_CHARGER_BD70528) += bd70528-charger.o obj-$(CONFIG_CHARGER_WILCO) += wilco-charger.o -obj-$(CONFIG_QTI_BATTERY_CHARGER) += qti_battery_charger.o +obj-$(CONFIG_QTI_BATTERY_CHARGER) += qti_battery_charger_main.o +qti_battery_charger_main-y += qti_battery_charger.o qti_typec_class.o obj-$(CONFIG_QCOM_POWER_SUPPLY) += qcom/ diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index ab0dbd6300be..9221a335b4cd 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -20,6 +20,7 @@ #include #include #include +#include "qti_typec_class.h" #define MSG_OWNER_BC 32778 #define MSG_TYPE_REQ_RESP 1 @@ -223,6 +224,7 @@ struct battery_chg_dev { struct device *dev; struct class battery_class; struct pmic_glink_client *client; + struct typec_role_class *typec_class; struct mutex rw_lock; struct completion ack; struct completion fw_buf_ack; @@ -666,12 +668,21 @@ static void battery_chg_update_uusb_type(struct battery_chg_dev *bcdev, /* Device mode connect notification */ extcon_set_state_sync(bcdev->extcon, EXTCON_USB, 1); bcdev->usb_prev_mode = EXTCON_USB; + rc = qti_typec_partner_register(bcdev->typec_class, + TYPEC_DEVICE); + if (rc < 0) + pr_err("Failed to register typec partner rc=%d\n", + rc); } break; case POWER_SUPPLY_SCOPE_SYSTEM: /* Host mode connect notification */ extcon_set_state_sync(bcdev->extcon, EXTCON_USB_HOST, 1); bcdev->usb_prev_mode = EXTCON_USB_HOST; + rc = qti_typec_partner_register(bcdev->typec_class, TYPEC_HOST); + if (rc < 0) + pr_err("Failed to register typec partner rc=%d\n", + rc); break; default: if (bcdev->usb_prev_mode == EXTCON_USB || @@ -680,6 +691,7 @@ static void battery_chg_update_uusb_type(struct battery_chg_dev *bcdev, extcon_set_state_sync(bcdev->extcon, bcdev->usb_prev_mode, 0); bcdev->usb_prev_mode = EXTCON_NONE; + qti_typec_partner_unregister(bcdev->typec_class); } break; } @@ -2059,6 +2071,15 @@ static int battery_chg_probe(struct platform_device *pdev) if (rc < 0) dev_warn(dev, "Failed to register extcon rc=%d\n", rc); + if (bcdev->connector_type == USB_CONNECTOR_TYPE_MICRO_USB) { + bcdev->typec_class = qti_typec_class_init(bcdev->dev); + if (IS_ERR_OR_NULL(bcdev->typec_class)) { + dev_err(dev, "Failed to init typec class err=%d\n", + PTR_ERR(bcdev->typec_class)); + return PTR_ERR(bcdev->typec_class); + } + } + schedule_work(&bcdev->usb_type_work); return 0; @@ -2079,6 +2100,7 @@ static int battery_chg_remove(struct platform_device *pdev) debugfs_remove_recursive(bcdev->debugfs_dir); class_unregister(&bcdev->battery_class); unregister_reboot_notifier(&bcdev->reboot_notifier); + qti_typec_class_deinit(bcdev->typec_class); rc = pmic_glink_unregister_client(bcdev->client); if (rc < 0) { pr_err("Error unregistering from pmic_glink, rc=%d\n", rc); diff --git a/drivers/power/supply/qti_typec_class.c b/drivers/power/supply/qti_typec_class.c new file mode 100644 index 000000000000..e38b04280482 --- /dev/null +++ b/drivers/power/supply/qti_typec_class.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#include +#include + +#include "qti_typec_class.h" + +int qti_typec_partner_register(struct typec_role_class *chip, int mode) +{ + + if (!chip || !chip->typec_port) + return -ENODEV; + + if (!chip->typec_partner) { + chip->typec_partner = typec_register_partner(chip->typec_port, + &chip->typec_partner_desc); + if (IS_ERR_OR_NULL(chip->typec_partner)) + return PTR_ERR(chip->typec_partner); + } + + if (mode == TYPEC_DEVICE) { + typec_set_data_role(chip->typec_port, TYPEC_DEVICE); + typec_set_pwr_role(chip->typec_port, TYPEC_SINK); + } else { + typec_set_data_role(chip->typec_port, TYPEC_HOST); + typec_set_pwr_role(chip->typec_port, TYPEC_SOURCE); + } + + return 0; +} + +void qti_typec_partner_unregister(struct typec_role_class *chip) +{ + if (!chip || !chip->typec_port) + return; + + if (chip->typec_partner) { + typec_unregister_partner(chip->typec_partner); + chip->typec_partner = NULL; + } +} + +struct typec_role_class *qti_typec_class_init(struct device *dev) +{ + struct typec_role_class *chip; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return ERR_PTR(-ENOMEM); + + chip->typec_caps.type = TYPEC_PORT_DRP; + chip->typec_caps.data = TYPEC_PORT_DRD; + chip->typec_caps.revision = 0x0130; + chip->typec_partner_desc.usb_pd = false; + chip->typec_partner_desc.accessory = TYPEC_ACCESSORY_NONE; + + chip->typec_port = typec_register_port(dev, &chip->typec_caps); + if (IS_ERR_OR_NULL(chip->typec_port)) + return ERR_PTR(-ENODEV); + + return chip; +} + +void qti_typec_class_deinit(struct typec_role_class *chip) +{ + if (!chip || !chip->typec_port) + return; + + qti_typec_partner_unregister(chip); + typec_unregister_port(chip->typec_port); + chip->typec_port = NULL; +} diff --git a/drivers/power/supply/qti_typec_class.h b/drivers/power/supply/qti_typec_class.h new file mode 100644 index 000000000000..5caf7f973bd7 --- /dev/null +++ b/drivers/power/supply/qti_typec_class.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2021 The Linux Foundation. All rights reserved. + */ +#ifndef __QTI_TYPEC_CLASS_H +#define __QTI_TYPEC_CLASS_H + +#include + +struct typec_role_class { + struct typec_port *typec_port; + struct typec_capability typec_caps; + struct typec_partner *typec_partner; + struct typec_partner_desc typec_partner_desc; +}; + +int qti_typec_partner_register(struct typec_role_class *chip, int mode); +void qti_typec_partner_unregister(struct typec_role_class *chip); +struct typec_role_class *qti_typec_class_init(struct device *dev); +void qti_typec_class_deinit(struct typec_role_class *chip); +#endif /* __QTI_TYPEC_CLASS_H */