Received: by 2002:a25:e7d8:0:0:0:0:0 with SMTP id e207csp1924390ybh; Fri, 13 Mar 2020 09:45:35 -0700 (PDT) X-Google-Smtp-Source: ADFU+vvAiLVXmrtwpgHLGK0DhV2YunN52GYYPBXu+CwEpLQGXq61rEVLkAuwau2RVYNxAL0v8YvS X-Received: by 2002:aca:ac46:: with SMTP id v67mr7775603oie.62.1584117935755; Fri, 13 Mar 2020 09:45:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1584117935; cv=none; d=google.com; s=arc-20160816; b=BhpfJa60X+2aROi13XQGDyT3w4aPqCho8+m51uDMXDbmb7m3Jk3XjjJj9z7fFsnbVo 6EAaRjNH8p0Lts9z5Wc5y2j73qWaWHOtpBypyQ3TQd46yJaNfvUwzJxWkpmuA7wO3hoU 7X/yMc0MyCI9/jmmg7War37+UOwVlXLsYXAWOBNm+HbNjZa0t+uZ8lee/uxyJawJu4m7 jGxcmPUYQ/teZtf04Qx80OjMk6ObiNRHqTYiw5ID9Yk8IWbgBAqweHDHkclDd7TWqfiP ynzOg9warBAP9Y+VeCWVXGyE4rQEqK1Dz0fX7lNRmCdsIF1D2A5Ukym1jY+CtZY1WE3j JEFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject; bh=Om9MAi/vqm/OVMTFQ9IdoNv1IY/4ExJpzf31itcvRIA=; b=iTNTv/rZDR0+Qry4nm9YiqStcjDOBTwBZ86GrSeDzMap1JbtQAl+nQa4AO3E0pKLSy cnRDlPgLUvKbGh4oqU1Qu/gI4KKOSyRKEDWgmla9sW9P1tRQHHM7TwrvTbjoquCcWBLr IA5xjxAUwbiimbtFF/xZF0r55bbGfTaVjqbfpyYJu6b4SI3evnmnmIpqCfaj+PioEU3u oi/OqeCrLspoO/CamuHC7jM9r5aWgeQxVpDsqyFovWFexAOjJS7JNziGEr8OHK8oIW0+ xK591C60lrE3Q29Z1oFWjbrfnjudjpgLjpfQTS9L10zz8OhIhPyjBq/fU1/2JjU25/fC wnow== ARC-Authentication-Results: i=1; mx.google.com; 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=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j17si4590022otl.278.2020.03.13.09.45.22; Fri, 13 Mar 2020 09:45:35 -0700 (PDT) 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; 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=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726622AbgCMQo4 (ORCPT + 99 others); Fri, 13 Mar 2020 12:44:56 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:55150 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726526AbgCMQo4 (ORCPT ); Fri, 13 Mar 2020 12:44:56 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: eballetbo) with ESMTPSA id BD27F2970C0 Subject: Re: [PATCH v4 2/4] platform/chrome: Add Type C connector class driver To: Prashant Malani , linux-kernel@vger.kernel.org Cc: Benson Leung , "open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS" , Guenter Roeck , Mark Rutland , Rob Herring References: <20200312225719.14753-1-pmalani@chromium.org> <20200312225719.14753-3-pmalani@chromium.org> From: Enric Balletbo i Serra Message-ID: <790892f8-21f9-eb72-6e39-8d7b252040e8@collabora.com> Date: Fri, 13 Mar 2020 17:44:50 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.5.0 MIME-Version: 1.0 In-Reply-To: <20200312225719.14753-3-pmalani@chromium.org> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Prashant, On 12/3/20 23:57, Prashant Malani wrote: > Add a driver to implement the Type C connector class for Chrome OS > devices with ECs (Embedded Controllers). > > The driver relies on firmware device specifications for various port > attributes. On ACPI platforms, this is specified using the logical > device with HID GOOG0014. On DT platforms, this is specified using the > DT node with compatible string "google,cros-ec-typec". > > The driver reads the device FW node and uses the port attributes to > register the typec ports with the Type C connector class framework, but > doesn't do much else. > > Subsequent patches will add more functionality to the driver, including > obtaining current port information (polarity, vconn role, current power > role etc.) after querying the EC. > > Signed-off-by: Prashant Malani > --- > > Changes in v4: > - Added Reviewed-by tag from previous review cycle Guess that you missed to add it ;-) Reviewed-by: Heikki Krogerus LGTM > - Added code to store port caps within the Cros EC type C data structure > - Added code to use “reg” to get the port-number in DT platforms. > > Changes in v3: > - Fixed minor spacing nits, and moved a modification to probe() if check > from later patch to here instead. > > Changes in v2: > - Updated Kconfig to default to MFD_CROS_EC_DEV. > - Fixed code comments. > - Moved get_num_ports() code into probe(). > - Added module author. > > drivers/platform/chrome/Kconfig | 11 ++ > drivers/platform/chrome/Makefile | 1 + > drivers/platform/chrome/cros_ec_typec.c | 238 ++++++++++++++++++++++++ > 3 files changed, 250 insertions(+) > create mode 100644 drivers/platform/chrome/cros_ec_typec.c > > diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig > index 5f57282a28da0..2320a4f0d9301 100644 > --- a/drivers/platform/chrome/Kconfig > +++ b/drivers/platform/chrome/Kconfig > @@ -214,6 +214,17 @@ config CROS_EC_SYSFS > To compile this driver as a module, choose M here: the > module will be called cros_ec_sysfs. > > +config CROS_EC_TYPEC > + tristate "ChromeOS EC Type-C Connector Control" > + depends on MFD_CROS_EC_DEV && TYPEC > + default MFD_CROS_EC_DEV > + help > + If you say Y here, you get support for accessing Type C connector > + information from the Chrome OS EC. > + > + To compile this driver as a module, choose M here: the module will be > + called cros_ec_typec. > + > config CROS_USBPD_LOGGER > tristate "Logging driver for USB PD charger" > depends on CHARGER_CROS_USBPD > diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile > index aacd5920d8a18..caf2a9cdb5e6d 100644 > --- a/drivers/platform/chrome/Makefile > +++ b/drivers/platform/chrome/Makefile > @@ -12,6 +12,7 @@ obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o > obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o > obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o > cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o > +obj-$(CONFIG_CROS_EC_TYPEC) += cros_ec_typec.o > obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o > obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o cros_ec_trace.o > obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o > diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c > new file mode 100644 > index 0000000000000..02e6d5cbbbf7a > --- /dev/null > +++ b/drivers/platform/chrome/cros_ec_typec.c > @@ -0,0 +1,238 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright 2020 Google LLC > + * > + * This driver provides the ability to view and manage Type C ports through the > + * Chrome OS EC. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define DRV_NAME "cros-ec-typec" > + > +/* Platform-specific data for the Chrome OS EC Type C controller. */ > +struct cros_typec_data { > + struct device *dev; > + struct cros_ec_device *ec; > + int num_ports; > + /* Array of ports, indexed by port number. */ > + struct typec_port *ports[EC_USB_PD_MAX_PORTS]; > + /* Initial capabilities for each port. */ > + struct typec_capability *caps[EC_USB_PD_MAX_PORTS]; > +}; > + > +static int cros_typec_parse_port_props(struct typec_capability *cap, > + struct fwnode_handle *fwnode, > + struct device *dev) > +{ > + const char *buf; > + int ret; > + > + memset(cap, 0, sizeof(*cap)); > + ret = fwnode_property_read_string(fwnode, "power-role", &buf); > + if (ret) { > + dev_err(dev, "power-role not found: %d\n", ret); > + return ret; > + } > + > + ret = typec_find_port_power_role(buf); > + if (ret < 0) > + return ret; > + cap->type = ret; > + > + ret = fwnode_property_read_string(fwnode, "data-role", &buf); > + if (ret) { > + dev_err(dev, "data-role not found: %d\n", ret); > + return ret; > + } > + > + ret = typec_find_port_data_role(buf); > + if (ret < 0) > + return ret; > + cap->data = ret; > + > + ret = fwnode_property_read_string(fwnode, "try-power-role", &buf); > + if (ret) { > + dev_err(dev, "try-power-role not found: %d\n", ret); > + return ret; > + } > + > + ret = typec_find_power_role(buf); > + if (ret < 0) > + return ret; > + cap->prefer_role = ret; > + > + cap->fwnode = fwnode; > + > + return 0; > +} > + > +static int cros_typec_init_ports(struct cros_typec_data *typec) > +{ > + struct device *dev = typec->dev; > + struct typec_capability *cap; > + struct fwnode_handle *fwnode; > + const char *port_prop; > + int ret; > + int i; > + int nports; > + u32 port_num = 0; > + > + nports = device_get_child_node_count(dev); > + if (nports == 0) { > + dev_err(dev, "No port entries found.\n"); > + return -ENODEV; > + } > + > + if (nports > typec->num_ports) { > + dev_err(dev, "More ports listed than can be supported.\n"); > + return -EINVAL; > + } > + > + /* DT uses "reg" to specify port number. */ > + port_prop = dev->of_node ? "reg" : "port-number"; > + device_for_each_child_node(dev, fwnode) { > + if (fwnode_property_read_u32(fwnode, port_prop, &port_num)) { > + ret = -EINVAL; > + dev_err(dev, "No port-number for port, aborting.\n"); > + goto unregister_ports; > + } > + > + if (port_num >= typec->num_ports) { > + dev_err(dev, "Invalid port number.\n"); > + ret = -EINVAL; > + goto unregister_ports; > + } > + > + dev_dbg(dev, "Registering port %d\n", port_num); > + > + cap = devm_kzalloc(dev, sizeof(*cap), GFP_KERNEL); > + if (!cap) { > + ret = -ENOMEM; > + goto unregister_ports; > + } > + > + typec->caps[port_num] = cap; > + > + ret = cros_typec_parse_port_props(cap, fwnode, dev); > + if (ret < 0) > + goto unregister_ports; > + > + typec->ports[port_num] = typec_register_port(dev, cap); > + if (IS_ERR(typec->ports[port_num])) { > + dev_err(dev, "Failed to register port %d\n", port_num); > + ret = PTR_ERR(typec->ports[port_num]); > + goto unregister_ports; > + } > + } > + > + return 0; > + > +unregister_ports: > + for (i = 0; i < typec->num_ports; i++) > + typec_unregister_port(typec->ports[i]); > + return ret; > +} > + > +static int cros_typec_ec_command(struct cros_typec_data *typec, > + unsigned int version, > + unsigned int command, > + void *outdata, > + unsigned int outsize, > + void *indata, > + unsigned int insize) > +{ > + struct cros_ec_command *msg; > + int ret; > + > + msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); > + if (!msg) > + return -ENOMEM; > + > + msg->version = version; > + msg->command = command; > + msg->outsize = outsize; > + msg->insize = insize; > + > + if (outsize) > + memcpy(msg->data, outdata, outsize); > + > + ret = cros_ec_cmd_xfer_status(typec->ec, msg); > + if (ret >= 0 && insize) > + memcpy(indata, msg->data, insize); > + > + kfree(msg); > + return ret; > +} > + > +#ifdef CONFIG_ACPI > +static const struct acpi_device_id cros_typec_acpi_id[] = { > + { "GOOG0014", 0 }, > + {} > +}; > +MODULE_DEVICE_TABLE(acpi, cros_typec_acpi_id); > +#endif > + > +#ifdef CONFIG_OF > +static const struct of_device_id cros_typec_of_match[] = { > + { .compatible = "google,cros-ec-typec", }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, cros_typec_of_match); > +#endif > + > +static int cros_typec_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct cros_typec_data *typec; > + struct ec_response_usb_pd_ports resp; > + int ret; > + > + typec = devm_kzalloc(dev, sizeof(*typec), GFP_KERNEL); > + if (!typec) > + return -ENOMEM; > + > + typec->dev = dev; > + typec->ec = dev_get_drvdata(pdev->dev.parent); > + platform_set_drvdata(pdev, typec); > + > + ret = cros_typec_ec_command(typec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, > + &resp, sizeof(resp)); > + if (ret < 0) > + return ret; > + > + typec->num_ports = resp.num_ports; > + if (typec->num_ports > EC_USB_PD_MAX_PORTS) { > + dev_warn(typec->dev, > + "Too many ports reported: %d, limiting to max: %d\n", > + typec->num_ports, EC_USB_PD_MAX_PORTS); > + typec->num_ports = EC_USB_PD_MAX_PORTS; > + } > + > + ret = cros_typec_init_ports(typec); > + if (ret < 0) > + return ret; > + > + return 0; > +} > + > +static struct platform_driver cros_typec_driver = { > + .driver = { > + .name = DRV_NAME, > + .acpi_match_table = ACPI_PTR(cros_typec_acpi_id), > + .of_match_table = of_match_ptr(cros_typec_of_match), > + }, > + .probe = cros_typec_probe, > +}; > + > +module_platform_driver(cros_typec_driver); > + > +MODULE_AUTHOR("Prashant Malani "); > +MODULE_DESCRIPTION("Chrome OS EC Type C control"); > +MODULE_LICENSE("GPL"); >