Received: by 10.223.185.116 with SMTP id b49csp449222wrg; Wed, 14 Feb 2018 01:25:33 -0800 (PST) X-Google-Smtp-Source: AH8x2279eOU9shcfckTeRux66PBHCzB4uSbrIzTRO4OI2+MwM0tVHpBvuVFLQ8BM336ndH0aDzW2 X-Received: by 10.99.174.7 with SMTP id q7mr3393003pgf.170.1518600333322; Wed, 14 Feb 2018 01:25:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518600333; cv=none; d=google.com; s=arc-20160816; b=lZWHcnaFvoNL71ecjHDcsyuHbhQ8Gzm8NZHUeoaZ7lIGlElfev76tatdxiYkuBIAnG luGtBbwHYLTyvLfCnjl6Z8UpBR8DoXtfJIZYHuWvXxAzVlZ891oZzzibefi0JrcJMPBC b+0jaV/h26JHeFX35QsoW2SDTPS7mw4Xl8i2Z67BF/paqs1oYG/jUIjj2J5Kxt8ceaiZ CDRBvGkQzu9BgGBdpS7muHyZi5yDhBPtkXxR19koZF+WvjepPch5z+FDSoXCI9CAVJ1q VABKg7xyFwK/1Db9ep9i5G2xC20YU9AR4bWofDuErKUG6/EFgtLGpWeHFDt9DThAXaG8 gGMQ== 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=0KKJhzDz8pvjUaphTcU2Zag2Y2iw6NEJrXzza3bQG00=; b=w4T3NugpDIs5tX4F68y8CEyS86gPVLPeOIPQB2WqHh19nrPQAsFCLQM3v8No5hhhro tC8T72t7Qh2eOIyESa6DdImp4jTwxpa1MH6BQpjGGky1itO7dQolHvAAsR2YD6+xQccO 6oOkKBQsXFuI0MFGYAKN6KpPs1EWFRuKU8hjBUiDfVfawjSfmA0H4utHsWfrpCvLHP3/ XtY7htZaKY0UqLFAfw7cqyF56AOPNsYaJn4i0yxso8fs9jnYfLEvjySEldrsMHNMjKa9 bnD6Cd++tonRWfnpHha7nR+QFA6nh92i/Cem+V+dTvdrl132OeV5485G0RNdPmOhinoP goiQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=OOzVRDOe; 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 j11si1932010pgp.468.2018.02.14.01.25.18; Wed, 14 Feb 2018 01:25:33 -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=OOzVRDOe; 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 S966763AbeBNJYh (ORCPT + 99 others); Wed, 14 Feb 2018 04:24:37 -0500 Received: from mail-pl0-f68.google.com ([209.85.160.68]:34731 "EHLO mail-pl0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S966405AbeBNJYf (ORCPT ); Wed, 14 Feb 2018 04:24:35 -0500 Received: by mail-pl0-f68.google.com with SMTP id bd10so3377704plb.1; Wed, 14 Feb 2018 01:24:35 -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=0KKJhzDz8pvjUaphTcU2Zag2Y2iw6NEJrXzza3bQG00=; b=OOzVRDOeC/6pks0H6TmnAekDdbLtZiB2S8IOWotR3d729jXMjq5Hyepvc0zSbJvde5 bSYSkgPAY43a8pSVgf98CjOl/2wZ6uWuVNVg+xGSXAg3/HzdtacpjDPdd4IiuhZVx8pg 9PT4y+0/ocfTnYpX0sL898vaVWzJEcwbJD18da0X77ZlOt3LYQzecTrnNTBPS/WLrMR9 3GlOTQgwlj+tDA5sz1dZCQtcxbm3kaQiWA6tWjBfB0f+HMqWngisTHITQu4BD8XT2NJT CGwCEH4djEjGimWgvm9h4gaNEsgM47DJW82Qn3litwgxmlb5peGLWAr91zmJLU3ezuUv YOVw== 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=0KKJhzDz8pvjUaphTcU2Zag2Y2iw6NEJrXzza3bQG00=; b=R2OloCzb77U/nx65r4lC+bthmuMyJv+B/8Qv1KNZ+tmQttWEUqn8NSczbXFiOskwSM Y1NY9AOyQ5ChsK095iGvjImMTKf2ZCliD+tU1oN14axE1uL3apApSFH/bsTBmWEFt5W6 73WlaliS6eyFk3+mw9+oEktuW+AQbb4wW7bvcSQOkjZuHm6mhKpvnjwK2MORySn7GMd9 JGHL5rEohcxB2+c3gzqqUSKsJEsdm2iAWTe+2pEVWv51VRd8V2O9zGYfayB96li4hRmO zadIpEe9KUlGpeysl6/tpaIU79VBci83+Wf8kpDggCXyK6Yzx6jxQwgD4EP+x45fFgaK wwjw== X-Gm-Message-State: APf1xPCcelA9/P6x3bJj9GuGUcrxgMcg3Z2pc3HvQjSdefgf4wUU5Bip BlBSmBTGh34SmMCEYxa6dcFsjoxDPwA= X-Received: by 2002:a17:902:8544:: with SMTP id d4-v6mr3917009plo.312.1518600274971; Wed, 14 Feb 2018 01:24:34 -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 81sm17394087pfu.117.2018.02.14.01.24.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 14 Feb 2018 01:24:33 -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] staging: typec: handle vendor defined part and modify drp toggling flow Date: Wed, 14 Feb 2018 17:24:04 +0800 Message-Id: <1518600244-29949-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 and tcpci_irq. More operations can be extended in tcpci_vendor_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 | 98 ++++++++++++++++++++++++++++++++++++------- drivers/staging/typec/tcpci.h | 15 +++++++ 2 files changed, 97 insertions(+), 16 deletions(-) diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 9bd4412..b3a97b3 100644 --- a/drivers/staging/typec/tcpci.c +++ b/drivers/staging/typec/tcpci.c @@ -30,6 +30,7 @@ struct tcpci { bool controls_vbus; struct tcpc_dev tcpc; + struct tcpci_vendor_data *vdata; }; static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -37,16 +38,29 @@ 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) +int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val) { return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); } +EXPORT_SYMBOL_GPL(tcpci_read16); -static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val) +int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val) { return regmap_raw_write(tcpci->regmap, reg, &val, sizeof(u16)); } +EXPORT_SYMBOL_GPL(tcpci_write16); + +int tcpci_read8(struct tcpci *tcpci, unsigned int reg, u8 *val) +{ + return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u8)); +} +EXPORT_SYMBOL_GPL(tcpci_read8); + +int tcpci_write8(struct tcpci *tcpci, unsigned int reg, u8 val) +{ + return regmap_raw_write(tcpci->regmap, reg, &val, sizeof(u8)); +} +EXPORT_SYMBOL_GPL(tcpci_write8); static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) { @@ -98,8 +112,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 +132,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) @@ -323,6 +350,15 @@ static int tcpci_init(struct tcpc_dev *tcpc) if (time_after(jiffies, timeout)) return -ETIMEDOUT; + /* Handle vendor init */ + if (tcpci->vdata) { + if (tcpci->vdata->init) { + ret = (*tcpci->vdata->init)(tcpci, tcpci->vdata); + if (ret < 0) + return ret; + } + } + /* Clear all events */ ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff); if (ret < 0) @@ -351,6 +387,13 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) tcpci_read16(tcpci, TCPC_ALERT, &status); + /* Handle vendor defined interrupt */ + if (tcpci->vdata) { + if (tcpci->vdata->irq_handler) + (*tcpci->vdata->irq_handler)(tcpci, tcpci->vdata, + &status); + } + /* * Clear alert status for everything except RX_STATUS, which shouldn't * be cleared until we have successfully retrieved message. @@ -417,7 +460,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id) .reg_bits = 8, .val_bits = 8, - .max_register = 0x7F, /* 0x80 .. 0xFF are vendor defined */ + .max_register = 0xFF, /* 0x80 .. 0xFF are vendor defined */ }; static const struct tcpc_config tcpci_tcpc_config = { @@ -435,22 +478,22 @@ 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 i2c_client *client, + struct tcpci_vendor_data *vdata) { struct tcpci *tcpci; int err; tcpci = devm_kzalloc(&client->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->vdata = vdata; tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config); if (IS_ERR(tcpci->regmap)) - return PTR_ERR(tcpci->regmap); + return ERR_CAST(tcpci->regmap); tcpci->tcpc.init = tcpci_init; tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,7 +510,7 @@ 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); @@ -477,17 +520,40 @@ static int tcpci_probe(struct i2c_client *client, IRQF_ONESHOT | IRQF_TRIGGER_LOW, dev_name(tcpci->dev), tcpci); if (err < 0) - return err; + return ERR_PTR(err); tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); - return PTR_ERR_OR_ZERO(tcpci->port); + 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; + + tcpci = tcpci_register_port(client, NULL); + if (PTR_ERR_OR_ZERO(tcpci)) + return PTR_ERR(tcpci); + + 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..b1fcb4a 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_vendor_data { + int (*init)(struct tcpci *tcpci, struct tcpci_vendor_data *data); + int (*irq_handler)(struct tcpci *tcpci, struct tcpci_vendor_data *data, + u16 *status); +}; + +int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val); +int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val); +int tcpci_read8(struct tcpci *tcpci, unsigned int reg, u8 *val); +int tcpci_write8(struct tcpci *tcpci, unsigned int reg, u8 val); +struct tcpci *tcpci_register_port(struct i2c_client *client, + struct tcpci_vendor_data *data); +void tcpci_unregister_port(struct tcpci *tcpci); #endif /* __LINUX_USB_TCPCI_H */ -- 1.9.1