diff options
Diffstat (limited to 'drivers/usb/typec/tcpm/qcom')
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/Makefile | 3 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c | 262 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h | 27 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c | 170 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.h | 94 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c | 80 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c | 290 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.h | 172 |
8 files changed, 573 insertions, 525 deletions
diff --git a/drivers/usb/typec/tcpm/qcom/Makefile b/drivers/usb/typec/tcpm/qcom/Makefile index dc1e8832e1..cc23042b94 100644 --- a/drivers/usb/typec/tcpm/qcom/Makefile +++ b/drivers/usb/typec/tcpm/qcom/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_TYPEC_QCOM_PMIC) += qcom_pmic_tcpm.o qcom_pmic_tcpm-y += qcom_pmic_typec.o \ qcom_pmic_typec_port.o \ - qcom_pmic_typec_pdphy.o + qcom_pmic_typec_pdphy.o \ + qcom_pmic_typec_pdphy_stub.o \ diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c index 1a2b4bddaa..d3958c061a 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c @@ -20,130 +20,15 @@ #include <drm/bridge/aux-bridge.h> +#include "qcom_pmic_typec.h" #include "qcom_pmic_typec_pdphy.h" #include "qcom_pmic_typec_port.h" struct pmic_typec_resources { - struct pmic_typec_pdphy_resources *pdphy_res; - struct pmic_typec_port_resources *port_res; + const struct pmic_typec_pdphy_resources *pdphy_res; + const struct pmic_typec_port_resources *port_res; }; -struct pmic_typec { - struct device *dev; - struct tcpm_port *tcpm_port; - struct tcpc_dev tcpc; - struct pmic_typec_pdphy *pmic_typec_pdphy; - struct pmic_typec_port *pmic_typec_port; - bool vbus_enabled; - struct mutex lock; /* VBUS state serialization */ -}; - -#define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc) - -static int qcom_pmic_typec_get_vbus(struct tcpc_dev *tcpc) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - int ret; - - mutex_lock(&tcpm->lock); - ret = tcpm->vbus_enabled || qcom_pmic_typec_port_get_vbus(tcpm->pmic_typec_port); - mutex_unlock(&tcpm->lock); - - return ret; -} - -static int qcom_pmic_typec_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - int ret = 0; - - mutex_lock(&tcpm->lock); - if (tcpm->vbus_enabled == on) - goto done; - - ret = qcom_pmic_typec_port_set_vbus(tcpm->pmic_typec_port, on); - if (ret) - goto done; - - tcpm->vbus_enabled = on; - tcpm_vbus_change(tcpm->tcpm_port); - -done: - dev_dbg(tcpm->dev, "set_vbus set: %d result %d\n", on, ret); - mutex_unlock(&tcpm->lock); - - return ret; -} - -static int qcom_pmic_typec_set_vconn(struct tcpc_dev *tcpc, bool on) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - - return qcom_pmic_typec_port_set_vconn(tcpm->pmic_typec_port, on); -} - -static int qcom_pmic_typec_get_cc(struct tcpc_dev *tcpc, - enum typec_cc_status *cc1, - enum typec_cc_status *cc2) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - - return qcom_pmic_typec_port_get_cc(tcpm->pmic_typec_port, cc1, cc2); -} - -static int qcom_pmic_typec_set_cc(struct tcpc_dev *tcpc, - enum typec_cc_status cc) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - - return qcom_pmic_typec_port_set_cc(tcpm->pmic_typec_port, cc); -} - -static int qcom_pmic_typec_set_polarity(struct tcpc_dev *tcpc, - enum typec_cc_polarity pol) -{ - /* Polarity is set separately by phy-qcom-qmp.c */ - return 0; -} - -static int qcom_pmic_typec_start_toggling(struct tcpc_dev *tcpc, - enum typec_port_type port_type, - enum typec_cc_status cc) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - - return qcom_pmic_typec_port_start_toggling(tcpm->pmic_typec_port, - port_type, cc); -} - -static int qcom_pmic_typec_set_roles(struct tcpc_dev *tcpc, bool attached, - enum typec_role power_role, - enum typec_data_role data_role) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - - return qcom_pmic_typec_pdphy_set_roles(tcpm->pmic_typec_pdphy, - data_role, power_role); -} - -static int qcom_pmic_typec_set_pd_rx(struct tcpc_dev *tcpc, bool on) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - - return qcom_pmic_typec_pdphy_set_pd_rx(tcpm->pmic_typec_pdphy, on); -} - -static int qcom_pmic_typec_pd_transmit(struct tcpc_dev *tcpc, - enum tcpm_transmit_type type, - const struct pd_message *msg, - unsigned int negotiated_rev) -{ - struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); - - return qcom_pmic_typec_pdphy_pd_transmit(tcpm->pmic_typec_pdphy, type, - msg, negotiated_rev); -} - static int qcom_pmic_typec_init(struct tcpc_dev *tcpc) { return 0; @@ -157,7 +42,7 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) const struct pmic_typec_resources *res; struct regmap *regmap; struct device *bridge_dev; - u32 base[2]; + u32 base; int ret; res = of_device_get_match_data(dev); @@ -170,16 +55,6 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) tcpm->dev = dev; tcpm->tcpc.init = qcom_pmic_typec_init; - tcpm->tcpc.get_vbus = qcom_pmic_typec_get_vbus; - tcpm->tcpc.set_vbus = qcom_pmic_typec_set_vbus; - tcpm->tcpc.set_cc = qcom_pmic_typec_set_cc; - tcpm->tcpc.get_cc = qcom_pmic_typec_get_cc; - tcpm->tcpc.set_polarity = qcom_pmic_typec_set_polarity; - tcpm->tcpc.set_vconn = qcom_pmic_typec_set_vconn; - tcpm->tcpc.start_toggling = qcom_pmic_typec_start_toggling; - tcpm->tcpc.set_pd_rx = qcom_pmic_typec_set_pd_rx; - tcpm->tcpc.set_roles = qcom_pmic_typec_set_roles; - tcpm->tcpc.pd_transmit = qcom_pmic_typec_pd_transmit; regmap = dev_get_regmap(dev->parent, NULL); if (!regmap) { @@ -187,29 +62,30 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) return -ENODEV; } - ret = of_property_read_u32_array(np, "reg", base, 2); + ret = of_property_read_u32_index(np, "reg", 0, &base); if (ret) return ret; - tcpm->pmic_typec_port = qcom_pmic_typec_port_alloc(dev); - if (IS_ERR(tcpm->pmic_typec_port)) - return PTR_ERR(tcpm->pmic_typec_port); - - tcpm->pmic_typec_pdphy = qcom_pmic_typec_pdphy_alloc(dev); - if (IS_ERR(tcpm->pmic_typec_pdphy)) - return PTR_ERR(tcpm->pmic_typec_pdphy); - - ret = qcom_pmic_typec_port_probe(pdev, tcpm->pmic_typec_port, - res->port_res, regmap, base[0]); + ret = qcom_pmic_typec_port_probe(pdev, tcpm, + res->port_res, regmap, base); if (ret) return ret; - ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm->pmic_typec_pdphy, - res->pdphy_res, regmap, base[1]); - if (ret) - return ret; + if (res->pdphy_res) { + ret = of_property_read_u32_index(np, "reg", 1, &base); + if (ret) + return ret; + + ret = qcom_pmic_typec_pdphy_probe(pdev, tcpm, + res->pdphy_res, regmap, base); + if (ret) + return ret; + } else { + ret = qcom_pmic_typec_pdphy_stub_probe(pdev, tcpm); + if (ret) + return ret; + } - mutex_init(&tcpm->lock); platform_set_drvdata(pdev, tcpm); tcpm->tcpc.fwnode = device_get_named_child_node(tcpm->dev, "connector"); @@ -226,18 +102,20 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) goto fwnode_remove; } - ret = qcom_pmic_typec_port_start(tcpm->pmic_typec_port, - tcpm->tcpm_port); + ret = tcpm->port_start(tcpm, tcpm->tcpm_port); if (ret) - goto fwnode_remove; + goto port_unregister; - ret = qcom_pmic_typec_pdphy_start(tcpm->pmic_typec_pdphy, - tcpm->tcpm_port); + ret = tcpm->pdphy_start(tcpm, tcpm->tcpm_port); if (ret) - goto fwnode_remove; + goto port_stop; return 0; +port_stop: + tcpm->port_stop(tcpm); +port_unregister: + tcpm_unregister_port(tcpm->tcpm_port); fwnode_remove: fwnode_remove_software_node(tcpm->tcpc.fwnode); @@ -248,91 +126,25 @@ static void qcom_pmic_typec_remove(struct platform_device *pdev) { struct pmic_typec *tcpm = platform_get_drvdata(pdev); - qcom_pmic_typec_pdphy_stop(tcpm->pmic_typec_pdphy); - qcom_pmic_typec_port_stop(tcpm->pmic_typec_port); + tcpm->pdphy_stop(tcpm); + tcpm->port_stop(tcpm); tcpm_unregister_port(tcpm->tcpm_port); fwnode_remove_software_node(tcpm->tcpc.fwnode); } -static struct pmic_typec_pdphy_resources pm8150b_pdphy_res = { - .irq_params = { - { - .virq = PMIC_PDPHY_SIG_TX_IRQ, - .irq_name = "sig-tx", - }, - { - .virq = PMIC_PDPHY_SIG_RX_IRQ, - .irq_name = "sig-rx", - }, - { - .virq = PMIC_PDPHY_MSG_TX_IRQ, - .irq_name = "msg-tx", - }, - { - .virq = PMIC_PDPHY_MSG_RX_IRQ, - .irq_name = "msg-rx", - }, - { - .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ, - .irq_name = "msg-tx-failed", - }, - { - .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ, - .irq_name = "msg-tx-discarded", - }, - { - .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ, - .irq_name = "msg-rx-discarded", - }, - }, - .nr_irqs = 7, -}; - -static struct pmic_typec_port_resources pm8150b_port_res = { - .irq_params = { - { - .irq_name = "vpd-detect", - .virq = PMIC_TYPEC_VPD_IRQ, - }, - - { - .irq_name = "cc-state-change", - .virq = PMIC_TYPEC_CC_STATE_IRQ, - }, - { - .irq_name = "vconn-oc", - .virq = PMIC_TYPEC_VCONN_OC_IRQ, - }, - - { - .irq_name = "vbus-change", - .virq = PMIC_TYPEC_VBUS_IRQ, - }, - - { - .irq_name = "attach-detach", - .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ, - }, - { - .irq_name = "legacy-cable-detect", - .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ, - }, - - { - .irq_name = "try-snk-src-detect", - .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ, - }, - }, - .nr_irqs = 7, +static const struct pmic_typec_resources pm8150b_typec_res = { + .pdphy_res = &pm8150b_pdphy_res, + .port_res = &pm8150b_port_res, }; -static struct pmic_typec_resources pm8150b_typec_res = { - .pdphy_res = &pm8150b_pdphy_res, +static const struct pmic_typec_resources pmi632_typec_res = { + /* PD PHY not present */ .port_res = &pm8150b_port_res, }; static const struct of_device_id qcom_pmic_typec_table[] = { { .compatible = "qcom,pm8150b-typec", .data = &pm8150b_typec_res }, + { .compatible = "qcom,pmi632-typec", .data = &pmi632_typec_res }, { } }; MODULE_DEVICE_TABLE(of, qcom_pmic_typec_table); diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h new file mode 100644 index 0000000000..3c75820c91 --- /dev/null +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Linaro Ltd. All rights reserved. + */ + +#ifndef __QCOM_PMIC_TYPEC_H__ +#define __QCOM_PMIC_TYPEC_H__ + +struct pmic_typec { + struct device *dev; + struct tcpm_port *tcpm_port; + struct tcpc_dev tcpc; + struct pmic_typec_pdphy *pmic_typec_pdphy; + struct pmic_typec_port *pmic_typec_port; + + int (*pdphy_start)(struct pmic_typec *tcpm, + struct tcpm_port *tcpm_port); + void (*pdphy_stop)(struct pmic_typec *tcpm); + + int (*port_start)(struct pmic_typec *tcpm, + struct tcpm_port *tcpm_port); + void (*port_stop)(struct pmic_typec *tcpm); +}; + +#define tcpc_to_tcpm(_tcpc_) container_of(_tcpc_, struct pmic_typec, tcpc) + +#endif diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c index 52c81378e3..5b7f52b74a 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c @@ -14,8 +14,74 @@ #include <linux/slab.h> #include <linux/usb/pd.h> #include <linux/usb/tcpm.h> +#include "qcom_pmic_typec.h" #include "qcom_pmic_typec_pdphy.h" +/* PD PHY register offsets and bit fields */ +#define USB_PDPHY_MSG_CONFIG_REG 0x40 +#define MSG_CONFIG_PORT_DATA_ROLE BIT(3) +#define MSG_CONFIG_PORT_POWER_ROLE BIT(2) +#define MSG_CONFIG_SPEC_REV_MASK (BIT(1) | BIT(0)) + +#define USB_PDPHY_EN_CONTROL_REG 0x46 +#define CONTROL_ENABLE BIT(0) + +#define USB_PDPHY_RX_STATUS_REG 0x4A +#define RX_FRAME_TYPE (BIT(0) | BIT(1) | BIT(2)) + +#define USB_PDPHY_FRAME_FILTER_REG 0x4C +#define FRAME_FILTER_EN_HARD_RESET BIT(5) +#define FRAME_FILTER_EN_SOP BIT(0) + +#define USB_PDPHY_TX_SIZE_REG 0x42 +#define TX_SIZE_MASK 0xF + +#define USB_PDPHY_TX_CONTROL_REG 0x44 +#define TX_CONTROL_RETRY_COUNT(n) (((n) & 0x3) << 5) +#define TX_CONTROL_FRAME_TYPE(n) (((n) & 0x7) << 2) +#define TX_CONTROL_FRAME_TYPE_CABLE_RESET (0x1 << 2) +#define TX_CONTROL_SEND_SIGNAL BIT(1) +#define TX_CONTROL_SEND_MSG BIT(0) + +#define USB_PDPHY_RX_SIZE_REG 0x48 + +#define USB_PDPHY_RX_ACKNOWLEDGE_REG 0x4B +#define RX_BUFFER_TOKEN BIT(0) + +#define USB_PDPHY_BIST_MODE_REG 0x4E +#define BIST_MODE_MASK 0xF +#define BIST_ENABLE BIT(7) +#define PD_MSG_BIST 0x3 +#define PD_BIST_TEST_DATA_MODE 0x8 + +#define USB_PDPHY_TX_BUFFER_HDR_REG 0x60 +#define USB_PDPHY_TX_BUFFER_DATA_REG 0x62 + +#define USB_PDPHY_RX_BUFFER_REG 0x80 + +/* VDD regulator */ +#define VDD_PDPHY_VOL_MIN 2800000 /* uV */ +#define VDD_PDPHY_VOL_MAX 3300000 /* uV */ +#define VDD_PDPHY_HPM_LOAD 3000 /* uA */ + +/* Message Spec Rev field */ +#define PD_MSG_HDR_REV(hdr) (((hdr) >> 6) & 3) + +/* timers */ +#define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */ +#define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */ + +/* Interrupt numbers */ +#define PMIC_PDPHY_SIG_TX_IRQ 0x0 +#define PMIC_PDPHY_SIG_RX_IRQ 0x1 +#define PMIC_PDPHY_MSG_TX_IRQ 0x2 +#define PMIC_PDPHY_MSG_RX_IRQ 0x3 +#define PMIC_PDPHY_MSG_TX_FAIL_IRQ 0x4 +#define PMIC_PDPHY_MSG_TX_DISCARD_IRQ 0x5 +#define PMIC_PDPHY_MSG_RX_DISCARD_IRQ 0x6 +#define PMIC_PDPHY_FR_SWAP_IRQ 0x7 + + struct pmic_typec_pdphy_irq_data { int virq; int irq; @@ -231,11 +297,13 @@ done: return ret; } -int qcom_pmic_typec_pdphy_pd_transmit(struct pmic_typec_pdphy *pmic_typec_pdphy, - enum tcpm_transmit_type type, - const struct pd_message *msg, - unsigned int negotiated_rev) +static int qcom_pmic_typec_pdphy_pd_transmit(struct tcpc_dev *tcpc, + enum tcpm_transmit_type type, + const struct pd_message *msg, + unsigned int negotiated_rev) { + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy; struct device *dev = pmic_typec_pdphy->dev; int ret; @@ -299,7 +367,7 @@ done: if (!ret) { dev_vdbg(dev, "pd_receive: handing %d bytes to tcpm\n", size); - tcpm_pd_receive(pmic_typec_pdphy->tcpm_port, &msg); + tcpm_pd_receive(pmic_typec_pdphy->tcpm_port, &msg, TCPC_TX_SOP); } } @@ -336,8 +404,10 @@ static irqreturn_t qcom_pmic_typec_pdphy_isr(int irq, void *dev_id) return IRQ_HANDLED; } -int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, bool on) +static int qcom_pmic_typec_pdphy_set_pd_rx(struct tcpc_dev *tcpc, bool on) { + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy; unsigned long flags; int ret; @@ -353,9 +423,12 @@ int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, b return ret; } -int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy, - bool data_role_host, bool power_role_src) +static int qcom_pmic_typec_pdphy_set_roles(struct tcpc_dev *tcpc, bool attached, + enum typec_role power_role, + enum typec_data_role data_role) { + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy; struct device *dev = pmic_typec_pdphy->dev; unsigned long flags; int ret; @@ -366,12 +439,13 @@ int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy, pmic_typec_pdphy->base + USB_PDPHY_MSG_CONFIG_REG, MSG_CONFIG_PORT_DATA_ROLE | MSG_CONFIG_PORT_POWER_ROLE, - data_role_host << 3 | power_role_src << 2); + (data_role == TYPEC_HOST ? MSG_CONFIG_PORT_DATA_ROLE : 0) | + (power_role == TYPEC_SOURCE ? MSG_CONFIG_PORT_POWER_ROLE : 0)); spin_unlock_irqrestore(&pmic_typec_pdphy->lock, flags); dev_dbg(dev, "pdphy_set_roles: data_role_host=%d power_role_src=%d\n", - data_role_host, power_role_src); + data_role, power_role); return ret; } @@ -401,10 +475,8 @@ static int qcom_pmic_typec_pdphy_enable(struct pmic_typec_pdphy *pmic_typec_pdph qcom_pmic_typec_pdphy_reset_off(pmic_typec_pdphy); done: - if (ret) { - regulator_disable(pmic_typec_pdphy->vdd_pdphy); + if (ret) dev_err(dev, "pdphy_enable fail %d\n", ret); - } return ret; } @@ -435,9 +507,10 @@ done: return ret; } -int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy, - struct tcpm_port *tcpm_port) +static int qcom_pmic_typec_pdphy_start(struct pmic_typec *tcpm, + struct tcpm_port *tcpm_port) { + struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy; int i; int ret; @@ -449,16 +522,22 @@ int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy, ret = pmic_typec_pdphy_reset(pmic_typec_pdphy); if (ret) - return ret; + goto err_disable_vdd_pdhy; for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++) enable_irq(pmic_typec_pdphy->irq_data[i].irq); return 0; + +err_disable_vdd_pdhy: + regulator_disable(pmic_typec_pdphy->vdd_pdphy); + + return ret; } -void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy) +static void qcom_pmic_typec_pdphy_stop(struct pmic_typec *tcpm) { + struct pmic_typec_pdphy *pmic_typec_pdphy = tcpm->pmic_typec_pdphy; int i; for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++) @@ -469,21 +548,21 @@ void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy) regulator_disable(pmic_typec_pdphy->vdd_pdphy); } -struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev) -{ - return devm_kzalloc(dev, sizeof(struct pmic_typec_pdphy), GFP_KERNEL); -} - int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev, - struct pmic_typec_pdphy *pmic_typec_pdphy, - struct pmic_typec_pdphy_resources *res, + struct pmic_typec *tcpm, + const struct pmic_typec_pdphy_resources *res, struct regmap *regmap, u32 base) { + struct pmic_typec_pdphy *pmic_typec_pdphy; struct device *dev = &pdev->dev; struct pmic_typec_pdphy_irq_data *irq_data; int i, ret, irq; + pmic_typec_pdphy = devm_kzalloc(dev, sizeof(*pmic_typec_pdphy), GFP_KERNEL); + if (!pmic_typec_pdphy) + return -ENOMEM; + if (!res->nr_irqs || res->nr_irqs > PMIC_PDPHY_MAX_IRQS) return -EINVAL; @@ -522,5 +601,48 @@ int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev, return ret; } + tcpm->pmic_typec_pdphy = pmic_typec_pdphy; + + tcpm->tcpc.set_pd_rx = qcom_pmic_typec_pdphy_set_pd_rx; + tcpm->tcpc.set_roles = qcom_pmic_typec_pdphy_set_roles; + tcpm->tcpc.pd_transmit = qcom_pmic_typec_pdphy_pd_transmit; + + tcpm->pdphy_start = qcom_pmic_typec_pdphy_start; + tcpm->pdphy_stop = qcom_pmic_typec_pdphy_stop; + return 0; } + +const struct pmic_typec_pdphy_resources pm8150b_pdphy_res = { + .irq_params = { + { + .virq = PMIC_PDPHY_SIG_TX_IRQ, + .irq_name = "sig-tx", + }, + { + .virq = PMIC_PDPHY_SIG_RX_IRQ, + .irq_name = "sig-rx", + }, + { + .virq = PMIC_PDPHY_MSG_TX_IRQ, + .irq_name = "msg-tx", + }, + { + .virq = PMIC_PDPHY_MSG_RX_IRQ, + .irq_name = "msg-rx", + }, + { + .virq = PMIC_PDPHY_MSG_TX_FAIL_IRQ, + .irq_name = "msg-tx-failed", + }, + { + .virq = PMIC_PDPHY_MSG_TX_DISCARD_IRQ, + .irq_name = "msg-tx-discarded", + }, + { + .virq = PMIC_PDPHY_MSG_RX_DISCARD_IRQ, + .irq_name = "msg-rx-discarded", + }, + }, + .nr_irqs = 7, +}; diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.h b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.h index e67954e31b..04dee20293 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.h +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.h @@ -8,74 +8,6 @@ #include <linux/platform_device.h> #include <linux/regmap.h> -#include <linux/usb/tcpm.h> - -#define USB_PDPHY_MAX_DATA_OBJ_LEN 28 -#define USB_PDPHY_MSG_HDR_LEN 2 - -/* PD PHY register offsets and bit fields */ -#define USB_PDPHY_MSG_CONFIG_REG 0x40 -#define MSG_CONFIG_PORT_DATA_ROLE BIT(3) -#define MSG_CONFIG_PORT_POWER_ROLE BIT(2) -#define MSG_CONFIG_SPEC_REV_MASK (BIT(1) | BIT(0)) - -#define USB_PDPHY_EN_CONTROL_REG 0x46 -#define CONTROL_ENABLE BIT(0) - -#define USB_PDPHY_RX_STATUS_REG 0x4A -#define RX_FRAME_TYPE (BIT(0) | BIT(1) | BIT(2)) - -#define USB_PDPHY_FRAME_FILTER_REG 0x4C -#define FRAME_FILTER_EN_HARD_RESET BIT(5) -#define FRAME_FILTER_EN_SOP BIT(0) - -#define USB_PDPHY_TX_SIZE_REG 0x42 -#define TX_SIZE_MASK 0xF - -#define USB_PDPHY_TX_CONTROL_REG 0x44 -#define TX_CONTROL_RETRY_COUNT(n) (((n) & 0x3) << 5) -#define TX_CONTROL_FRAME_TYPE(n) (((n) & 0x7) << 2) -#define TX_CONTROL_FRAME_TYPE_CABLE_RESET (0x1 << 2) -#define TX_CONTROL_SEND_SIGNAL BIT(1) -#define TX_CONTROL_SEND_MSG BIT(0) - -#define USB_PDPHY_RX_SIZE_REG 0x48 - -#define USB_PDPHY_RX_ACKNOWLEDGE_REG 0x4B -#define RX_BUFFER_TOKEN BIT(0) - -#define USB_PDPHY_BIST_MODE_REG 0x4E -#define BIST_MODE_MASK 0xF -#define BIST_ENABLE BIT(7) -#define PD_MSG_BIST 0x3 -#define PD_BIST_TEST_DATA_MODE 0x8 - -#define USB_PDPHY_TX_BUFFER_HDR_REG 0x60 -#define USB_PDPHY_TX_BUFFER_DATA_REG 0x62 - -#define USB_PDPHY_RX_BUFFER_REG 0x80 - -/* VDD regulator */ -#define VDD_PDPHY_VOL_MIN 2800000 /* uV */ -#define VDD_PDPHY_VOL_MAX 3300000 /* uV */ -#define VDD_PDPHY_HPM_LOAD 3000 /* uA */ - -/* Message Spec Rev field */ -#define PD_MSG_HDR_REV(hdr) (((hdr) >> 6) & 3) - -/* timers */ -#define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */ -#define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */ - -/* Interrupt numbers */ -#define PMIC_PDPHY_SIG_TX_IRQ 0x0 -#define PMIC_PDPHY_SIG_RX_IRQ 0x1 -#define PMIC_PDPHY_MSG_TX_IRQ 0x2 -#define PMIC_PDPHY_MSG_RX_IRQ 0x3 -#define PMIC_PDPHY_MSG_TX_FAIL_IRQ 0x4 -#define PMIC_PDPHY_MSG_TX_DISCARD_IRQ 0x5 -#define PMIC_PDPHY_MSG_RX_DISCARD_IRQ 0x6 -#define PMIC_PDPHY_FR_SWAP_IRQ 0x7 /* Resources */ #define PMIC_PDPHY_MAX_IRQS 0x08 @@ -87,33 +19,19 @@ struct pmic_typec_pdphy_irq_params { struct pmic_typec_pdphy_resources { unsigned int nr_irqs; - struct pmic_typec_pdphy_irq_params irq_params[PMIC_PDPHY_MAX_IRQS]; + const struct pmic_typec_pdphy_irq_params irq_params[PMIC_PDPHY_MAX_IRQS]; }; /* API */ struct pmic_typec_pdphy; -struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev); - +extern const struct pmic_typec_pdphy_resources pm8150b_pdphy_res; int qcom_pmic_typec_pdphy_probe(struct platform_device *pdev, - struct pmic_typec_pdphy *pmic_typec_pdphy, - struct pmic_typec_pdphy_resources *res, + struct pmic_typec *tcpm, + const struct pmic_typec_pdphy_resources *res, struct regmap *regmap, u32 base); - -int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy, - struct tcpm_port *tcpm_port); - -void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy); - -int qcom_pmic_typec_pdphy_set_roles(struct pmic_typec_pdphy *pmic_typec_pdphy, - bool power_role_src, bool data_role_host); - -int qcom_pmic_typec_pdphy_set_pd_rx(struct pmic_typec_pdphy *pmic_typec_pdphy, bool on); - -int qcom_pmic_typec_pdphy_pd_transmit(struct pmic_typec_pdphy *pmic_typec_pdphy, - enum tcpm_transmit_type type, - const struct pd_message *msg, - unsigned int negotiated_rev); +int qcom_pmic_typec_pdphy_stub_probe(struct platform_device *pdev, + struct pmic_typec *tcpm); #endif /* __QCOM_PMIC_TYPEC_PDPHY_H__ */ diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c new file mode 100644 index 0000000000..df79059cda --- /dev/null +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Linaro Ltd. All rights reserved. + */ + +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/usb/pd.h> +#include <linux/usb/tcpm.h> +#include "qcom_pmic_typec.h" +#include "qcom_pmic_typec_pdphy.h" + +static int qcom_pmic_typec_pdphy_stub_pd_transmit(struct tcpc_dev *tcpc, + enum tcpm_transmit_type type, + const struct pd_message *msg, + unsigned int negotiated_rev) +{ + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct device *dev = tcpm->dev; + + dev_dbg(dev, "pdphy_transmit: type=%d\n", type); + + tcpm_pd_transmit_complete(tcpm->tcpm_port, + TCPC_TX_SUCCESS); + + return 0; +} + +static int qcom_pmic_typec_pdphy_stub_set_pd_rx(struct tcpc_dev *tcpc, bool on) +{ + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct device *dev = tcpm->dev; + + dev_dbg(dev, "set_pd_rx: %s\n", on ? "on" : "off"); + + return 0; +} + +static int qcom_pmic_typec_pdphy_stub_set_roles(struct tcpc_dev *tcpc, bool attached, + enum typec_role power_role, + enum typec_data_role data_role) +{ + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct device *dev = tcpm->dev; + + dev_dbg(dev, "pdphy_set_roles: data_role_host=%d power_role_src=%d\n", + data_role, power_role); + + return 0; +} + +static int qcom_pmic_typec_pdphy_stub_start(struct pmic_typec *tcpm, + struct tcpm_port *tcpm_port) +{ + return 0; +} + +static void qcom_pmic_typec_pdphy_stub_stop(struct pmic_typec *tcpm) +{ +} + +int qcom_pmic_typec_pdphy_stub_probe(struct platform_device *pdev, + struct pmic_typec *tcpm) +{ + tcpm->tcpc.set_pd_rx = qcom_pmic_typec_pdphy_stub_set_pd_rx; + tcpm->tcpc.set_roles = qcom_pmic_typec_pdphy_stub_set_roles; + tcpm->tcpc.pd_transmit = qcom_pmic_typec_pdphy_stub_pd_transmit; + + tcpm->pdphy_start = qcom_pmic_typec_pdphy_stub_start; + tcpm->pdphy_stop = qcom_pmic_typec_pdphy_stub_stop; + + return 0; +} diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c index a8f3f4d3a4..a747baa297 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c @@ -16,8 +16,147 @@ #include <linux/usb/tcpm.h> #include <linux/usb/typec_mux.h> #include <linux/workqueue.h> + +#include "qcom_pmic_typec.h" #include "qcom_pmic_typec_port.h" +#define TYPEC_SNK_STATUS_REG 0x06 +#define DETECTED_SNK_TYPE_MASK GENMASK(6, 0) +#define SNK_DAM_MASK GENMASK(6, 4) +#define SNK_DAM_500MA BIT(6) +#define SNK_DAM_1500MA BIT(5) +#define SNK_DAM_3000MA BIT(4) +#define SNK_RP_STD BIT(3) +#define SNK_RP_1P5 BIT(2) +#define SNK_RP_3P0 BIT(1) +#define SNK_RP_SHORT BIT(0) + +#define TYPEC_SRC_STATUS_REG 0x08 +#define DETECTED_SRC_TYPE_MASK GENMASK(4, 0) +#define SRC_HIGH_BATT BIT(5) +#define SRC_DEBUG_ACCESS BIT(4) +#define SRC_RD_OPEN BIT(3) +#define SRC_RD_RA_VCONN BIT(2) +#define SRC_RA_OPEN BIT(1) +#define AUDIO_ACCESS_RA_RA BIT(0) + +#define TYPEC_STATE_MACHINE_STATUS_REG 0x09 +#define TYPEC_ATTACH_DETACH_STATE BIT(5) + +#define TYPEC_SM_STATUS_REG 0x0A +#define TYPEC_SM_VBUS_VSAFE5V BIT(5) +#define TYPEC_SM_VBUS_VSAFE0V BIT(6) +#define TYPEC_SM_USBIN_LT_LV BIT(7) + +#define TYPEC_MISC_STATUS_REG 0x0B +#define TYPEC_WATER_DETECTION_STATUS BIT(7) +#define SNK_SRC_MODE BIT(6) +#define TYPEC_VBUS_DETECT BIT(5) +#define TYPEC_VBUS_ERROR_STATUS BIT(4) +#define TYPEC_DEBOUNCE_DONE BIT(3) +#define CC_ORIENTATION BIT(1) +#define CC_ATTACHED BIT(0) + +#define LEGACY_CABLE_STATUS_REG 0x0D +#define TYPEC_LEGACY_CABLE_STATUS BIT(1) +#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS BIT(0) + +#define TYPEC_U_USB_STATUS_REG 0x0F +#define U_USB_GROUND_NOVBUS BIT(6) +#define U_USB_GROUND BIT(4) +#define U_USB_FMB1 BIT(3) +#define U_USB_FLOAT1 BIT(2) +#define U_USB_FMB2 BIT(1) +#define U_USB_FLOAT2 BIT(0) + +#define TYPEC_MODE_CFG_REG 0x44 +#define TYPEC_TRY_MODE_MASK GENMASK(4, 3) +#define EN_TRY_SNK BIT(4) +#define EN_TRY_SRC BIT(3) +#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0) +#define EN_SRC_ONLY BIT(2) +#define EN_SNK_ONLY BIT(1) +#define TYPEC_DISABLE_CMD BIT(0) + +#define TYPEC_VCONN_CONTROL_REG 0x46 +#define VCONN_EN_ORIENTATION BIT(2) +#define VCONN_EN_VALUE BIT(1) +#define VCONN_EN_SRC BIT(0) + +#define TYPEC_CCOUT_CONTROL_REG 0x48 +#define TYPEC_CCOUT_BUFFER_EN BIT(2) +#define TYPEC_CCOUT_VALUE BIT(1) +#define TYPEC_CCOUT_SRC BIT(0) + +#define DEBUG_ACCESS_SRC_CFG_REG 0x4C +#define EN_UNORIENTED_DEBUG_ACCESS_SRC BIT(0) + +#define TYPE_C_CRUDE_SENSOR_CFG_REG 0x4e +#define EN_SRC_CRUDE_SENSOR BIT(1) +#define EN_SNK_CRUDE_SENSOR BIT(0) + +#define TYPEC_EXIT_STATE_CFG_REG 0x50 +#define BYPASS_VSAFE0V_DURING_ROLE_SWAP BIT(3) +#define SEL_SRC_UPPER_REF BIT(2) +#define USE_TPD_FOR_EXITING_ATTACHSRC BIT(1) +#define EXIT_SNK_BASED_ON_CC BIT(0) + +#define TYPEC_CURRSRC_CFG_REG 0x52 +#define TYPEC_SRC_RP_SEL_330UA BIT(1) +#define TYPEC_SRC_RP_SEL_180UA BIT(0) +#define TYPEC_SRC_RP_SEL_80UA 0 +#define TYPEC_SRC_RP_SEL_MASK GENMASK(1, 0) + +#define TYPEC_INTERRUPT_EN_CFG_1_REG 0x5E +#define TYPEC_LEGACY_CABLE_INT_EN BIT(7) +#define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN BIT(6) +#define TYPEC_TRYSOURCE_DETECT_INT_EN BIT(5) +#define TYPEC_TRYSINK_DETECT_INT_EN BIT(4) +#define TYPEC_CCOUT_DETACH_INT_EN BIT(3) +#define TYPEC_CCOUT_ATTACH_INT_EN BIT(2) +#define TYPEC_VBUS_DEASSERT_INT_EN BIT(1) +#define TYPEC_VBUS_ASSERT_INT_EN BIT(0) + +#define TYPEC_INTERRUPT_EN_CFG_2_REG 0x60 +#define TYPEC_SRC_BATT_HPWR_INT_EN BIT(6) +#define MICRO_USB_STATE_CHANGE_INT_EN BIT(5) +#define TYPEC_STATE_MACHINE_CHANGE_INT_EN BIT(4) +#define TYPEC_DEBUG_ACCESS_DETECT_INT_EN BIT(3) +#define TYPEC_WATER_DETECTION_INT_EN BIT(2) +#define TYPEC_VBUS_ERROR_INT_EN BIT(1) +#define TYPEC_DEBOUNCE_DONE_INT_EN BIT(0) + +#define TYPEC_DEBOUNCE_OPTION_REG 0x62 +#define REDUCE_TCCDEBOUNCE_TO_2MS BIT(2) + +#define TYPE_C_SBU_CFG_REG 0x6A +#define SEL_SBU1_ISRC_VAL 0x04 +#define SEL_SBU2_ISRC_VAL 0x01 + +#define TYPEC_U_USB_CFG_REG 0x70 +#define EN_MICRO_USB_FACTORY_MODE BIT(1) +#define EN_MICRO_USB_MODE BIT(0) + +#define TYPEC_PMI632_U_USB_WATER_PROTECTION_CFG_REG 0x72 + +#define TYPEC_U_USB_WATER_PROTECTION_CFG_REG 0x73 +#define EN_MICRO_USB_WATER_PROTECTION BIT(4) +#define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2) +#define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0) + +#define TYPEC_PMI632_MICRO_USB_MODE_REG 0x73 +#define MICRO_USB_MODE_ONLY BIT(0) + +/* Interrupt numbers */ +#define PMIC_TYPEC_OR_RID_IRQ 0x0 +#define PMIC_TYPEC_VPD_IRQ 0x1 +#define PMIC_TYPEC_CC_STATE_IRQ 0x2 +#define PMIC_TYPEC_VCONN_OC_IRQ 0x3 +#define PMIC_TYPEC_VBUS_IRQ 0x4 +#define PMIC_TYPEC_ATTACH_DETACH_IRQ 0x5 +#define PMIC_TYPEC_LEGACY_CABLE_IRQ 0x6 +#define PMIC_TYPEC_TRY_SNK_SRC_IRQ 0x7 + struct pmic_typec_port_irq_data { int virq; int irq; @@ -33,6 +172,8 @@ struct pmic_typec_port { struct pmic_typec_port_irq_data *irq_data; struct regulator *vdd_vbus; + bool vbus_enabled; + struct mutex vbus_lock; /* VBUS state serialization */ int cc; bool debouncing_cc; @@ -131,7 +272,7 @@ done: return IRQ_HANDLED; } -int qcom_pmic_typec_port_get_vbus(struct pmic_typec_port *pmic_typec_port) +static int qcom_pmic_typec_port_vbus_detect(struct pmic_typec_port *pmic_typec_port) { struct device *dev = pmic_typec_port->dev; unsigned int misc; @@ -148,7 +289,7 @@ int qcom_pmic_typec_port_get_vbus(struct pmic_typec_port *pmic_typec_port) return !!(misc & TYPEC_VBUS_DETECT); } -int qcom_pmic_typec_port_set_vbus(struct pmic_typec_port *pmic_typec_port, bool on) +static int qcom_pmic_typec_port_vbus_toggle(struct pmic_typec_port *pmic_typec_port, bool on) { u32 sm_stat; u32 val; @@ -179,10 +320,49 @@ int qcom_pmic_typec_port_set_vbus(struct pmic_typec_port *pmic_typec_port, bool return 0; } -int qcom_pmic_typec_port_get_cc(struct pmic_typec_port *pmic_typec_port, - enum typec_cc_status *cc1, - enum typec_cc_status *cc2) +static int qcom_pmic_typec_port_get_vbus(struct tcpc_dev *tcpc) +{ + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; + int ret; + + mutex_lock(&pmic_typec_port->vbus_lock); + ret = pmic_typec_port->vbus_enabled || qcom_pmic_typec_port_vbus_detect(pmic_typec_port); + mutex_unlock(&pmic_typec_port->vbus_lock); + + return ret; +} + +static int qcom_pmic_typec_port_set_vbus(struct tcpc_dev *tcpc, bool on, bool sink) +{ + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; + int ret = 0; + + mutex_lock(&pmic_typec_port->vbus_lock); + if (pmic_typec_port->vbus_enabled == on) + goto done; + + ret = qcom_pmic_typec_port_vbus_toggle(pmic_typec_port, on); + if (ret) + goto done; + + pmic_typec_port->vbus_enabled = on; + tcpm_vbus_change(tcpm->tcpm_port); + +done: + dev_dbg(tcpm->dev, "set_vbus set: %d result %d\n", on, ret); + mutex_unlock(&pmic_typec_port->vbus_lock); + + return ret; +} + +static int qcom_pmic_typec_port_get_cc(struct tcpc_dev *tcpc, + enum typec_cc_status *cc1, + enum typec_cc_status *cc2) { + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; struct device *dev = pmic_typec_port->dev; unsigned int misc, val; bool attached; @@ -275,9 +455,11 @@ static void qcom_pmic_set_cc_debounce(struct pmic_typec_port *pmic_typec_port) msecs_to_jiffies(2)); } -int qcom_pmic_typec_port_set_cc(struct pmic_typec_port *pmic_typec_port, - enum typec_cc_status cc) +static int qcom_pmic_typec_port_set_cc(struct tcpc_dev *tcpc, + enum typec_cc_status cc) { + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; struct device *dev = pmic_typec_port->dev; unsigned int mode, currsrc; unsigned int misc; @@ -341,8 +523,17 @@ done: return ret; } -int qcom_pmic_typec_port_set_vconn(struct pmic_typec_port *pmic_typec_port, bool on) +static int qcom_pmic_typec_port_set_polarity(struct tcpc_dev *tcpc, + enum typec_cc_polarity pol) +{ + /* Polarity is set separately by phy-qcom-qmp.c */ + return 0; +} + +static int qcom_pmic_typec_port_set_vconn(struct tcpc_dev *tcpc, bool on) { + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; struct device *dev = pmic_typec_port->dev; unsigned int orientation, misc, mask, value; unsigned long flags; @@ -377,10 +568,12 @@ done: return ret; } -int qcom_pmic_typec_port_start_toggling(struct pmic_typec_port *pmic_typec_port, - enum typec_port_type port_type, - enum typec_cc_status cc) +static int qcom_pmic_typec_port_start_toggling(struct tcpc_dev *tcpc, + enum typec_port_type port_type, + enum typec_cc_status cc) { + struct pmic_typec *tcpm = tcpc_to_tcpm(tcpc); + struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; struct device *dev = pmic_typec_port->dev; unsigned int misc; u8 mode = 0; @@ -441,9 +634,10 @@ done: (TYPEC_STATE_MACHINE_CHANGE_INT_EN | TYPEC_VBUS_ERROR_INT_EN | \ TYPEC_DEBOUNCE_DONE_INT_EN) -int qcom_pmic_typec_port_start(struct pmic_typec_port *pmic_typec_port, - struct tcpm_port *tcpm_port) +static int qcom_pmic_typec_port_start(struct pmic_typec *tcpm, + struct tcpm_port *tcpm_port) { + struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; int i; int mask; int ret; @@ -491,29 +685,30 @@ done: return ret; } -void qcom_pmic_typec_port_stop(struct pmic_typec_port *pmic_typec_port) +static void qcom_pmic_typec_port_stop(struct pmic_typec *tcpm) { + struct pmic_typec_port *pmic_typec_port = tcpm->pmic_typec_port; int i; for (i = 0; i < pmic_typec_port->nr_irqs; i++) disable_irq(pmic_typec_port->irq_data[i].irq); } -struct pmic_typec_port *qcom_pmic_typec_port_alloc(struct device *dev) -{ - return devm_kzalloc(dev, sizeof(struct pmic_typec_port), GFP_KERNEL); -} - int qcom_pmic_typec_port_probe(struct platform_device *pdev, - struct pmic_typec_port *pmic_typec_port, - struct pmic_typec_port_resources *res, + struct pmic_typec *tcpm, + const struct pmic_typec_port_resources *res, struct regmap *regmap, u32 base) { struct device *dev = &pdev->dev; struct pmic_typec_port_irq_data *irq_data; + struct pmic_typec_port *pmic_typec_port; int i, ret, irq; + pmic_typec_port = devm_kzalloc(dev, sizeof(*pmic_typec_port), GFP_KERNEL); + if (!pmic_typec_port) + return -ENOMEM; + if (!res->nr_irqs || res->nr_irqs > PMIC_TYPEC_MAX_IRQS) return -EINVAL; @@ -522,6 +717,8 @@ int qcom_pmic_typec_port_probe(struct platform_device *pdev, if (!irq_data) return -ENOMEM; + mutex_init(&pmic_typec_port->vbus_lock); + pmic_typec_port->vdd_vbus = devm_regulator_get(dev, "vdd-vbus"); if (IS_ERR(pmic_typec_port->vdd_vbus)) return PTR_ERR(pmic_typec_port->vdd_vbus); @@ -556,5 +753,56 @@ int qcom_pmic_typec_port_probe(struct platform_device *pdev, return ret; } + tcpm->pmic_typec_port = pmic_typec_port; + + tcpm->tcpc.get_vbus = qcom_pmic_typec_port_get_vbus; + tcpm->tcpc.set_vbus = qcom_pmic_typec_port_set_vbus; + tcpm->tcpc.set_cc = qcom_pmic_typec_port_set_cc; + tcpm->tcpc.get_cc = qcom_pmic_typec_port_get_cc; + tcpm->tcpc.set_polarity = qcom_pmic_typec_port_set_polarity; + tcpm->tcpc.set_vconn = qcom_pmic_typec_port_set_vconn; + tcpm->tcpc.start_toggling = qcom_pmic_typec_port_start_toggling; + + tcpm->port_start = qcom_pmic_typec_port_start; + tcpm->port_stop = qcom_pmic_typec_port_stop; + return 0; } + +const struct pmic_typec_port_resources pm8150b_port_res = { + .irq_params = { + { + .irq_name = "vpd-detect", + .virq = PMIC_TYPEC_VPD_IRQ, + }, + + { + .irq_name = "cc-state-change", + .virq = PMIC_TYPEC_CC_STATE_IRQ, + }, + { + .irq_name = "vconn-oc", + .virq = PMIC_TYPEC_VCONN_OC_IRQ, + }, + + { + .irq_name = "vbus-change", + .virq = PMIC_TYPEC_VBUS_IRQ, + }, + + { + .irq_name = "attach-detach", + .virq = PMIC_TYPEC_ATTACH_DETACH_IRQ, + }, + { + .irq_name = "legacy-cable-detect", + .virq = PMIC_TYPEC_LEGACY_CABLE_IRQ, + }, + + { + .irq_name = "try-snk-src-detect", + .virq = PMIC_TYPEC_TRY_SNK_SRC_IRQ, + }, + }, + .nr_irqs = 7, +}; diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.h b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.h index d4d358c680..2ca83a46cf 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.h +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.h @@ -3,149 +3,12 @@ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2023, Linaro Ltd. All rights reserved. */ -#ifndef __QCOM_PMIC_TYPEC_H__ -#define __QCOM_PMIC_TYPEC_H__ +#ifndef __QCOM_PMIC_TYPEC_PORT_H__ +#define __QCOM_PMIC_TYPEC_PORT_H__ #include <linux/platform_device.h> #include <linux/usb/tcpm.h> -#define TYPEC_SNK_STATUS_REG 0x06 -#define DETECTED_SNK_TYPE_MASK GENMASK(6, 0) -#define SNK_DAM_MASK GENMASK(6, 4) -#define SNK_DAM_500MA BIT(6) -#define SNK_DAM_1500MA BIT(5) -#define SNK_DAM_3000MA BIT(4) -#define SNK_RP_STD BIT(3) -#define SNK_RP_1P5 BIT(2) -#define SNK_RP_3P0 BIT(1) -#define SNK_RP_SHORT BIT(0) - -#define TYPEC_SRC_STATUS_REG 0x08 -#define DETECTED_SRC_TYPE_MASK GENMASK(4, 0) -#define SRC_HIGH_BATT BIT(5) -#define SRC_DEBUG_ACCESS BIT(4) -#define SRC_RD_OPEN BIT(3) -#define SRC_RD_RA_VCONN BIT(2) -#define SRC_RA_OPEN BIT(1) -#define AUDIO_ACCESS_RA_RA BIT(0) - -#define TYPEC_STATE_MACHINE_STATUS_REG 0x09 -#define TYPEC_ATTACH_DETACH_STATE BIT(5) - -#define TYPEC_SM_STATUS_REG 0x0A -#define TYPEC_SM_VBUS_VSAFE5V BIT(5) -#define TYPEC_SM_VBUS_VSAFE0V BIT(6) -#define TYPEC_SM_USBIN_LT_LV BIT(7) - -#define TYPEC_MISC_STATUS_REG 0x0B -#define TYPEC_WATER_DETECTION_STATUS BIT(7) -#define SNK_SRC_MODE BIT(6) -#define TYPEC_VBUS_DETECT BIT(5) -#define TYPEC_VBUS_ERROR_STATUS BIT(4) -#define TYPEC_DEBOUNCE_DONE BIT(3) -#define CC_ORIENTATION BIT(1) -#define CC_ATTACHED BIT(0) - -#define LEGACY_CABLE_STATUS_REG 0x0D -#define TYPEC_LEGACY_CABLE_STATUS BIT(1) -#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS BIT(0) - -#define TYPEC_U_USB_STATUS_REG 0x0F -#define U_USB_GROUND_NOVBUS BIT(6) -#define U_USB_GROUND BIT(4) -#define U_USB_FMB1 BIT(3) -#define U_USB_FLOAT1 BIT(2) -#define U_USB_FMB2 BIT(1) -#define U_USB_FLOAT2 BIT(0) - -#define TYPEC_MODE_CFG_REG 0x44 -#define TYPEC_TRY_MODE_MASK GENMASK(4, 3) -#define EN_TRY_SNK BIT(4) -#define EN_TRY_SRC BIT(3) -#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0) -#define EN_SRC_ONLY BIT(2) -#define EN_SNK_ONLY BIT(1) -#define TYPEC_DISABLE_CMD BIT(0) - -#define TYPEC_VCONN_CONTROL_REG 0x46 -#define VCONN_EN_ORIENTATION BIT(2) -#define VCONN_EN_VALUE BIT(1) -#define VCONN_EN_SRC BIT(0) - -#define TYPEC_CCOUT_CONTROL_REG 0x48 -#define TYPEC_CCOUT_BUFFER_EN BIT(2) -#define TYPEC_CCOUT_VALUE BIT(1) -#define TYPEC_CCOUT_SRC BIT(0) - -#define DEBUG_ACCESS_SRC_CFG_REG 0x4C -#define EN_UNORIENTED_DEBUG_ACCESS_SRC BIT(0) - -#define TYPE_C_CRUDE_SENSOR_CFG_REG 0x4e -#define EN_SRC_CRUDE_SENSOR BIT(1) -#define EN_SNK_CRUDE_SENSOR BIT(0) - -#define TYPEC_EXIT_STATE_CFG_REG 0x50 -#define BYPASS_VSAFE0V_DURING_ROLE_SWAP BIT(3) -#define SEL_SRC_UPPER_REF BIT(2) -#define USE_TPD_FOR_EXITING_ATTACHSRC BIT(1) -#define EXIT_SNK_BASED_ON_CC BIT(0) - -#define TYPEC_CURRSRC_CFG_REG 0x52 -#define TYPEC_SRC_RP_SEL_330UA BIT(1) -#define TYPEC_SRC_RP_SEL_180UA BIT(0) -#define TYPEC_SRC_RP_SEL_80UA 0 -#define TYPEC_SRC_RP_SEL_MASK GENMASK(1, 0) - -#define TYPEC_INTERRUPT_EN_CFG_1_REG 0x5E -#define TYPEC_LEGACY_CABLE_INT_EN BIT(7) -#define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN BIT(6) -#define TYPEC_TRYSOURCE_DETECT_INT_EN BIT(5) -#define TYPEC_TRYSINK_DETECT_INT_EN BIT(4) -#define TYPEC_CCOUT_DETACH_INT_EN BIT(3) -#define TYPEC_CCOUT_ATTACH_INT_EN BIT(2) -#define TYPEC_VBUS_DEASSERT_INT_EN BIT(1) -#define TYPEC_VBUS_ASSERT_INT_EN BIT(0) - -#define TYPEC_INTERRUPT_EN_CFG_2_REG 0x60 -#define TYPEC_SRC_BATT_HPWR_INT_EN BIT(6) -#define MICRO_USB_STATE_CHANGE_INT_EN BIT(5) -#define TYPEC_STATE_MACHINE_CHANGE_INT_EN BIT(4) -#define TYPEC_DEBUG_ACCESS_DETECT_INT_EN BIT(3) -#define TYPEC_WATER_DETECTION_INT_EN BIT(2) -#define TYPEC_VBUS_ERROR_INT_EN BIT(1) -#define TYPEC_DEBOUNCE_DONE_INT_EN BIT(0) - -#define TYPEC_DEBOUNCE_OPTION_REG 0x62 -#define REDUCE_TCCDEBOUNCE_TO_2MS BIT(2) - -#define TYPE_C_SBU_CFG_REG 0x6A -#define SEL_SBU1_ISRC_VAL 0x04 -#define SEL_SBU2_ISRC_VAL 0x01 - -#define TYPEC_U_USB_CFG_REG 0x70 -#define EN_MICRO_USB_FACTORY_MODE BIT(1) -#define EN_MICRO_USB_MODE BIT(0) - -#define TYPEC_PMI632_U_USB_WATER_PROTECTION_CFG_REG 0x72 - -#define TYPEC_U_USB_WATER_PROTECTION_CFG_REG 0x73 -#define EN_MICRO_USB_WATER_PROTECTION BIT(4) -#define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2) -#define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0) - -#define TYPEC_PMI632_MICRO_USB_MODE_REG 0x73 -#define MICRO_USB_MODE_ONLY BIT(0) - -/* Interrupt numbers */ -#define PMIC_TYPEC_OR_RID_IRQ 0x0 -#define PMIC_TYPEC_VPD_IRQ 0x1 -#define PMIC_TYPEC_CC_STATE_IRQ 0x2 -#define PMIC_TYPEC_VCONN_OC_IRQ 0x3 -#define PMIC_TYPEC_VBUS_IRQ 0x4 -#define PMIC_TYPEC_ATTACH_DETACH_IRQ 0x5 -#define PMIC_TYPEC_LEGACY_CABLE_IRQ 0x6 -#define PMIC_TYPEC_TRY_SNK_SRC_IRQ 0x7 - /* Resources */ #define PMIC_TYPEC_MAX_IRQS 0x08 @@ -156,40 +19,17 @@ struct pmic_typec_port_irq_params { struct pmic_typec_port_resources { unsigned int nr_irqs; - struct pmic_typec_port_irq_params irq_params[PMIC_TYPEC_MAX_IRQS]; + const struct pmic_typec_port_irq_params irq_params[PMIC_TYPEC_MAX_IRQS]; }; /* API */ -struct pmic_typec; -struct pmic_typec_port *qcom_pmic_typec_port_alloc(struct device *dev); +extern const struct pmic_typec_port_resources pm8150b_port_res; int qcom_pmic_typec_port_probe(struct platform_device *pdev, - struct pmic_typec_port *pmic_typec_port, - struct pmic_typec_port_resources *res, + struct pmic_typec *tcpm, + const struct pmic_typec_port_resources *res, struct regmap *regmap, u32 base); -int qcom_pmic_typec_port_start(struct pmic_typec_port *pmic_typec_port, - struct tcpm_port *tcpm_port); - -void qcom_pmic_typec_port_stop(struct pmic_typec_port *pmic_typec_port); - -int qcom_pmic_typec_port_get_cc(struct pmic_typec_port *pmic_typec_port, - enum typec_cc_status *cc1, - enum typec_cc_status *cc2); - -int qcom_pmic_typec_port_set_cc(struct pmic_typec_port *pmic_typec_port, - enum typec_cc_status cc); - -int qcom_pmic_typec_port_get_vbus(struct pmic_typec_port *pmic_typec_port); - -int qcom_pmic_typec_port_set_vconn(struct pmic_typec_port *pmic_typec_port, bool on); - -int qcom_pmic_typec_port_start_toggling(struct pmic_typec_port *pmic_typec_port, - enum typec_port_type port_type, - enum typec_cc_status cc); - -int qcom_pmic_typec_port_set_vbus(struct pmic_typec_port *pmic_typec_port, bool on); - #endif /* __QCOM_PMIC_TYPE_C_PORT_H__ */ |