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