Received: by 10.223.185.116 with SMTP id b49csp2166900wrg; Sun, 4 Mar 2018 20:25:18 -0800 (PST) X-Google-Smtp-Source: AG47ELsBUAjrx1zZc2USud9DgrPVP0SK1+vFZgeGuwW+k7WSd/SXfC+ahyRq2YBSNBf7o6YiHCkb X-Received: by 10.101.81.132 with SMTP id h4mr11303311pgq.332.1520223918424; Sun, 04 Mar 2018 20:25:18 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520223918; cv=none; d=google.com; s=arc-20160816; b=w/NgXxFnViO4J8lf20dH8BazbBKmzMM9FF6KMeRhrSB7uwPoXZtgw107VQUU4pJeSS G9TQRkcqjni9GoULX9F90dKJdKsXqSO83YqDlDSWmV3yhu2WwIpmt+Plq9dZC9mkmkMl Vs3aKjk+iDu4vGDgfuWCTg3VGDxZZpYbhm9zvCQAz/+69i9pzs2ggMOyUkW0DPD1sC9M sKW+w5iz9S2ahkw/LYH6jkPCR/Iqs9naMvpa8CuplTinOv2pZTIV0e8lUU7lnwUuFbWj zkmqTHWsA8cL92WrwdkB/Bq2yndvKsevB1rdaM3LQGLmgDJ3CVXVsziOb2cHtSFYLxOV F14Q== 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=hkh8FqAREyQqg6awUsvl88LI8rM2ST8kZE+417gC2Gg=; b=fXZLItlDvP8Tpg51E4DyDya3+5QiH6fjFRIlMx+568vkq6cekJJvv7zJznmKVk7dww n3IFTXBHFRQDqUDxge5tOsAFFidGlne+1Aif14d5nd2NLLE11ZVootAjuItu5JHq60QD He7dO84/CkhZ5m0WTySTXr4e1mNql7gnV2diRqqU4feRq5X8fkUEhbL3MZMwVkrsg5f6 hjkU+NwqqcrnRH061A/RYasGBMQnGQZWQ3QeDfLC+BzR31Y9gPJEfFbCA1vCIRTokubK Z55v+RffX4Uyni6mYmsSOVYSgpJJfTRkhDZWDF0IwG3AJ8Rnrk8k/ypkNUx8eS9GLylA bmhQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=bpH/WDeA; 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 h18si9449026pfi.31.2018.03.04.20.25.03; Sun, 04 Mar 2018 20:25:18 -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=bpH/WDeA; 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 S932544AbeCEERJ (ORCPT + 99 others); Sun, 4 Mar 2018 23:17:09 -0500 Received: from mail-pf0-f194.google.com ([209.85.192.194]:34680 "EHLO mail-pf0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932355AbeCEERH (ORCPT ); Sun, 4 Mar 2018 23:17:07 -0500 Received: by mail-pf0-f194.google.com with SMTP id j20so6706751pfi.1; Sun, 04 Mar 2018 20:17:07 -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=hkh8FqAREyQqg6awUsvl88LI8rM2ST8kZE+417gC2Gg=; b=bpH/WDeAOxMjj5Fn1WRHEUYbH0feKhS7MBztVUadO0KWUlzoRuaX4XOXVX6e/tEUnv aCAg7Bv0m7pUeAxn3qj4Et7JjVX1PXFzlorC6f49O0YZGTSMnQVKnuISkUm7slx4pr+M AcdknGHtT+pNeeeNZjI8GzX8XgelGVt1MFEJ17vAVSzaiVzJ09r14KYSSDNTu5b5z2jP 90LIZULlZhFxRTo4WojzgqBbHz/9FUlgQaVOCgRlmz6ltmp6TapXFiophHoglYJUT55e 35Tz6T0b31UZL5J83Zpk9sMgppU+bejBYTE04NCRC26BRQB7MhfofcFqN+G23o+DVsWn DQQQ== 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=hkh8FqAREyQqg6awUsvl88LI8rM2ST8kZE+417gC2Gg=; b=BUzy2SAOsDBRm9pKQH1e4Q6HZ0O1gX4qErAZjxbjsxkl4FzeK3vUZoXLMYSIvyR2ic 0RBxdAp/4BMEvDfWUxyln5x/18lwwBhSQBxPyZVvBFy5HY4yaQZnP2I0H9hVZJ0ubQni 4+QU7Xfq2MvPYoIeDfjhNxK6dD+z/NOxNPzOAQdjnZCMX6UDTSKPpbxWMok2lalR1M2G 59GjddW34PmBkzT4kG/JPiOOZMd6LoTvsyZwqx3OD36pi52IEs92IZGF75v2LzbSa5Rb kCpnCt/BEFaW4UvA6Aa9THb5VJOYMTiH6O0yzHhvA4URqup4TH4hLiWROiRdbE5QkHwX Gzxw== X-Gm-Message-State: APf1xPCYOgy+0ljHJYZOJe3WEP76JU4whSGBdgeAHuPZA2M5t8KzbmcE u7bObMeArWSIfnIg2FBN2MHRavUJnCc= X-Received: by 10.101.97.139 with SMTP id c11mr10346277pgv.431.1520223426641; Sun, 04 Mar 2018 20:17:06 -0800 (PST) Received: from localhost.localdomain (114-137-238-64.emome-ip.hinet.net. [114.137.238.64]) by smtp.gmail.com with ESMTPSA id n79sm24527440pfa.55.2018.03.04.20.17.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 04 Mar 2018 20:17:05 -0800 (PST) From: ShuFan Lee To: heikki.krogerus@linux.intel.com, linux@roeck-us.net, greg@kroah.com Cc: shufan_lee@richtek.com, cy_huang@richtek.com, jun.li@nxp.com, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Subject: [PATCH v6] staging: typec: handle vendor defined part and modify drp toggling flow Date: Mon, 5 Mar 2018 12:16:42 +0800 Message-Id: <1520223402-19906-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: ShuFan Lee Handle vendor defined behavior in tcpci_init, tcpci_set_vconn, tcpci_start_drp_toggling 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 = 1, Rp level and RC.CCx to Rd/Rd or Rp/Rp - Set LOOK4CONNECTION command Signed-off-by: ShuFan Lee --- drivers/staging/typec/tcpci.c | 134 ++++++++++++++++++++++++++++++++++-------- drivers/staging/typec/tcpci.h | 15 +++++ 2 files changed, 123 insertions(+), 26 deletions(-) patch changelogs between v1 & v2 - Remove unnecessary i2c_client in the structure of tcpci - Rename structure of tcpci_vendor_data to tcpci_data - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver - Add set_vconn ops in tcpci_data (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn) - Export tcpci_irq so that vendor can call it in their own IRQ handler patch changelogs between v2 & v3 - Change the return type of tcpci_irq from int to irqreturn_t patch changelogs between v3 & v4 - Directly return regmap_write at the end of drp_toggling function - Because tcpci_irq is called in _tcpci_irq, move _tcpci_irq to the place after tcpci_irq patch changelogs between v4 & v5 - Add a space between my first & last name, from ShuFanLee to ShuFan Lee. patch changelogs between v5 & v6 - Add start_drp_toggling in tcpci_data and call it at the beginning of tcpci_start_drp_toggling - Modify the flow of tcpci_start_drp_toggling as following - Set Rp level, RC.CCx to Rd/Rd or Rp/Rp and DRP = 1 - Set LOOK4CONNECTION command diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..9e600f7 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,12 @@ struct tcpci { bool controls_vbus; struct tcpc_dev tcpc; + struct tcpci_data *data; +}; + +struct tcpci_chip { + struct tcpci *tcpci; + struct tcpci_data data; }; static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) return container_of(tcpc, struct tcpci, tcpc); } -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, - u16 *val) +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val) { return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); } @@ -98,9 +102,19 @@ 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; + if (tcpci->data) { + if (tcpci->data->start_drp_toggling) { + ret = tcpci->data->start_drp_toggling(tcpci, + tcpci->data, cc); + if (ret < 0) + return ret; + } + } + switch (cc) { default: case TYPEC_CC_RP_DEF: @@ -117,7 +131,17 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, break; } - return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (cc == TYPEC_CC_RD) + reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); + else + reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | + (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT); + ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); + if (ret < 0) + return ret; + return regmap_write(tcpci->regmap, TCPC_COMMAND, + TCPC_CMD_LOOK4CONNECTION); } static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) @@ -178,6 +202,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 +357,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 +387,8 @@ 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) +irqreturn_t tcpci_irq(struct tcpci *tcpci) { - struct tcpci *tcpci = dev_id; u16 status; tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +454,14 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(tcpci_irq); + +static irqreturn_t _tcpci_irq(int irq, void *dev_id) +{ + struct tcpci *tcpci = dev_id; + + return tcpci_irq(tcpci); +} static const struct regmap_config tcpci_regmap_config = { .reg_bits = 8, @@ -435,22 +485,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 +513,63 @@ static int tcpci_probe(struct i2c_client *client, err = tcpci_parse_config(tcpci); if (err < 0) - return err; + return ERR_PTR(err); + + tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); + if (PTR_ERR_OR_ZERO(tcpci->port)) + return ERR_CAST(tcpci->port); - /* Disable chip interrupts */ - tcpci_write16(tcpci, TCPC_ALERT_MASK, 0); + 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); - err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL, - tcpci_irq, +static int tcpci_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct tcpci_chip *chip; + int err; + u16 val = 0; + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config); + if (IS_ERR(chip->data.regmap)) + return PTR_ERR(chip->data.regmap); + + /* Disable chip interrupts before requesting irq */ + err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val, + sizeof(u16)); + if (err < 0) + return err; + + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + _tcpci_irq, IRQF_ONESHOT | IRQF_TRIGGER_LOW, - dev_name(tcpci->dev), tcpci); + dev_name(&client->dev), chip); if (err < 0) return err; - tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); - return PTR_ERR_OR_ZERO(tcpci->port); + chip->tcpci = tcpci_register_port(&client->dev, &chip->data); + if (PTR_ERR_OR_ZERO(chip->tcpci)) + return PTR_ERR(chip->tcpci); + + i2c_set_clientdata(client, chip); + return 0; } static int tcpci_remove(struct i2c_client *client) { - struct tcpci *tcpci = i2c_get_clientdata(client); + struct tcpci_chip *chip = i2c_get_clientdata(client); - tcpm_unregister_port(tcpci->port); + tcpci_unregister_port(chip->tcpci); return 0; } diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h index fdfb06c..a2c1754 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,18 @@ #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); + int (*start_drp_toggling)(struct tcpci *tcpci, struct tcpci_data *data, + enum typec_cc_status cc); +}; + +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data); +void tcpci_unregister_port(struct tcpci *tcpci); +irqreturn_t tcpci_irq(struct tcpci *tcpci); + #endif /* __LINUX_USB_TCPCI_H */ -- 1.9.1