From patchwork Mon Mar 18 16:22:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hung-ying Tyan X-Patchwork-Id: 228682 X-Patchwork-Delegate: promsoft@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id C05432C00B1 for ; Tue, 19 Mar 2013 03:30:36 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 395804A048; Mon, 18 Mar 2013 17:30:33 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id aPwF2psQnWx9; Mon, 18 Mar 2013 17:30:33 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 054BD4A032; Mon, 18 Mar 2013 17:30:32 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id EF93A4A032 for ; Mon, 18 Mar 2013 17:30:23 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VPlkFBisKps6 for ; Mon, 18 Mar 2013 17:30:21 +0100 (CET) X-Greylist: delayed 408 seconds by postgrey-1.27 at theia; Mon, 18 Mar 2013 17:30:18 CET X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-qa0-f73.google.com (mail-qa0-f73.google.com [209.85.216.73]) by theia.denx.de (Postfix) with ESMTPS id DDA784A02A for ; Mon, 18 Mar 2013 17:30:17 +0100 (CET) Received: by mail-qa0-f73.google.com with SMTP id g10so304333qah.0 for ; Mon, 18 Mar 2013 09:30:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:x-gm-message-state; bh=KXCdwk2AIxaSsN9aiOcEysLNVgFB8NBgFcm1Y6MxtNo=; b=gH11a/hXAe9CHqACAxiuPzvf9oGB8IJhGGNBBigKYO5IeJdFDE+epPEny2gKp0ORwt TwHzxP68Mygryz+0btqGTSb430JyVm7Qwct8IMMnXGpFvmfDoNdqd6i8rsjEBvi1J+n6 4xZSGlu6FctJP7sdG2SWIBkaXlRmkfcYJ1890eAo0EyD8qSJQWB2+TUt+zxVmZRDbaqA gG16/qzVLR+2uIsqISRjqsv7acR2EOCgU3ScpisEENf5KZhTd3OegTtTp/Ft74OtPdGQ TXkCt2oZskEooJujGdooV8iePEgu8fZivtc69VHLuKMyvDYLMQKRfUllPy7BJ4Y6VACQ a5fw== X-Received: by 10.58.127.196 with SMTP id ni4mr13124533veb.5.1363623805245; Mon, 18 Mar 2013 09:23:25 -0700 (PDT) Received: from corp2gmr1-1.hot.corp.google.com (corp2gmr1-1.hot.corp.google.com [172.24.189.92]) by gmr-mx.google.com with ESMTPS id t30si2020720yhi.6.2013.03.18.09.23.25 (version=TLSv1.1 cipher=AES128-SHA bits=128/128); Mon, 18 Mar 2013 09:23:25 -0700 (PDT) Received: from tyanh-z620.tpe.corp.google.com (tyanh-z620.tpe.corp.google.com [172.30.210.193]) by corp2gmr1-1.hot.corp.google.com (Postfix) with ESMTP id BE60F31C1EC; Mon, 18 Mar 2013 09:23:24 -0700 (PDT) Received: by tyanh-z620.tpe.corp.google.com (Postfix, from userid 30259) id 096C1E0645; Tue, 19 Mar 2013 00:23:23 +0800 (CST) From: Hung-ying Tyan To: U-Boot Mailing List Date: Tue, 19 Mar 2013 00:22:02 +0800 Message-Id: <1363623727-22073-3-git-send-email-tyanh@chromium.org> X-Mailer: git-send-email 1.8.1.3 In-Reply-To: <1363623727-22073-1-git-send-email-tyanh@chromium.org> References: <1363623727-22073-1-git-send-email-tyanh@chromium.org> X-Gm-Message-State: ALoCoQnuRuSo0Aq2cuRZc3ptRTPUzaZBQp8ckR1nIK5v3Ar1elVhxPvi9xs6EiceJ0BKZh0npgA0X/8ISdBKatiCEiAbX4Xaczb2oBGpegtuh2MuOjnuF+6VMjMF707RLoZYbEHcuLGd82FnAfDJ046u6MS8l1WCIWrYLBDI76+V+2DE3W9zTg/REq5gSHIPsUCcabY8Wok/ Cc: Tom Rini , Randall Spangler Subject: [U-Boot] [PATCH v2 2/7] cros: add I2C support for cros_ec X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This patch adds I2C support for carrying out the cros_ec protocol. Signed-off-by: Randall Spangler Signed-off-by: Simon Glass Signed-off-by: Hung-ying Tyan Acked-by: Simon Glass --- Changes in v2: - Wrapped lines to comply with the 80-char rule. drivers/misc/Makefile | 1 + drivers/misc/cros_ec_i2c.c | 199 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 drivers/misc/cros_ec_i2c.c diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 33fe822..9363ef9 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o COBJS-$(CONFIG_GPIO_LED) += gpio_led.o COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o COBJS-$(CONFIG_CROS_EC) += cros_ec.o +COBJS-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o COBJS-$(CONFIG_NS87308) += ns87308.o COBJS-$(CONFIG_PDSP188x) += pdsp188x.o COBJS-$(CONFIG_STATUS_LED) += status_led.o diff --git a/drivers/misc/cros_ec_i2c.c b/drivers/misc/cros_ec_i2c.c new file mode 100644 index 0000000..b0060ac --- /dev/null +++ b/drivers/misc/cros_ec_i2c.c @@ -0,0 +1,199 @@ +/* + * Chromium OS cros_ec driver - I2C interface + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include +#include +#include + +#ifdef DEBUG_TRACE +#define debug_trace(fmt, b...) debug(fmt, #b) +#else +#define debug_trace(fmt, b...) +#endif + +int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len) +{ + int old_bus = 0; + /* version8, cmd8, arglen8, out8[dout_len], csum8 */ + int out_bytes = dout_len + 4; + /* response8, arglen8, in8[din_len], checksum8 */ + int in_bytes = din_len + 3; + uint8_t *ptr; + /* Receive input data, so that args will be dword aligned */ + uint8_t *in_ptr; + int ret; + + old_bus = i2c_get_bus_num(); + + /* + * Sanity-check I/O sizes given transaction overhead in internal + * buffers. + */ + if (out_bytes > sizeof(dev->dout)) { + debug("%s: Cannot send %d bytes\n", __func__, dout_len); + return -1; + } + if (in_bytes > sizeof(dev->din)) { + debug("%s: Cannot receive %d bytes\n", __func__, din_len); + return -1; + } + assert(dout_len >= 0); + assert(dinp); + + /* + * Copy command and data into output buffer so we can do a single I2C + * burst transaction. + */ + ptr = dev->dout; + + /* + * in_ptr starts of pointing to a dword-aligned input data buffer. + * We decrement it back by the number of header bytes we expect to + * receive, so that the first parameter of the resulting input data + * will be dword aligned. + */ + in_ptr = dev->din + sizeof(int64_t); + if (!dev->cmd_version_is_supported) { + /* Send an old-style command */ + *ptr++ = cmd; + out_bytes = dout_len + 1; + in_bytes = din_len + 2; + in_ptr--; /* Expect just a status byte */ + } else { + *ptr++ = EC_CMD_VERSION0 + cmd_version; + *ptr++ = cmd; + *ptr++ = dout_len; + in_ptr -= 2; /* Expect status, length bytes */ + } + memcpy(ptr, dout, dout_len); + ptr += dout_len; + + if (dev->cmd_version_is_supported) + *ptr++ = (uint8_t) + cros_ec_calc_checksum(dev->dout, dout_len + 3); + + /* Set to the proper i2c bus */ + if (i2c_set_bus_num(dev->bus_num)) { + debug("%s: Cannot change to I2C bus %d\n", __func__, + dev->bus_num); + return -1; + } + + /* Send output data */ + cros_ec_dump_data("out", -1, dev->dout, out_bytes); + ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes); + if (ret) { + debug("%s: Cannot complete I2C write to 0x%x\n", + __func__, dev->addr); + ret = -1; + } + + if (!ret) { + ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes); + if (ret) { + debug("%s: Cannot complete I2C read from 0x%x\n", + __func__, dev->addr); + ret = -1; + } + } + + /* Return to original bus number */ + i2c_set_bus_num(old_bus); + if (ret) + return ret; + + if (*in_ptr != EC_RES_SUCCESS) { + debug("%s: Received bad result code %d\n", __func__, *in_ptr); + return -(int)*in_ptr; + } + + if (dev->cmd_version_is_supported) { + int len, csum; + + len = in_ptr[1]; + if (len + 3 > sizeof(dev->din)) { + debug("%s: Received length %#02x too large\n", + __func__, len); + return -1; + } + csum = cros_ec_calc_checksum(in_ptr, 2 + len); + if (csum != in_ptr[2 + len]) { + debug("%s: Invalid checksum rx %#02x, calced %#02x\n", + __func__, in_ptr[2 + din_len], csum); + return -1; + } + din_len = min(din_len, len); + cros_ec_dump_data("in", -1, in_ptr, din_len + 3); + } else { + cros_ec_dump_data("in (old)", -1, in_ptr, in_bytes); + } + + /* Return pointer to dword-aligned input data, if any */ + *dinp = dev->din + sizeof(int64_t); + + return din_len; +} + +int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob) +{ + /* Decode interface-specific FDT params */ + dev->max_frequency = fdtdec_get_int(blob, dev->node, + "i2c-max-frequency", 100000); + dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node); + if (dev->bus_num == -1) { + debug("%s: Failed to read bus number\n", __func__); + return -1; + } + dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1); + if (dev->addr == -1) { + debug("%s: Failed to read device address\n", __func__); + return -1; + } + + return 0; +} + +/** + * Initialize I2C protocol. + * + * @param dev CROS_EC device + * @param blob Device tree blob + * @return 0 if ok, -1 on error + */ +int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob) +{ + i2c_init(dev->max_frequency, dev->addr); + + dev->cmd_version_is_supported = 0; + + return 0; +}