CHROMIUM: mfd: chromeos_ec: support command version numbers
authorChe-Liang Chiou <clchiou@chromium.org>
Wed, 7 Nov 2012 00:45:06 +0000 (16:45 -0800)
committerGerrit <chrome-bot@google.com>
Thu, 15 Nov 2012 23:25:50 +0000 (15:25 -0800)
ec supports versioned command and non-versioned command should be
deprecated.  To minimize changes to ec clients, driver will accept not
8-bits but 16-bits command code and interpret top 8-bits as version
number.  Because current ec clients all use commands of version-zero,
they will not be effected by this API change.

BUG=chrome-os-partner:15609
TEST=manual, add debugging sysfs entry to exercise kernel code path, and
     make sure ec driver still works on snow.

Change-Id: I640e7756baddd20d8bc14c7f8ba10c13e60ed8ff
Signed-off-by: Che-Liang Chiou <clchiou@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/37496
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/mfd/chromeos_ec.c
drivers/mfd/chromeos_ec_i2c.c
include/linux/mfd/chromeos_ec.h

index 80a2199..ecefbd7 100644 (file)
@@ -46,34 +46,32 @@ int cros_ec_prepare_tx(struct chromeos_ec_device *ec_dev,
        return EC_MSG_TX_PROTO_BYTES + msg->out_len;
 }
 
-static int cros_ec_command_recv(struct chromeos_ec_device *ec_dev,
-                                char cmd, void *buf, int buf_len)
+static int cros_ec_command_sendrecv(struct chromeos_ec_device *ec_dev,
+               uint16_t cmd, void *out_buf, int out_len,
+               void *in_buf, int in_len)
 {
        struct chromeos_ec_msg msg;
 
-       msg.version = 0;
-       msg.cmd = cmd;
-       msg.in_buf = buf;
-       msg.in_len = buf_len;
-       msg.out_buf = NULL;
-       msg.out_len = 0;
+       msg.version = cmd >> 8;
+       msg.cmd = cmd & 0xff;
+       msg.out_buf = out_buf;
+       msg.out_len = out_len;
+       msg.in_buf = in_buf;
+       msg.in_len = in_len;
 
        return ec_dev->command_xfer(ec_dev, &msg);
 }
 
-static int cros_ec_command_send(struct chromeos_ec_device *ec_dev,
-                                char cmd, void *buf, int buf_len)
+static int cros_ec_command_recv(struct chromeos_ec_device *ec_dev,
+               uint16_t cmd, void *buf, int buf_len)
 {
-       struct chromeos_ec_msg msg;
-
-       msg.version = 0;
-       msg.cmd = cmd;
-       msg.out_buf = buf;
-       msg.out_len = buf_len;
-       msg.in_buf = NULL;
-       msg.in_len = 0;
+       return cros_ec_command_sendrecv(ec_dev, cmd, NULL, 0, buf, buf_len);
+}
 
-       return ec_dev->command_xfer(ec_dev, &msg);
+static int cros_ec_command_send(struct chromeos_ec_device *ec_dev,
+               uint16_t cmd, void *buf, int buf_len)
+{
+       return cros_ec_command_sendrecv(ec_dev, cmd, buf, buf_len, NULL, 0);
 }
 
 struct chromeos_ec_device *__devinit cros_ec_alloc(const char *name)
@@ -147,6 +145,7 @@ int __devinit cros_ec_register(struct chromeos_ec_device *ec_dev)
 
        ec_dev->command_send = cros_ec_command_send;
        ec_dev->command_recv = cros_ec_command_recv;
+       ec_dev->command_sendrecv = cros_ec_command_sendrecv;
 
        if (ec_dev->din_size) {
                ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL);
index 363ce35..f1fe6e8 100644 (file)
@@ -61,43 +61,39 @@ static int cros_ec_command_xfer_noretry(struct chromeos_ec_device *ec_dev,
        i2c_msg[1].addr = client->addr;
        i2c_msg[1].flags = I2C_M_RD;
 
-       if (msg->in_len) {
-               /* allocate larger packet
-                * (one byte for checksum, one for result code)
-                */
-               packet_len = msg->in_len + 2;
-               in_buf = kzalloc(packet_len, GFP_KERNEL);
-               if (!in_buf)
-                       goto done;
-               i2c_msg[1].len = packet_len;
-               i2c_msg[1].buf = (char *)in_buf;
-       } else {
-               i2c_msg[1].len = 1;
-               i2c_msg[1].buf = (char *)&res_code;
-       }
+       /*
+        * allocate larger packet (one byte for checksum, one byte for
+        * length, and one for result code)
+        */
+       packet_len = msg->in_len + 3;
+       in_buf = kzalloc(packet_len, GFP_KERNEL);
+       if (!in_buf)
+               goto done;
+       i2c_msg[1].len = packet_len;
+       i2c_msg[1].buf = (char *)in_buf;
 
-       if (msg->out_len) {
-               /* allocate larger packet
-                * (one byte for checksum, one for command code)
-                */
-               packet_len = msg->out_len + 2;
-               out_buf = kzalloc(packet_len, GFP_KERNEL);
-               if (!out_buf)
-                       goto done;
-               i2c_msg[0].len = packet_len;
-               i2c_msg[0].buf = (char *)out_buf;
-               out_buf[0] = msg->cmd;
-
-               /* copy message payload and compute checksum */
-               for (i = 0, sum = 0; i < msg->out_len; i++) {
-                       out_buf[i + 1] = msg->out_buf[i];
-                       sum += out_buf[i + 1];
-               }
-               out_buf[msg->out_len + 1] = sum;
-       } else {
-               i2c_msg[0].len = 1;
-               i2c_msg[0].buf = (char *)&msg->cmd;
+       /*
+        * allocate larger packet (one byte for checksum, one for
+        * command code, one for length, and one for command version)
+        */
+       packet_len = msg->out_len + 4;
+       out_buf = kzalloc(packet_len, GFP_KERNEL);
+       if (!out_buf)
+               goto done;
+       i2c_msg[0].len = packet_len;
+       i2c_msg[0].buf = (char *)out_buf;
+
+       out_buf[0] = EC_CMD_VERSION0 + msg->version;
+       out_buf[1] = msg->cmd;
+       out_buf[2] = msg->out_len;
+
+       /* copy message payload and compute checksum */
+       sum = out_buf[0] + out_buf[1] + out_buf[2];
+       for (i = 0; i < msg->out_len; i++) {
+               out_buf[3 + i] = msg->out_buf[i];
+               sum += out_buf[3 + i];
        }
+       out_buf[3 + msg->out_len] = sum;
 
        /* send command to EC and read answer */
        ret = i2c_transfer(client->adapter, i2c_msg, 2);
@@ -117,23 +113,23 @@ static int cros_ec_command_xfer_noretry(struct chromeos_ec_device *ec_dev,
                ret = -EINVAL;
                goto done;
        }
-       if (msg->in_len) {
-               /* copy response packet payload and compute checksum */
-               for (i = 0, sum = 0; i < msg->in_len; i++) {
-                       msg->in_buf[i] = in_buf[i + 1];
-                       sum += in_buf[i + 1];
-               }
+
+       /* copy response packet payload and compute checksum */
+       sum = in_buf[0] + in_buf[1];
+       for (i = 0; i < msg->in_len; i++) {
+               msg->in_buf[i] = in_buf[2 + i];
+               sum += in_buf[2 + i];
+       }
 #ifdef DEBUG
-               dev_dbg(ec_dev->dev, "packet: ");
-               for (i = 0; i < i2c_msg[1].len; i++)
-                       printk(" %02x", in_buf[i]);
-               printk(", sum = %02x\n", sum);
+       dev_dbg(ec_dev->dev, "packet: ");
+       for (i = 0; i < i2c_msg[1].len; i++)
+               printk(KERN_CONT " %02x", in_buf[i]);
+       printk(KERN_CONT ", sum = %02x\n", sum);
 #endif
-               if (sum != in_buf[msg->in_len + 1]) {
-                       dev_err(ec_dev->dev, "bad packet checksum\n");
-                       ret = -EBADMSG;
-                       goto done;
-               }
+       if (sum != in_buf[2 + msg->in_len]) {
+               dev_err(ec_dev->dev, "bad packet checksum\n");
+               ret = -EBADMSG;
+               goto done;
        }
 
        ret = 0;
index 1114746..8a379bb 100644 (file)
@@ -68,9 +68,12 @@ struct chromeos_ec_device {
        int din_size;           /* Size of din buffer */
        int dout_size;          /* Size of dout buffer */
        int (*command_send)(struct chromeos_ec_device *ec,
-                       char cmd, void *out_buf, int out_len);
+                       uint16_t cmd, void *out_buf, int out_len);
        int (*command_recv)(struct chromeos_ec_device *ec,
-                       char cmd, void *in_buf, int in_len);
+                       uint16_t cmd, void *in_buf, int in_len);
+       int (*command_sendrecv)(struct chromeos_ec_device *ec,
+                       uint16_t cmd, void *out_buf, int out_len,
+                       void *in_buf, int in_len);
        int (*command_xfer)(struct chromeos_ec_device *ec,
                        struct chromeos_ec_msg *msg);
        int (*command_i2c)(struct chromeos_ec_device *ec,