summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/cros_ec.c122
-rw-r--r--drivers/misc/cros_ec_sandbox.c99
-rw-r--r--drivers/misc/cros_ec_spi.c87
3 files changed, 280 insertions, 28 deletions
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 068373b942..521edfd5de 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -16,6 +16,7 @@
#include <common.h>
#include <command.h>
+#include <dm.h>
#include <i2c.h>
#include <cros_ec.h>
#include <fdtdec.h>
@@ -24,6 +25,8 @@
#include <asm/errno.h>
#include <asm/io.h>
#include <asm-generic/gpio.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
#ifdef DEBUG_TRACE
#define debug_trace(fmt, b...) debug(fmt, #b)
@@ -38,7 +41,9 @@ enum {
CROS_EC_CMD_HASH_TIMEOUT_MS = 2000,
};
+#ifndef CONFIG_DM_CROS_EC
static struct cros_ec_dev static_dev, *last_dev;
+#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -204,6 +209,9 @@ static int send_command_proto3(struct cros_ec_dev *dev,
const void *dout, int dout_len,
uint8_t **dinp, int din_len)
{
+#ifdef CONFIG_DM_CROS_EC
+ struct dm_cros_ec_ops *ops;
+#endif
int out_bytes, in_bytes;
int rv;
@@ -218,6 +226,10 @@ static int send_command_proto3(struct cros_ec_dev *dev,
if (in_bytes < 0)
return in_bytes;
+#ifdef CONFIG_DM_CROS_EC
+ ops = dm_cros_ec_get_ops(dev->dev);
+ rv = ops->packet(dev->dev, out_bytes, in_bytes);
+#else
switch (dev->interface) {
#ifdef CONFIG_CROS_EC_SPI
case CROS_EC_IF_SPI:
@@ -235,6 +247,7 @@ static int send_command_proto3(struct cros_ec_dev *dev,
debug("%s: Unsupported interface\n", __func__);
rv = -1;
}
+#endif
if (rv < 0)
return rv;
@@ -246,6 +259,9 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
const void *dout, int dout_len,
uint8_t **dinp, int din_len)
{
+#ifdef CONFIG_DM_CROS_EC
+ struct dm_cros_ec_ops *ops;
+#endif
int ret = -1;
/* Handle protocol version 3 support */
@@ -254,6 +270,11 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
dout, dout_len, dinp, din_len);
}
+#ifdef CONFIG_DM_CROS_EC
+ ops = dm_cros_ec_get_ops(dev->dev);
+ ret = ops->command(dev->dev, cmd, cmd_version,
+ (const uint8_t *)dout, dout_len, dinp, din_len);
+#else
switch (dev->interface) {
#ifdef CONFIG_CROS_EC_SPI
case CROS_EC_IF_SPI:
@@ -280,6 +301,7 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
default:
ret = -1;
}
+#endif
return ret;
}
@@ -990,6 +1012,7 @@ int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
return 0;
}
+#ifndef CONFIG_DM_CROS_EC
/**
* Decode EC interface details from the device tree and allocate a suitable
* device.
@@ -1055,11 +1078,61 @@ static int cros_ec_decode_fdt(const void *blob, int node,
return 0;
}
+#endif
-int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_register(struct udevice *dev)
{
+ struct cros_ec_dev *cdev = dev->uclass_priv;
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
char id[MSG_BYTES];
+
+ cdev->dev = dev;
+ fdtdec_decode_gpio(blob, node, "ec-interrupt", &cdev->ec_int);
+ cdev->optimise_flash_write = fdtdec_get_bool(blob, node,
+ "optimise-flash-write");
+
+ /* we will poll the EC interrupt line */
+ fdtdec_setup_gpio(&cdev->ec_int);
+ if (fdt_gpio_isvalid(&cdev->ec_int)) {
+ gpio_request(cdev->ec_int.gpio, "cros-ec-irq");
+ gpio_direction_input(cdev->ec_int.gpio);
+ }
+
+ if (cros_ec_check_version(cdev)) {
+ debug("%s: Could not detect CROS-EC version\n", __func__);
+ return -CROS_EC_ERR_CHECK_VERSION;
+ }
+
+ if (cros_ec_read_id(cdev, id, sizeof(id))) {
+ debug("%s: Could not read KBC ID\n", __func__);
+ return -CROS_EC_ERR_READ_ID;
+ }
+
+ /* Remember this device for use by the cros_ec command */
+ debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
+
+ return 0;
+}
+#else
+int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
+{
struct cros_ec_dev *dev;
+ char id[MSG_BYTES];
+#ifdef CONFIG_DM_CROS_EC
+ struct udevice *udev;
+ int ret;
+
+ ret = uclass_find_device(UCLASS_CROS_EC, 0, &udev);
+ if (!ret)
+ device_remove(udev);
+ ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
+ if (ret)
+ return ret;
+ dev = udev->uclass_priv;
+ return 0;
+#else
int node = 0;
*cros_ecp = NULL;
@@ -1108,11 +1181,14 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
default:
return 0;
}
+#endif
/* we will poll the EC interrupt line */
fdtdec_setup_gpio(&dev->ec_int);
- if (fdt_gpio_isvalid(&dev->ec_int))
+ if (fdt_gpio_isvalid(&dev->ec_int)) {
+ gpio_request(dev->ec_int.gpio, "cros-ec-irq");
gpio_direction_input(dev->ec_int.gpio);
+ }
if (cros_ec_check_version(dev)) {
debug("%s: Could not detect CROS-EC version\n", __func__);
@@ -1125,11 +1201,15 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
}
/* Remember this device for use by the cros_ec command */
- last_dev = *cros_ecp = dev;
+ *cros_ecp = dev;
+#ifndef CONFIG_DM_CROS_EC
+ last_dev = dev;
+#endif
debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id);
return 0;
}
+#endif
int cros_ec_decode_region(int argc, char * const argv[])
{
@@ -1147,15 +1227,10 @@ int cros_ec_decode_region(int argc, char * const argv[])
return -1;
}
-int cros_ec_decode_ec_flash(const void *blob, struct fdt_cros_ec *config)
+int cros_ec_decode_ec_flash(const void *blob, int node,
+ struct fdt_cros_ec *config)
{
- int flash_node, node;
-
- node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC);
- if (node < 0) {
- debug("Failed to find chrome-ec node'\n");
- return -1;
- }
+ int flash_node;
flash_node = fdt_subnode_offset(blob, node, "flash");
if (flash_node < 0) {
@@ -1516,7 +1591,10 @@ static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag,
static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- struct cros_ec_dev *dev = last_dev;
+ struct cros_ec_dev *dev;
+#ifdef CONFIG_DM_CROS_EC
+ struct udevice *udev;
+#endif
const char *cmd;
int ret = 0;
@@ -1525,19 +1603,31 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
cmd = argv[1];
if (0 == strcmp("init", cmd)) {
+#ifndef CONFIG_DM_CROS_EC
ret = cros_ec_init(gd->fdt_blob, &dev);
if (ret) {
printf("Could not init cros_ec device (err %d)\n", ret);
return 1;
}
+#endif
return 0;
}
+#ifdef CONFIG_DM_CROS_EC
+ ret = uclass_get_device(UCLASS_CROS_EC, 0, &udev);
+ if (ret) {
+ printf("Cannot get cros-ec device (err=%d)\n", ret);
+ return 1;
+ }
+ dev = udev->uclass_priv;
+#else
/* Just use the last allocated device; there should be only one */
if (!last_dev) {
printf("No CROS-EC device available\n");
return 1;
}
+ dev = last_dev;
+#endif
if (0 == strcmp("id", cmd)) {
char id[MSG_BYTES];
@@ -1794,3 +1884,11 @@ U_BOOT_CMD(
"crosec i2c mw chip address[.0, .1, .2] value [count] - write to I2C passthru (fill)"
);
#endif
+
+#ifdef CONFIG_DM_CROS_EC
+UCLASS_DRIVER(cros_ec) = {
+ .id = UCLASS_CROS_EC,
+ .name = "cros_ec",
+ .per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
+};
+#endif
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index 8a04af557d..99cc5297cf 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -8,6 +8,7 @@
#include <common.h>
#include <cros_ec.h>
+#include <dm.h>
#include <ec_commands.h>
#include <errno.h>
#include <hash.h>
@@ -85,7 +86,7 @@ struct ec_state {
struct ec_keymatrix_entry *matrix; /* the key matrix info */
uint8_t keyscan[KEYBOARD_COLS];
bool recovery_req;
-} s_state, *state;
+} s_state, *g_state;
/**
* cros_ec_read_state() - read the sandbox EC state from the state file
@@ -138,7 +139,7 @@ static int cros_ec_read_state(const void *blob, int node)
*/
static int cros_ec_write_state(void *blob, int node)
{
- struct ec_state *ec = &s_state;
+ struct ec_state *ec = g_state;
/* We are guaranteed enough space to write basic properties */
fdt_setprop_u32(blob, node, "current-image", ec->current_image);
@@ -369,7 +370,7 @@ static int process_cmd(struct ec_state *ec,
struct fmap_entry *entry;
int ret, size;
- entry = &state->ec_config.region[EC_FLASH_REGION_RW];
+ entry = &ec->ec_config.region[EC_FLASH_REGION_RW];
switch (req->cmd) {
case EC_VBOOT_HASH_RECALC:
@@ -426,7 +427,7 @@ static int process_cmd(struct ec_state *ec,
case EC_FLASH_REGION_RO:
case EC_FLASH_REGION_RW:
case EC_FLASH_REGION_WP_RO:
- entry = &state->ec_config.region[req->region];
+ entry = &ec->ec_config.region[req->region];
resp->offset = entry->offset;
resp->size = entry->length;
len = sizeof(*resp);
@@ -466,16 +467,24 @@ static int process_cmd(struct ec_state *ec,
return len;
}
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_sandbox_packet(struct udevice *udev, int out_bytes, int in_bytes)
+{
+ struct cros_ec_dev *dev = udev->uclass_priv;
+ struct ec_state *ec = dev_get_priv(dev->dev);
+#else
int cros_ec_sandbox_packet(struct cros_ec_dev *dev, int out_bytes,
int in_bytes)
{
+ struct ec_state *ec = &s_state;
+#endif
struct ec_host_request *req_hdr = (struct ec_host_request *)dev->dout;
const void *req_data = req_hdr + 1;
struct ec_host_response *resp_hdr = (struct ec_host_response *)dev->din;
void *resp_data = resp_hdr + 1;
int len;
- len = process_cmd(&s_state, req_hdr, req_data, resp_hdr, resp_data);
+ len = process_cmd(ec, req_hdr, req_data, resp_hdr, resp_data);
if (len < 0)
return len;
@@ -498,7 +507,11 @@ int cros_ec_sandbox_decode_fdt(struct cros_ec_dev *dev, const void *blob)
void cros_ec_check_keyboard(struct cros_ec_dev *dev)
{
+#ifdef CONFIG_DM_CROS_EC
+ struct ec_state *ec = dev_get_priv(dev->dev);
+#else
struct ec_state *ec = &s_state;
+#endif
ulong start;
printf("Press keys for EC to detect on reset (ESC=recovery)...");
@@ -512,6 +525,52 @@ void cros_ec_check_keyboard(struct cros_ec_dev *dev)
}
}
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_probe(struct udevice *dev)
+{
+ struct ec_state *ec = dev->priv;
+ struct cros_ec_dev *cdev = dev->uclass_priv;
+ const void *blob = gd->fdt_blob;
+ int node;
+ int err;
+
+ memcpy(ec, &s_state, sizeof(*ec));
+ err = cros_ec_decode_ec_flash(blob, dev->of_offset, &ec->ec_config);
+ if (err)
+ return err;
+
+ node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB);
+ if (node < 0) {
+ debug("%s: No cros_ec keyboard found\n", __func__);
+ } else if (keyscan_read_fdt_matrix(ec, blob, node)) {
+ debug("%s: Could not read key matrix\n", __func__);
+ return -1;
+ }
+
+ /* If we loaded EC data, check that the length matches */
+ if (ec->flash_data &&
+ ec->flash_data_len != ec->ec_config.flash.length) {
+ printf("EC data length is %x, expected %x, discarding data\n",
+ ec->flash_data_len, ec->ec_config.flash.length);
+ os_free(ec->flash_data);
+ ec->flash_data = NULL;
+ }
+
+ /* Otherwise allocate the memory */
+ if (!ec->flash_data) {
+ ec->flash_data_len = ec->ec_config.flash.length;
+ ec->flash_data = os_malloc(ec->flash_data_len);
+ if (!ec->flash_data)
+ return -ENOMEM;
+ }
+
+ cdev->dev = dev;
+ g_state = ec;
+ return cros_ec_register(dev);
+}
+
+#else
+
/**
* Initialize sandbox EC emulation.
*
@@ -525,8 +584,13 @@ int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob)
int node;
int err;
- state = &s_state;
- err = cros_ec_decode_ec_flash(blob, &ec->ec_config);
+ node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC);
+ if (node < 0) {
+ debug("Failed to find chrome-ec node'\n");
+ return -1;
+ }
+
+ err = cros_ec_decode_ec_flash(blob, node, &ec->ec_config);
if (err)
return err;
@@ -557,3 +621,24 @@ int cros_ec_sandbox_init(struct cros_ec_dev *dev, const void *blob)
return 0;
}
+#endif
+
+#ifdef CONFIG_DM_CROS_EC
+struct dm_cros_ec_ops cros_ec_ops = {
+ .packet = cros_ec_sandbox_packet,
+};
+
+static const struct udevice_id cros_ec_ids[] = {
+ { .compatible = "google,cros-ec" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_sandbox) = {
+ .name = "cros_ec",
+ .id = UCLASS_CROS_EC,
+ .of_match = cros_ec_ids,
+ .probe = cros_ec_probe,
+ .priv_auto_alloc_size = sizeof(struct ec_state),
+ .ops = &cros_ec_ops,
+};
+#endif
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index 015333f139..e403664bb5 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -15,23 +15,34 @@
#include <common.h>
#include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
#include <spi.h>
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
+{
+ struct cros_ec_dev *dev = udev->uclass_priv;
+#else
int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
{
+#endif
+ struct spi_slave *slave = dev_get_parentdata(dev->dev);
int rv;
/* Do the transfer */
- if (spi_claim_bus(dev->spi)) {
+ if (spi_claim_bus(slave)) {
debug("%s: Cannot claim SPI bus\n", __func__);
return -1;
}
- rv = spi_xfer(dev->spi, max(out_bytes, in_bytes) * 8,
+ rv = spi_xfer(slave, max(out_bytes, in_bytes) * 8,
dev->dout, dev->din,
SPI_XFER_BEGIN | SPI_XFER_END);
- spi_release_bus(dev->spi);
+ spi_release_bus(slave);
if (rv) {
debug("%s: Cannot complete SPI transfer\n", __func__);
@@ -56,10 +67,19 @@ int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
* @param din_len Maximum size of response in bytes
* @return number of bytes in response, or -1 on error
*/
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_spi_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 = udev->uclass_priv;
+#else
int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len)
{
+#endif
+ struct spi_slave *slave = dev_get_parentdata(dev->dev);
int in_bytes = din_len + 4; /* status, length, checksum, trailer */
uint8_t *out;
uint8_t *p;
@@ -92,7 +112,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
*/
memset(dev->din, '\0', in_bytes);
- if (spi_claim_bus(dev->spi)) {
+ if (spi_claim_bus(slave)) {
debug("%s: Cannot claim SPI bus\n", __func__);
return -1;
}
@@ -113,10 +133,10 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
p = dev->din + sizeof(int64_t) - 2;
len = dout_len + 4;
cros_ec_dump_data("out", cmd, out, len);
- rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p,
+ rv = spi_xfer(slave, max(len, in_bytes) * 8, out, p,
SPI_XFER_BEGIN | SPI_XFER_END);
- spi_release_bus(dev->spi);
+ spi_release_bus(slave);
if (rv) {
debug("%s: Cannot complete SPI transfer\n", __func__);
@@ -146,6 +166,7 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
return len;
}
+#ifndef CONFIG_DM_CROS_EC
int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
{
/* Decode interface-specific FDT params */
@@ -165,11 +186,59 @@ int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
*/
int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
{
- dev->spi = spi_setup_slave_fdt(blob, dev->node, dev->parent_node);
- if (!dev->spi) {
+ int ret;
+
+ ret = spi_setup_slave_fdt(blob, dev->node, dev->parent_node,
+ &slave);
+ if (ret) {
debug("%s: Could not setup SPI slave\n", __func__);
- return -1;
+ return ret;
}
return 0;
}
+#endif
+
+#ifdef CONFIG_DM_CROS_EC
+int cros_ec_probe(struct udevice *dev)
+{
+ struct spi_slave *slave = dev_get_parentdata(dev);
+ int ret;
+
+ /*
+ * TODO(sjg@chromium.org)
+ *
+ * This is really horrible at present. It is an artifact of removing
+ * the child_pre_probe() method for SPI. Everything here could go in
+ * an automatic function, except that spi_get_bus_and_cs() wants to
+ * set it up manually and call device_probe_child().
+ *
+ * The solution may be to re-enable the child_pre_probe() method for
+ * SPI and have it do nothing if the child is already passed in via
+ * device_probe_child().
+ */
+ slave->dev = dev;
+ ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
+ if (ret)
+ return ret;
+ return cros_ec_register(dev);
+}
+
+struct dm_cros_ec_ops cros_ec_ops = {
+ .packet = cros_ec_spi_packet,
+ .command = cros_ec_spi_command,
+};
+
+static const struct udevice_id cros_ec_ids[] = {
+ { .compatible = "google,cros-ec" },
+ { }
+};
+
+U_BOOT_DRIVER(cros_ec_spi) = {
+ .name = "cros_ec",
+ .id = UCLASS_CROS_EC,
+ .of_match = cros_ec_ids,
+ .probe = cros_ec_probe,
+ .ops = &cros_ec_ops,
+};
+#endif