summaryrefslogtreecommitdiff
path: root/driver/fpc1140.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/fpc1140.c')
-rw-r--r--driver/fpc1140.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/driver/fpc1140.c b/driver/fpc1140.c
index edeeb6bd36..05094eb713 100644
--- a/driver/fpc1140.c
+++ b/driver/fpc1140.c
@@ -9,11 +9,18 @@
#include "ec_commands.h"
#include "endian.h"
#include "gpio.h"
+#include "host_command.h"
#include "mkbp_event.h"
#include "spi.h"
+#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
+#ifdef HAVE_PRIVATE
+#include "fpc1145_private.h"
+
+uint8_t fp_buffer[FPC_IMAGE_SIZE];
+#endif
#define CPRINTF(format, args...) cprintf(CC_FP, format, ## args)
#define CPRINTS(format, args...) cprints(CC_FP, format, ## args)
@@ -36,6 +43,13 @@ enum fpc_cmd {
#endif
static uint32_t fp_events;
+static uint32_t sensor_mode;
+
+/* Opaque sensor configuration registers settings */
+static union {
+ struct ec_params_fp_sensor_config sensor_config;
+ uint8_t data[0x220];
+} u;
static int fpc_send_cmd(const uint8_t cmd)
{
@@ -86,6 +100,9 @@ static uint8_t fpc_read_int(void)
/* Reset and initialize the sensor IC */
static int fpc_init(void)
{
+#ifdef HAVE_PRIVATE
+ memcpy(&u.sensor_config, &fpc1145_config, fpc1145_config_size);
+#endif
/* configure the SPI controller (also ensure that CS_N is high) */
gpio_config_module(MODULE_SPI_MASTER, 1);
spi_enable(CONFIG_SPI_FP_PORT, 1);
@@ -149,3 +166,125 @@ static int fp_get_next_event(uint8_t *out)
return sizeof(event_out);
}
DECLARE_EVENT_SOURCE(EC_MKBP_EVENT_FINGERPRINT, fp_get_next_event);
+
+static int fp_command_passthru(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_fp_passthru *params = args->params;
+ void *out = args->response;
+ int rc;
+ int ret = EC_RES_SUCCESS;
+
+ if (system_is_locked())
+ return EC_RES_ACCESS_DENIED;
+
+ if (params->len > args->params_size +
+ offsetof(struct ec_params_fp_passthru, data) ||
+ params->len > args->response_max)
+ return EC_RES_INVALID_PARAM;
+
+ rc = spi_transaction_async(&spi_devices[0], params->data,
+ params->len, out, SPI_READBACK_ALL);
+ if (params->flags & EC_FP_FLAG_NOT_COMPLETE)
+ rc |= spi_transaction_wait(&spi_devices[0]);
+ else
+ rc |= spi_transaction_flush(&spi_devices[0]);
+
+ if (rc == EC_ERROR_TIMEOUT)
+ ret = EC_RES_TIMEOUT;
+ else if (rc)
+ ret = EC_RES_ERROR;
+
+ args->response_size = params->len;
+ return ret;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_PASSTHRU, fp_command_passthru, EC_VER_MASK(0));
+
+static int fp_command_sensor_config(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_fp_sensor_config *p = args->params;
+ int i, index;
+ unsigned limit = args->params_size
+ - offsetof(struct ec_params_fp_sensor_config, data);
+
+ /* Validate the content size */
+ if (p->count > EC_FP_SENSOR_CONFIG_MAX_REGS ||
+ args->params_size > sizeof(u))
+ return EC_RES_INVALID_PARAM;
+ for (i = 0, index = 0; i < p->count; i++) {
+ if (index + p->len[i] > limit)
+ return EC_RES_INVALID_PARAM;
+ index += p->len[i];
+ }
+
+ memcpy(&u.sensor_config, p, args->params_size);
+
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_SENSOR_CONFIG, fp_command_sensor_config,
+ EC_VER_MASK(0));
+
+static int fp_command_mode(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_fp_mode *p = args->params;
+ struct ec_response_fp_mode *r = args->response;
+
+ if (!(p->mode & FP_MODE_DONT_CHANGE)) {
+ sensor_mode = p->mode;
+ if (p->mode & FP_MODE_DEEPSLEEP) {
+ /* TBD fpc_send_cmd(FPC_CMD_DEEPSLEEP) */;
+ } else {
+ if (p->mode & FP_MODE_FINGER_DOWN)
+ /* TBD: fp_prepare_capture()*/;
+ if (p->mode & FP_MODE_FINGER_UP)
+ /* TBD */;
+ }
+ }
+
+ r->mode = sensor_mode;
+ args->response_size = sizeof(*r);
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_MODE, fp_command_mode, EC_VER_MASK(0));
+
+static int fp_command_info(struct host_cmd_handler_args *args)
+{
+ struct ec_response_fp_info *r = args->response;
+ int rc;
+ const uint8_t cmd = FPC_CMD_HW_ID;
+ uint16_t id;
+ int ret = EC_RES_SUCCESS;
+
+#ifdef HAVE_PRIVATE
+ memcpy(r, &fpc1145_info, sizeof(*r));
+#else
+ return EC_RES_UNAVAILABLE;
+#endif
+ rc = spi_transaction(SPI_FPC_DEVICE, &cmd, 1, (void *)&id, sizeof(id));
+ if (rc)
+ return EC_RES_ERROR;
+ r->model_id = be16toh(id);
+
+ args->response_size = sizeof(*r);
+ return ret;
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_INFO, fp_command_info, EC_VER_MASK(0));
+
+static int fp_command_frame(struct host_cmd_handler_args *args)
+{
+#ifdef HAVE_PRIVATE
+ const struct ec_params_fp_frame *params = args->params;
+ void *out = args->response;
+
+ if (params->offset + params->size > sizeof(fp_buffer) ||
+ params->size > args->response_max)
+ return EC_RES_INVALID_PARAM;
+
+ memcpy(out, fp_buffer + params->offset, params->size);
+
+ args->response_size = params->size;
+ return EC_RES_SUCCESS;
+#else
+ return EC_RES_UNAVAILABLE;
+#endif
+}
+DECLARE_HOST_COMMAND(EC_CMD_FP_FRAME, fp_command_frame, EC_VER_MASK(0));