1 /* 2 * Chromium OS cros_ec driver - I2C interface 3 * 4 * Copyright (c) 2012 The Chromium OS Authors. 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 /* 25 * The Matrix Keyboard Protocol driver handles talking to the keyboard 26 * controller chip. Mostly this is for keyboard functions, but some other 27 * things have slipped in, so we provide generic services to talk to the 28 * KBC. 29 */ 30 31 #include <common.h> 32 #include <i2c.h> 33 #include <cros_ec.h> 34 35 #ifdef DEBUG_TRACE 36 #define debug_trace(fmt, b...) debug(fmt, #b) 37 #else 38 #define debug_trace(fmt, b...) 39 #endif 40 41 int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, 42 const uint8_t *dout, int dout_len, 43 uint8_t **dinp, int din_len) 44 { 45 int old_bus = 0; 46 /* version8, cmd8, arglen8, out8[dout_len], csum8 */ 47 int out_bytes = dout_len + 4; 48 /* response8, arglen8, in8[din_len], checksum8 */ 49 int in_bytes = din_len + 3; 50 uint8_t *ptr; 51 /* Receive input data, so that args will be dword aligned */ 52 uint8_t *in_ptr; 53 int ret; 54 55 old_bus = i2c_get_bus_num(); 56 57 /* 58 * Sanity-check I/O sizes given transaction overhead in internal 59 * buffers. 60 */ 61 if (out_bytes > sizeof(dev->dout)) { 62 debug("%s: Cannot send %d bytes\n", __func__, dout_len); 63 return -1; 64 } 65 if (in_bytes > sizeof(dev->din)) { 66 debug("%s: Cannot receive %d bytes\n", __func__, din_len); 67 return -1; 68 } 69 assert(dout_len >= 0); 70 assert(dinp); 71 72 /* 73 * Copy command and data into output buffer so we can do a single I2C 74 * burst transaction. 75 */ 76 ptr = dev->dout; 77 78 /* 79 * in_ptr starts of pointing to a dword-aligned input data buffer. 80 * We decrement it back by the number of header bytes we expect to 81 * receive, so that the first parameter of the resulting input data 82 * will be dword aligned. 83 */ 84 in_ptr = dev->din + sizeof(int64_t); 85 if (!dev->cmd_version_is_supported) { 86 /* Send an old-style command */ 87 *ptr++ = cmd; 88 out_bytes = dout_len + 1; 89 in_bytes = din_len + 2; 90 in_ptr--; /* Expect just a status byte */ 91 } else { 92 *ptr++ = EC_CMD_VERSION0 + cmd_version; 93 *ptr++ = cmd; 94 *ptr++ = dout_len; 95 in_ptr -= 2; /* Expect status, length bytes */ 96 } 97 memcpy(ptr, dout, dout_len); 98 ptr += dout_len; 99 100 if (dev->cmd_version_is_supported) 101 *ptr++ = (uint8_t) 102 cros_ec_calc_checksum(dev->dout, dout_len + 3); 103 104 /* Set to the proper i2c bus */ 105 if (i2c_set_bus_num(dev->bus_num)) { 106 debug("%s: Cannot change to I2C bus %d\n", __func__, 107 dev->bus_num); 108 return -1; 109 } 110 111 /* Send output data */ 112 cros_ec_dump_data("out", -1, dev->dout, out_bytes); 113 ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes); 114 if (ret) { 115 debug("%s: Cannot complete I2C write to 0x%x\n", 116 __func__, dev->addr); 117 ret = -1; 118 } 119 120 if (!ret) { 121 ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes); 122 if (ret) { 123 debug("%s: Cannot complete I2C read from 0x%x\n", 124 __func__, dev->addr); 125 ret = -1; 126 } 127 } 128 129 /* Return to original bus number */ 130 i2c_set_bus_num(old_bus); 131 if (ret) 132 return ret; 133 134 if (*in_ptr != EC_RES_SUCCESS) { 135 debug("%s: Received bad result code %d\n", __func__, *in_ptr); 136 return -(int)*in_ptr; 137 } 138 139 if (dev->cmd_version_is_supported) { 140 int len, csum; 141 142 len = in_ptr[1]; 143 if (len + 3 > sizeof(dev->din)) { 144 debug("%s: Received length %#02x too large\n", 145 __func__, len); 146 return -1; 147 } 148 csum = cros_ec_calc_checksum(in_ptr, 2 + len); 149 if (csum != in_ptr[2 + len]) { 150 debug("%s: Invalid checksum rx %#02x, calced %#02x\n", 151 __func__, in_ptr[2 + din_len], csum); 152 return -1; 153 } 154 din_len = min(din_len, len); 155 cros_ec_dump_data("in", -1, in_ptr, din_len + 3); 156 } else { 157 cros_ec_dump_data("in (old)", -1, in_ptr, in_bytes); 158 } 159 160 /* Return pointer to dword-aligned input data, if any */ 161 *dinp = dev->din + sizeof(int64_t); 162 163 return din_len; 164 } 165 166 int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob) 167 { 168 /* Decode interface-specific FDT params */ 169 dev->max_frequency = fdtdec_get_int(blob, dev->node, 170 "i2c-max-frequency", 100000); 171 dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node); 172 if (dev->bus_num == -1) { 173 debug("%s: Failed to read bus number\n", __func__); 174 return -1; 175 } 176 dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1); 177 if (dev->addr == -1) { 178 debug("%s: Failed to read device address\n", __func__); 179 return -1; 180 } 181 182 return 0; 183 } 184 185 /** 186 * Initialize I2C protocol. 187 * 188 * @param dev CROS_EC device 189 * @param blob Device tree blob 190 * @return 0 if ok, -1 on error 191 */ 192 int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob) 193 { 194 i2c_init(dev->max_frequency, dev->addr); 195 196 dev->cmd_version_is_supported = 0; 197 198 return 0; 199 } 200