summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabe Black <gabeblack@google.com>2013-06-28 14:24:33 -0700
committerStefan Reinauer <stefan.reinauer@coreboot.org>2013-07-10 23:18:30 +0200
commit9f96aa6b5e6bc5af8feb7bb29239f8421ded1f14 (patch)
tree2ef6a5a9bf7f316e62a1232c04154c5d24e3a5dd /src
parent2b3167908be680b5aa1cd6fe2f42a44d4c118f3f (diff)
chromeec: Add a function to send passthrough i2c messages.
Change-Id: I576d0dbf65693f40d7d1c20d3d5e7a75b8e14dc9 Signed-off-by: Gabe Black <gabeblack@google.com> Reviewed-on: http://review.coreboot.org/3752 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src')
-rw-r--r--src/ec/google/chromeec/ec.c88
-rw-r--r--src/ec/google/chromeec/ec.h2
2 files changed, 90 insertions, 0 deletions
diff --git a/src/ec/google/chromeec/ec.c b/src/ec/google/chromeec/ec.c
index 9b848c06c2..7546a82ee8 100644
--- a/src/ec/google/chromeec/ec.c
+++ b/src/ec/google/chromeec/ec.c
@@ -136,6 +136,94 @@ void google_chromeec_early_init(void)
#ifndef __PRE_RAM__
+int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
+ uint8_t *buffer, int len, int is_read)
+{
+ union {
+ struct ec_params_i2c_passthru p;
+ uint8_t outbuf[EC_HOST_PARAM_SIZE];
+ } params;
+ union {
+ struct ec_response_i2c_passthru r;
+ uint8_t inbuf[EC_HOST_PARAM_SIZE];
+ } response;
+ struct ec_params_i2c_passthru *p = &params.p;
+ struct ec_response_i2c_passthru *r = &response.r;
+ struct ec_params_i2c_passthru_msg *msg = p->msg;
+ struct chromeec_command cmd;
+ uint8_t *pdata;
+ int read_len, write_len;
+ int size;
+ int rv;
+
+ p->port = 0;
+
+ if (alen != 1) {
+ printk(BIOS_ERR, "Unsupported address length %d\n", alen);
+ return -1;
+ }
+ if (is_read) {
+ read_len = len;
+ write_len = alen;
+ p->num_msgs = 2;
+ } else {
+ read_len = 0;
+ write_len = alen + len;
+ p->num_msgs = 1;
+ }
+
+ size = sizeof(*p) + p->num_msgs * sizeof(*msg);
+ if (size + write_len > sizeof(params)) {
+ printk(BIOS_ERR, "Params too large for buffer\n");
+ return -1;
+ }
+ if (sizeof(*r) + read_len > sizeof(response)) {
+ printk(BIOS_ERR, "Read length too big for buffer\n");
+ return -1;
+ }
+
+ /* Create a message to write the register address and optional data */
+ pdata = (uint8_t *)p + size;
+ msg->addr_flags = chip;
+ msg->len = write_len;
+ pdata[0] = addr;
+ if (!is_read)
+ memcpy(pdata + 1, buffer, len);
+ msg++;
+
+ if (read_len) {
+ msg->addr_flags = chip | EC_I2C_FLAG_READ;
+ msg->len = read_len;
+ }
+
+ cmd.cmd_code = EC_CMD_I2C_PASSTHRU;
+ cmd.cmd_version = 0;
+ cmd.cmd_data_in = p;
+ cmd.cmd_size_in = size + write_len;
+ cmd.cmd_data_out = r;
+ cmd.cmd_size_out = sizeof(*r) + read_len;
+ rv = google_chromeec_command(&cmd);
+ if (rv != 0)
+ return rv;
+
+ /* Parse response */
+ if (r->i2c_status & EC_I2C_STATUS_ERROR) {
+ printk(BIOS_ERR, "Transfer failed with status=0x%x\n",
+ r->i2c_status);
+ return -1;
+ }
+
+ if (cmd.cmd_size_out < sizeof(*r) + read_len) {
+ printk(BIOS_ERR, "Truncated read response\n");
+ return -1;
+ }
+
+ if (read_len)
+ memcpy(buffer, r->data, read_len);
+
+ return 0;
+}
+
static int google_chromeec_set_mask(u8 type, u32 mask)
{
struct ec_params_host_event_mask req;
diff --git a/src/ec/google/chromeec/ec.h b/src/ec/google/chromeec/ec.h
index 356d2d215d..f661d311a8 100644
--- a/src/ec/google/chromeec/ec.h
+++ b/src/ec/google/chromeec/ec.h
@@ -25,6 +25,8 @@
#include <stdint.h>
#ifndef __PRE_RAM__
+int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
+ uint8_t *buffer, int len, int is_read);
u32 google_chromeec_get_wake_mask(void);
int google_chromeec_set_sci_mask(u32 mask);
int google_chromeec_set_smi_mask(u32 mask);