Received: by 10.223.185.116 with SMTP id b49csp637672wrg; Wed, 14 Feb 2018 04:46:51 -0800 (PST) X-Google-Smtp-Source: AH8x226gs63QuXdsVuor7D7RP3RxbvghUhlNUnHlPWXKVzQG35cR+DWyLThesPiY48DRZl0+smNc X-Received: by 2002:a17:902:5482:: with SMTP id e2-v6mr225474pli.65.1518612411162; Wed, 14 Feb 2018 04:46:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518612411; cv=none; d=google.com; s=arc-20160816; b=N32SNL9ap+1RkYCSLp+4hT2L6fpYZsW+ii1iAeCRhS0FF9RxKB+MwOz7MGU3p3Edcz 6eQN1n3/B5PlSLSBPrMJQJLUpinO7hRSfth/hblDBa9zdL/xAHmefTNcjCJ79BJiGEvq M6+xVQhKYFKEOSVKdMonK+t5IMFCr3krqvmpjO1yv6543DR/hoGq9XtDGJ7sHRM5t+na 744VdXapMUfiir0jq1pNmuTh7Azrc666tKtAFPawP9Ew9ECxEmCMGZjnEGqgBei8xygq E0XVNnktAyMe3NfqT4bbKmJ7tquCfCfnvxU+RwfYxO2HqO9AvswoRVxlOrxIPBDKyW0X WVnA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=OxooCiEv0fqhP/Fj+ZvT8aRn8A29slxxTtoQGf21u58=; b=mLBSUvK+RPvxpOrWyMJ8Fx6ofkYFkaOEdG979jF/q7NnHAoNto2LNufXtEFtqCeZtH zrufU7bFKgumO/H7gyzXy2EjftkUJv6dY/DwfDnYMyt5KvUjoDxeQIqfhiKDrlaAH28N tDfSiE1wDeykX4T/K5/4XF2IuLHSx8LTiA1aVZMirlolEpmMJgKFjPQgCOHrwMbvCkxR LyQV3K5ykuWuI4r+TEse6xznsPfBA/VhfQoGnak/MeGTnJpJn6S6ATUN9lMgTSCYRZMh 5A+64Rx93xBXn3GUExU/mso1T+MW45fPX29m/Jg9D8lb6zvKctXk95YPYSPISAXnihQf UqWQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=IpsCVlME; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t8si1906681pgo.398.2018.02.14.04.46.36; Wed, 14 Feb 2018 04:46:51 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=IpsCVlME; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S967740AbeBNMpx (ORCPT + 99 others); Wed, 14 Feb 2018 07:45:53 -0500 Received: from mail-pl0-f65.google.com ([209.85.160.65]:37139 "EHLO mail-pl0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S967589AbeBNMpv (ORCPT ); Wed, 14 Feb 2018 07:45:51 -0500 Received: by mail-pl0-f65.google.com with SMTP id ay8so8468405plb.4; Wed, 14 Feb 2018 04:45:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=OxooCiEv0fqhP/Fj+ZvT8aRn8A29slxxTtoQGf21u58=; b=IpsCVlMEhMoQL9Jvz7WWTfm5oTeflFXLfOcgCr6CBAMnglYBbtN27ScCT07uhMvLsF 0PipmHLANhlfJGDUQcn/hw1MY3vuqvXxUPJ+uRdZCVYrg3o7pbRi0ARTa0sNmf8GwLhU gqrNYc5s/T8/4ZepRP5MOHkKN3PHzC1FK4TzH9rK0jC8lsgI7N00Y92+yNEWd8GWVi+F B+28bONpsMAXDxZzNaqIosjSo8n1Icd5TRpqB47vGSe2becQsh6nQyIijtO2kjyK5WaC SSW2OZJQ6sDGVGaGUPerdjNdRlScW/PZORbB+7WfGjKLUsEkt1Zh+nDDc+9zZMQTawRo AvCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=OxooCiEv0fqhP/Fj+ZvT8aRn8A29slxxTtoQGf21u58=; b=E667sK/gC+RE64Oxf2aQQpUwlQY9nBHtdIGcajxbiVYZwZqj9ZSx19SjTMzp29hov0 PIVQWADh93AGTulwzumCSf/mrh7HOrqdmUqqBAGLnHt2beFIyCiMXqXJJ9ktPy77as9I L8YJrpXU+KeyJ/kqM+opqDbAM4xU+xO2xhNj1TAmpHMs40+gUFjEuyS2omfiTPqWtvDK JCC9eU1Yl+kfXNmL28nusjGz+tFt5R8zmrAX1FanwZSd3VmwTpduvuJZdgb3idsaMICk Q3oCBjoCbOyDi5YKo1ZB542TwVMiR6Qys5oo9mhEpNYjwUvLPJuNqc9Cm/A1bych4IZQ qEmg== X-Gm-Message-State: APf1xPCaX6jIUvzkN8Vy52iIkpyYY4dx9xstXDvqgGUpBJDy0D277Ud9 K4oxD5qtFzirq7J3wlHdils= X-Received: by 2002:a17:902:988b:: with SMTP id s11-v6mr4203739plp.99.1518612351167; Wed, 14 Feb 2018 04:45:51 -0800 (PST) Received: from localhost.localdomain (114-137-128-140.emome-ip.hinet.net. [114.137.128.140]) by smtp.gmail.com with ESMTPSA id j25sm37220996pfi.118.2018.02.14.04.45.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 14 Feb 2018 04:45:50 -0800 (PST) From: ShuFanLee To: heikki.krogerus@linux.intel.com, linux@roeck-us.net Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, cy_huang@richtek.com, shufan_lee@richtek.com Subject: [PATCH v2] staging: typec: handle vendor defined part and modify drp toggling flow Date: Wed, 14 Feb 2018 20:45:34 +0800 Message-Id: <1518612334-24140-1-git-send-email-leechu729@gmail.com> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: ShuFanLee Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq. More operations can be extended in tcpci_data if needed. According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not start DRP toggling until subsequently the TCPM writes to the COMMAND register to start DRP toggling. DRP toggling flow is chagned as following: - Write DRP = 0 & Rd/Rd - Write DRP = 1 - Set LOOK4CONNECTION command Signed-off-by: ShuFanLee --- drivers/staging/typec/tcpci.c | 111 ++++++++++++++++++++++++++++++++++-------- drivers/staging/typec/tcpci.h | 13 +++++ 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..461fbd48 100644 --- a/drivers/staging/typec/tcpci.c +++ b/drivers/staging/typec/tcpci.c @@ -21,7 +21,6 @@ struct tcpci { struct device *dev; - struct i2c_client *client; struct tcpm_port *port; @@ -30,6 +29,7 @@ struct tcpci { bool controls_vbus; struct tcpc_dev tcpc; + struct tcpci_data *data; }; static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -98,8 +98,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, enum typec_cc_status cc) { + int ret; struct tcpci *tcpci = tcpc_to_tcpci(tcpc); - unsigned int reg = TCPC_ROLE_CTRL_DRP; + unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); switch (cc) { default: @@ -116,8 +118,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, TCPC_ROLE_CTRL_RP_VAL_SHIFT); break; } - - return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + usleep_range(500, 1000); + reg |= TCPC_ROLE_CTRL_DRP; + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + ret = regmap_write(tcpci->regmap, TCPC_COMMAND, + TCPC_CMD_LOOK4CONNECTION); + if (ret < 0) + return ret; + return 0; } static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) @@ -178,6 +191,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable) struct tcpci *tcpci = tcpc_to_tcpci(tcpc); int ret; + /* Handle vendor set vconn */ + if (tcpci->data) { + if (tcpci->data->set_vconn) { + ret = tcpci->data->set_vconn(tcpci, tcpci->data, + enable); + if (ret < 0) + return ret; + } + } + ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL, enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0); if (ret < 0) @@ -323,6 +346,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) if (time_after(jiffies, timeout)) return -ETIMEDOUT; + /* Handle vendor init */ + if (tcpci->data) { + if (tcpci->data->init) { + ret = tcpci->data->init(tcpci, tcpci->data); + if (ret < 0) + return ret; + } + } + /* Clear all events */ ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff); if (ret < 0) @@ -344,9 +376,16 @@ static int tcpci_init(struct tcpc_dev *tcpc) return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg); } -static irqreturn_t tcpci_irq(int irq, void *dev_id) +static irqreturn_t _tcpci_irq(int irq, void *dev_id) { struct tcpci *tcpci = dev_id; + + tcpci_irq(tcpci); + return IRQ_HANDLED; +} + +int tcpci_irq(struct tcpci *tcpci) +{ u16 status; tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +451,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(tcpci_irq); static const struct regmap_config tcpci_regmap_config = { .reg_bits = 8, @@ -435,22 +475,18 @@ static int tcpci_parse_config(struct tcpci *tcpci) return 0; } -static int tcpci_probe(struct i2c_client *client, - const struct i2c_device_id *i2c_id) +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) { struct tcpci *tcpci; int err; - tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL); + tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL); if (!tcpci) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - tcpci->client = client; - tcpci->dev = &client->dev; - i2c_set_clientdata(client, tcpci); - tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config); - if (IS_ERR(tcpci->regmap)) - return PTR_ERR(tcpci->regmap); + tcpci->dev = dev; + tcpci->data = data; + tcpci->regmap = data->regmap; tcpci->tcpc.init = tcpci_init; tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,27 +503,60 @@ static int tcpci_probe(struct i2c_client *client, err = tcpci_parse_config(tcpci); if (err < 0) - return err; + return ERR_PTR(err); /* Disable chip interrupts */ tcpci_write16(tcpci, TCPC_ALERT_MASK, 0); - err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL, - tcpci_irq, + tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); + if (PTR_ERR_OR_ZERO(tcpci->port)) + return ERR_CAST(tcpci->port); + + return tcpci; +} +EXPORT_SYMBOL_GPL(tcpci_register_port); + +void tcpci_unregister_port(struct tcpci *tcpci) +{ + tcpm_unregister_port(tcpci->port); +} +EXPORT_SYMBOL_GPL(tcpci_unregister_port); + +static int tcpci_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct tcpci *tcpci; + struct tcpci_data *data; + int err; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + tcpci = tcpci_register_port(&client->dev, data); + if (PTR_ERR_OR_ZERO(tcpci)) + return PTR_ERR(tcpci); + + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + _tcpci_irq, IRQF_ONESHOT | IRQF_TRIGGER_LOW, dev_name(tcpci->dev), tcpci); if (err < 0) return err; - tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); - return PTR_ERR_OR_ZERO(tcpci->port); + i2c_set_clientdata(client, tcpci); + return 0; } static int tcpci_remove(struct i2c_client *client) { struct tcpci *tcpci = i2c_get_clientdata(client); - tcpm_unregister_port(tcpci->port); + tcpci_unregister_port(tcpci); return 0; } diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h index fdfb06c..c838723 100644 --- a/drivers/staging/typec/tcpci.h +++ b/drivers/staging/typec/tcpci.h @@ -59,6 +59,7 @@ #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0) #define TCPC_CC_STATUS 0x1d +#define TCPC_CC_STATUS_DRPRST BIT(5) #define TCPC_CC_STATUS_TERM BIT(4) #define TCPC_CC_STATUS_CC2_SHIFT 2 #define TCPC_CC_STATUS_CC2_MASK 0x3 @@ -121,4 +122,16 @@ #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78 +struct tcpci; +struct tcpci_data { + struct regmap *regmap; + int (*init)(struct tcpci *tcpci, struct tcpci_data *data); + int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data, + bool enable); +}; + +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data); +void tcpci_unregister_port(struct tcpci *tcpci); +int tcpci_irq(struct tcpci *tcpci); + #endif /* __LINUX_USB_TCPCI_H */ -- 1.9.1