Source
x
// SPDX-License-Identifier: GPL-2.0+
/*
* Chromium OS cros_ec driver - LPC interface
*
* Copyright (c) 2012 The Chromium OS Authors.
*/
/*
* 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.
*/
static int wait_for_sync(struct cros_ec_dev *dev)
{
unsigned long start;
start = get_timer(0);
while (inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK) {
if (get_timer(start) > 1000) {
debug("%s: Timeout waiting for CROS_EC sync\n",
__func__);
return -1;
}
}
return 0;
}
int cros_ec_lpc_packet(struct udevice *udev, int out_bytes, int in_bytes)
{
struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
uint8_t *d;
int i;
if (out_bytes > EC_LPC_HOST_PACKET_SIZE)
return log_msg_ret("Cannot send that many bytes\n", -E2BIG);
if (in_bytes > EC_LPC_HOST_PACKET_SIZE)
return log_msg_ret("Cannot receive that many bytes\n", -E2BIG);
if (wait_for_sync(dev))
return log_msg_ret("Timeout waiting ready\n", -ETIMEDOUT);
/* Write data */
for (i = 0, d = (uint8_t *)dev->dout; i < out_bytes; i++, d++)
outb(*d, EC_LPC_ADDR_HOST_PACKET + i);
/* Start the command */
outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD);
if (wait_for_sync(dev))
return log_msg_ret("Timeout waiting ready\n", -ETIMEDOUT);
/* Read back args */
for (i = 0, d = dev->din; i < in_bytes; i++, d++)
*d = inb(EC_LPC_ADDR_HOST_PACKET + i);
return in_bytes;
}
int cros_ec_lpc_command(struct udevice *udev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len)
{
struct cros_ec_dev *dev = dev_get_uclass_priv(udev);
const int cmd_addr = EC_LPC_ADDR_HOST_CMD;
const int data_addr = EC_LPC_ADDR_HOST_DATA;
const int args_addr = EC_LPC_ADDR_HOST_ARGS;
const int param_addr = EC_LPC_ADDR_HOST_PARAM;
struct ec_lpc_host_args args;
uint8_t *d;
int csum;
int i;
if (dout_len > EC_PROTO2_MAX_PARAM_SIZE) {
debug("%s: Cannot send %d bytes\n", __func__, dout_len);
return -1;