Received: by 10.223.185.116 with SMTP id b49csp1030658wrg; Wed, 21 Feb 2018 10:52:34 -0800 (PST) X-Google-Smtp-Source: AH8x2243jTYyCjHYBkxlANYlEFCwMvVYexgZOZW4aVl5Y/WzLX1HEu4Ekfbn9BkgbWI20sAh9FKd X-Received: by 2002:a17:902:9698:: with SMTP id n24-v6mr3922746plp.93.1519239154066; Wed, 21 Feb 2018 10:52:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519239154; cv=none; d=google.com; s=arc-20160816; b=Ez5C3IV1B9FGeOKxnYMXDczcjpSmHIHiwM+uZBrBbZZxvxmQyqB1j3AZZGH6w3hIjO YrUzikzi0KJHHK5/sIFeCVS+dw1PZ03ns81Tbn13ZYXmcD0E5uS11wCY7gXGI34d1CxK MtfsFqndNrjQaAis32BtLtpjy1K4HWqt2jIkFmMsu2sgX2hZFsnYh93kEwzSfGio9YPv sbrwLKlpLKmDKs39dKSw1fopFIoxTE2eKb7R1+zGTvyiajpM/Vx35uRQPZ2CUF4Qb+fj NSjCiHY9S4RKWkSeDXYh0bnMiS/xZXaM2kgGEpzI9TECjTEFDShD6AScjsSyKpYj8bZo s0FQ== 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=s3nueMDqe7lNHFWBfG1VdUmwdWbF2Qb6dFVbdOO2KO0=; b=rZFAtUTBfkz9xr2squVELKkXULqQ/h5M0shz1F+VGjDA98s4UpOqzwKFI4GeHx+TDp FUEUyZfRn9WIVtOBQjzXUGMn3Cr1HW3vRg7uRrhlsRqr/uYjYAHv26Dx/6lpdNgCnWfm GuhNz1zLM/WoK8nCvYfsXhSTw+9LtEQUjfzZuTgWh4VjJxb2CzIzYOjCLmo3MWE9lLRR +vj4MOihK24uj+fBl+SsIRj3FV2V//SM4tC4uvi1fIcwJun6hZwWFqkiigCwwmcqqvVd esmpl5kdL5Hx3Mnb76ynVclEyAND3XlSb663UdhR8Ri6Zl+h6ORilQCmyb99ZNqO00M1 811g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=Vp+a1/Co; 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 f84si265318pfe.128.2018.02.21.10.52.20; Wed, 21 Feb 2018 10:52:34 -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=Vp+a1/Co; 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 S937662AbeBUOa7 (ORCPT + 99 others); Wed, 21 Feb 2018 09:30:59 -0500 Received: from mail-pf0-f195.google.com ([209.85.192.195]:40590 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932696AbeBUOa4 (ORCPT ); Wed, 21 Feb 2018 09:30:56 -0500 Received: by mail-pf0-f195.google.com with SMTP id m5so713078pff.7; Wed, 21 Feb 2018 06:30:56 -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=s3nueMDqe7lNHFWBfG1VdUmwdWbF2Qb6dFVbdOO2KO0=; b=Vp+a1/CoZrBUr8UpaX3wNMdhn9dUoDNl6oP6vbI7JPldRHtKKqkq0BFfu+mE8lb0/Z u9kacGW8c4SUVGZTqUasIay6GW0g+JCqiWEx2Cl0sT7Xf/pkjwQ8K2Ao1XL4rnaTWTUh OI/e8SKZwtTOE6wRG0ERSfvpvhn8RpUxiUBuJrEUIzZ4lo4rAkJ0oZee54j5NPV3rG7K W6k8IC1S6Nw0XIYHRXtiQaGUFcDOeP85x+dylwzUynHy+TqpUib76e/hxFQapZOhuRGK 4Mu/bGLG4q0LItSxT4Q5+iCf9CrzNxJh9+CsHt7eAjSoXz023/clYUsiAow9vGyFmqve M2Lw== 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=s3nueMDqe7lNHFWBfG1VdUmwdWbF2Qb6dFVbdOO2KO0=; b=hHfXHXufVJxdK6QbqXmc17g5RIs2CVZXp2Ux9Wl2JNlgKPVl7WyLpp4CfLeVQMdejl 8Q7XXeNQa/BVOCkLPxoXbUHe3SnRoVIWUWhVt7EvdGEYchlUeCloRz0NevncIqUivKWn ThvLQ/tHO/GLR8XoeL39ls9D5O22HTJCLxfCfiWb4EyQL2NwlUOsQEsxssZR1KVGc4w8 nTcXrrHGxsc512DLt9muuw8aOfa2EhPLbhwK+kDqN1gi4wRx1mk/AqEU4ekvtK628SHb 1wMEXfB2WL8azEn4deqVIjvwjCVwLgv2acQN+dTVBcjkCcE9uiAX+QwUoZlP97AeB7G2 ABdQ== X-Gm-Message-State: APf1xPANBwd+UVHl0dArPP2scTTtRTFpvNN9x9eGdblwhRsNv+Y7qKC3 q9TA3Uk5Lvkhvkg1fPnqLOw= X-Received: by 10.99.137.195 with SMTP id v186mr2882916pgd.90.1519223455446; Wed, 21 Feb 2018 06:30:55 -0800 (PST) Received: from localhost.localdomain (114-32-235-24.HINET-IP.hinet.net. [114.32.235.24]) by smtp.gmail.com with ESMTPSA id v186sm62142068pfb.5.2018.02.21.06.30.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 21 Feb 2018 06:30:54 -0800 (PST) From: ShuFanLee To: heikki.krogerus@linux.intel.com, linux@roeck-us.net, greg@kroah.com Cc: shufan_lee@richtek.com, cy_huang@richtek.com, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org Subject: [PATCH v3] 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 Date: Wed, 21 Feb 2018 22:30:34 +0800 Message-Id: <1519223434-7396-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 Signed-off-by: ShuFanLee --- drivers/staging/typec/tcpci.c | 128 +++++++++++++++++++++++++++++++++--------- drivers/staging/typec/tcpci.h | 13 +++++ 2 files changed, 115 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 - Disable IRQs and request threaded IRQ before registering tcpci port diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..4959c69 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,8 +102,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: @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, 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 +196,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 +351,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 +381,15 @@ 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; + + return tcpci_irq(tcpci); +} + +irqreturn_t tcpci_irq(struct tcpci *tcpci) +{ u16 status; tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +455,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 +479,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 +507,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..40025b2 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); +irqreturn_t tcpci_irq(struct tcpci *tcpci); + #endif /* __LINUX_USB_TCPCI_H */ -- 1.9.1