summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChiehchun Yu <chiehchun.yu@elan.corp-partner.google.com>2020-01-16 14:44:50 +0800
committerCommit Bot <commit-bot@chromium.org>2021-01-12 20:47:52 +0000
commit3775fdbf7e863603eb65ec52348a45d7139db628 (patch)
tree9b9bc902067543a51db1d7772e348a2a15f9e437
parent4167ccc6fc40b865d5eb9f6e13b7a95f9aba0f19 (diff)
downloadchrome-ec-3775fdbf7e863603eb65ec52348a45d7139db628.tar.gz
elan_private: Implement elan sensor driver
This patch provides ELAN FP APIs that used to control ELAN FP sensor and matching algorithm. BRANCH=None BUG=None TEST=We build on nami_fp, and testing Elan sensor with libelan_515.a and libelan_80.a successfully. Change-Id: I7a58025106f8ed570860b758323bf2047cde0731 Signed-off-by: Chiehchun Yu <chiehchun.yu@elan.corp-partner.google.com> Signed-off-by: herman lin <herman.lin@emc.com.tw> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2002994 Reviewed-by: Yicheng Li <yichengli@chromium.org> Tested-by: Yicheng Li <yichengli@chromium.org> Commit-Queue: Yicheng Li <yichengli@chromium.org>
-rw-r--r--driver/fingerprint/build.mk1
-rw-r--r--driver/fingerprint/elan/build.mk20
-rw-r--r--driver/fingerprint/elan/elan_private.c248
-rw-r--r--driver/fingerprint/elan/elan_sensor.h164
-rw-r--r--driver/fingerprint/elan/elan_sensor_pal.c246
-rw-r--r--driver/fingerprint/elan/elan_sensor_pal.h126
-rw-r--r--driver/fingerprint/elan/elan_setting.h101
-rw-r--r--driver/fingerprint/fpsensor.h4
-rw-r--r--include/config.h2
9 files changed, 912 insertions, 0 deletions
diff --git a/driver/fingerprint/build.mk b/driver/fingerprint/build.mk
index 862fa29914..6cb9dc7adb 100644
--- a/driver/fingerprint/build.mk
+++ b/driver/fingerprint/build.mk
@@ -7,4 +7,5 @@
# Note that this variable includes the trailing "/"
_fingerprint_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST)))
+include $(_fingerprint_cur_dir)elan/build.mk
include $(_fingerprint_cur_dir)fpc/build.mk
diff --git a/driver/fingerprint/elan/build.mk b/driver/fingerprint/elan/build.mk
new file mode 100644
index 0000000000..2e4ad2d46f
--- /dev/null
+++ b/driver/fingerprint/elan/build.mk
@@ -0,0 +1,20 @@
+# Copyright 2021 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Build for ELAN fingerprint drivers
+
+# Note that this variable includes the trailing "/"
+_elan_cur_dir:=$(dir $(lastword $(MAKEFILE_LIST)))
+
+ifneq (,$(filter rw,$(CONFIG_FP_SENSOR_ELAN80) $(CONFIG_FP_SENSOR_ELAN515)))
+
+# Make sure output directory is created (in build directory)
+dirs-y+="$(_elan_cur_dir)"
+
+include $(_elan_cur_dir)../../../private/fingerprint/elan/build.mk
+
+all-obj-rw+=$(_elan_cur_dir)elan_private.o
+all-obj-rw+=$(_elan_cur_dir)elan_sensor_pal.o
+
+endif
diff --git a/driver/fingerprint/elan/elan_private.c b/driver/fingerprint/elan/elan_private.c
new file mode 100644
index 0000000000..336542c8f3
--- /dev/null
+++ b/driver/fingerprint/elan/elan_private.c
@@ -0,0 +1,248 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stddef.h>
+#include "common.h"
+#include "console.h"
+#include "endian.h"
+#include "gpio.h"
+#include "link_defs.h"
+#include "spi.h"
+#include "system.h"
+#include "timer.h"
+#include "util.h"
+#include "shared_mem.h"
+#include "math_util.h"
+#include "fpsensor.h"
+#include "cryptoc/util.h"
+
+#include "elan_sensor.h"
+#include "elan_setting.h"
+#include "elan_sensor_pal.h"
+
+extern uint16_t raw[IMAGE_TOTAL_PIXEL];
+static uint16_t errors;
+
+#define CPRINTF(format, args...) cprintf(CC_FP, format, ##args)
+
+/* Sensor description */
+static struct ec_response_fp_info ec_fp_sensor_info = {
+ /* Sensor identification */
+ .vendor_id = VID,
+ .product_id = PID,
+ .model_id = MID,
+ .version = VERSION,
+ /* Image frame characteristics */
+ .frame_size = FP_SENSOR_RES_X * FP_SENSOR_RES_Y,
+ .pixel_format = V4L2_PIX_FMT_GREY,
+ .width = FP_SENSOR_RES_X,
+ .height = FP_SENSOR_RES_Y,
+ .bpp = FP_SENSOR_RES_BPP,
+};
+
+/**
+ * set fingerprint sensor into power saving mode
+ */
+void fp_sensor_low_power(void)
+{
+ elan_woe_mode();
+}
+
+/**
+ * Reset and initialize the sensor IC
+ */
+int fp_sensor_init(void)
+{
+ CPRINTF("========%s=======\n", __func__);
+
+ errors = 0;
+ algorithm_parameter_setting();
+ if (elan_execute_calibration() < 0)
+ errors |= FP_ERROR_INIT_FAIL;
+ if (elan_woe_mode() != 0)
+ errors |= FP_ERROR_SPI_COMM;
+
+ return EC_SUCCESS;
+}
+
+/**
+ * Deinitialize the sensor IC
+ */
+int fp_sensor_deinit(void)
+{
+ CPRINTF("========%s=======\n", __func__);
+ always_memset(raw, 0, sizeof(raw));
+ return EC_SUCCESS;
+}
+
+/**
+ * Fill the 'ec_response_fp_info' buffer with the sensor information
+ *
+ * @param[out] resp retrieve the version, sensor and template information
+ *
+ * @return EC_SUCCESS on success otherwise error.
+ */
+int fp_sensor_get_info(struct ec_response_fp_info *resp)
+{
+ int ret = 0;
+
+ CPRINTF("========%s=======\n", __func__);
+ memcpy(resp, &ec_fp_sensor_info, sizeof(struct ec_response_fp_info));
+ elan_sensor_get_alg_info(resp);
+ resp->errors |= errors;
+ CPRINTF("##%s## FrameSize=%d, errors=0x%04x\n", __func__,
+ resp->frame_size, resp->errors);
+
+ return ret;
+}
+
+/**
+ * Compares given finger image against enrolled templates.
+ *
+ * @param[in] templ a pointer to the array of template buffers.
+ * @param[in] templ_count the number of buffers in the array of templates.
+ * @param[in] image the buffer containing the finger image
+ * @param[out] match_index index of the matched finger in the template
+ * array if any.
+ * @param[out] update_bitmap contains one bit per template, the bit is set if
+ * the match has updated the given template.
+ *
+ * @return negative value on error, else one of the following code :
+ * - EC_MKBP_FP_ERR_MATCH_NO on non-match
+ * - EC_MKBP_FP_ERR_MATCH_YES for match when template was not updated with
+ * new data
+ * - EC_MKBP_FP_ERR_MATCH_YES_UPDATED for match when template was updated
+ * - EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED match, but update failed (not saved)
+ * - EC_MKBP_FP_ERR_MATCH_LOW_QUALITY when matching could not be performed due
+ * to low image quality
+ * - EC_MKBP_FP_ERR_MATCH_LOW_COVERAGE when matching could not be performed
+ * due to finger covering too little area of the sensor
+ */
+int fp_finger_match(void *templ, uint32_t templ_count, uint8_t *image,
+ int32_t *match_index, uint32_t *update_bitmap)
+{
+ CPRINTF("========%s=======\n", __func__);
+ return elan_match(templ, templ_count, image, match_index,
+ update_bitmap);
+}
+
+/**
+ * start a finger enrollment session and initialize enrollment data
+ *
+ * @return 0 on success.
+ *
+ */
+int fp_enrollment_begin(void)
+{
+ CPRINTF("========%s=======\n", __func__);
+ return elan_enrollment_begin();
+}
+
+/**
+ * Generate a template from the finger whose enrollment has just being
+ * completed.
+ *
+ * @param templ the buffer which will receive the template.
+ * templ can be set to NULL to abort the current enrollment
+ * process.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int fp_enrollment_finish(void *templ)
+{
+ CPRINTF("========%s=======\n", __func__);
+ return elan_enrollment_finish(templ);
+}
+
+/**
+ * Adds fingerprint image to the current enrollment session.
+ *
+ * @param[in] image fingerprint image data
+ * @param[out] completion retrieve percentage of current enrollment
+ *
+ * @return a negative value on error or one of the following codes:
+ * - EC_MKBP_FP_ERR_ENROLL_OK when image was successfully enrolled
+ * - EC_MKBP_FP_ERR_ENROLL_IMMOBILE when image added, but user should be
+ * advised to move finger
+ * - EC_MKBP_FP_ERR_ENROLL_LOW_QUALITY when image could not be used due to
+ * low image quality
+ * - EC_MKBP_FP_ERR_ENROLL_LOW_COVERAGE when image could not be used due to
+ * finger covering too little area of the sensor
+ */
+int fp_finger_enroll(uint8_t *image, int *completion)
+{
+ CPRINTF("========%s=======\n", __func__);
+ return elan_enroll(image, completion);
+}
+
+/**
+ * Put the sensor in its lowest power state.
+ *
+ * fp_sensor_configure_detect needs to be called to restore finger detection
+ * functionality.
+ */
+void fp_sensor_configure_detect(void)
+{
+ CPRINTF("========%s=======\n", __func__);
+ elan_woe_mode();
+}
+
+/**
+ * Acquires a fingerprint image with specific capture mode.
+ *
+ * @param[out] image_data Memory buffer to retrieve fingerprint image data
+ * Image_data is allocated by the caller and the size
+ * is FP_SENSOR_IMAGE_SIZE.
+ * @param[in] mode one of the FP_CAPTURE_ constants to get a specific
+ * image type
+ * - FP_CAPTURE_VENDOR_FORMAT: Full blown vendor-defined capture
+ * - FP_CAPTURE_SIMPLE_IMAGE: Simple raw image capture
+ * - FP_CAPTURE_PATTERN0: Self test pattern
+ * - FP_CAPTURE_PATTERN1: Self test pattern
+ * - FP_CAPTURE_QUALITY_TEST
+ * - FP_CAPTURE_RESET_TEST
+ * - FP_CAPTURE_TYPE_MAX
+ *
+ * @return
+ * - 0 on success
+ * - negative value on error
+ * - FP_SENSOR_LOW_IMAGE_QUALITY on image captured but quality is too low
+ * - FP_SENSOR_TOO_FAST on finger removed before image was captured
+ * - FP_SENSOR_LOW_SENSOR_COVERAGE on sensor not fully covered by finger
+ */
+int fp_sensor_acquire_image_with_mode(uint8_t *image_data, int mode)
+{
+ CPRINTF("========%s=======\n", __func__);
+ return elan_sensor_acquire_image_with_mode(image_data, mode);
+}
+
+/**
+ * Returns the status of the finger on the sensor.
+ *
+ * @return one of the following codes:
+ * - FINGER_NONE
+ * - FINGER_PARTIAL
+ * - FINGER_PRESENT
+ */
+enum finger_state fp_sensor_finger_status(void)
+{
+ CPRINTF("========%s=======\n", __func__);
+ return elan_sensor_finger_status();
+}
+
+/**
+ * Runs a test for defective pixels.
+ *
+ * Should be triggered periodically by the client. The maintenance command can
+ * take several hundred milliseconds to run.
+ *
+ * @return EC_ERROR_HW_INTERNAL on error (such as finger on sensor)
+ * @return EC_SUCCESS on success
+ */
+int fp_maintenance(void)
+{
+ CPRINTF("========%s=======\n", __func__);
+ return elan_fp_maintenance(&errors);
+}
diff --git a/driver/fingerprint/elan/elan_sensor.h b/driver/fingerprint/elan/elan_sensor.h
new file mode 100644
index 0000000000..a9cf4e3f72
--- /dev/null
+++ b/driver/fingerprint/elan/elan_sensor.h
@@ -0,0 +1,164 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef CROS_EC_DRIVER_FINGERPRINT_ELAN_ELAN_SENSOR_H
+#define CROS_EC_DRIVER_FINGERPRINT_ELAN_ELAN_SENSOR_H
+#include "common.h"
+
+/* Sensor pixel resolution */
+#if defined(CONFIG_FP_SENSOR_ELAN80)
+#define FP_SENSOR_IMAGE_SIZE (80 * 80)
+#define FP_SENSOR_RES_X 80
+#define FP_SENSOR_RES_Y 80
+#define FP_ALGORITHM_TEMPLATE_SIZE 40960
+#define FP_MAX_FINGER_COUNT 3
+#elif defined(CONFIG_FP_SENSOR_ELAN515)
+#define FP_SENSOR_IMAGE_SIZE (52 * 150)
+#define FP_SENSOR_RES_X 52
+#define FP_SENSOR_RES_Y 150
+#define FP_ALGORITHM_TEMPLATE_SIZE 67000
+#define FP_MAX_FINGER_COUNT 3
+#endif
+#define FP_SENSOR_RES_BPP (8)
+
+/**
+ * Set ELAN fingerprint sensor into finger touch detects and power saving mode
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_woe_mode(void);
+
+/**
+ * Set ELAN fingerprint sensor into the image sensing mode
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_sensing_mode(void);
+
+/**
+ * To initialize parameters of the ELAN matching algorithm
+ *
+ */
+void algorithm_parameter_setting(void);
+
+/**
+ * Compares given finger image against enrolled templates.
+ *
+ * @param[in] templ a pointer to the array of template buffers.
+ * @param[in] templ_count the number of buffers in the array of templates.
+ * @param[in] image the buffer containing the finger image
+ * @param[out] match_index index of the matched finger in the template
+ * array if any.
+ * @param[out] update_bitmap contains one bit per template, the bit is set if
+ * the match has updated the given template.
+ *
+ * @return negative value on error, else one of the following code :
+ * - EC_MKBP_FP_ERR_MATCH_NO on non-match
+ * - EC_MKBP_FP_ERR_MATCH_YES for match when template was not updated with
+ * new data
+ * - EC_MKBP_FP_ERR_MATCH_YES_UPDATED for match when template was updated
+ * - EC_MKBP_FP_ERR_MATCH_YES_UPDATE_FAILED match, but update failed (not saved)
+ * - EC_MKBP_FP_ERR_MATCH_LOW_QUALITY when matching could not be performed due
+ * to low image quality
+ * - EC_MKBP_FP_ERR_MATCH_LOW_COVERAGE when matching could not be performed
+ * due to finger covering too little area of the sensor
+ */
+int elan_match(void *templ, uint32_t templ_count, uint8_t *image,
+ int32_t *match_index, uint32_t *update_bitmap);
+
+/**
+ * start a finger enrollment session and initialize enrollment data
+ *
+ * @return 0 on success.
+ *
+ */
+int elan_enrollment_begin(void);
+
+/**
+ * Adds fingerprint image to the current enrollment session.
+ *
+ * @param[in] image fingerprint image data
+ * @param[out] completion retrieve percentage of current enrollment
+ *
+ * @return a negative value on error or one of the following codes:
+ * - EC_MKBP_FP_ERR_ENROLL_OK when image was successfully enrolled
+ * - EC_MKBP_FP_ERR_ENROLL_IMMOBILE when image added, but user should be
+ advised to move finger
+ * - EC_MKBP_FP_ERR_ENROLL_LOW_QUALITY when image could not be used due to
+ * low image quality
+ * - EC_MKBP_FP_ERR_ENROLL_LOW_COVERAGE when image could not be used due to
+ * finger covering too little area of the sensor
+ */
+int elan_enroll(uint8_t *image, int *completion);
+
+/**
+ * Acquires a fingerprint image with specific capture mode.
+ *
+ * @param[out] image_data Memory buffer to retrieve fingerprint image data
+ * Image_data is allocated by the caller and the size
+ * is FP_SENSOR_IMAGE_SIZE.
+ * @param[in] mode one of the FP_CAPTURE_ constants to get a
+ * specific image type
+ * - FP_CAPTURE_VENDOR_FORMAT: Full blown vendor-defined capture
+ * - FP_CAPTURE_SIMPLE_IMAGE: Simple raw image capture
+ * - FP_CAPTURE_PATTERN0: Self test pattern
+ * - FP_CAPTURE_PATTERN1: Self test pattern
+ * - FP_CAPTURE_QUALITY_TEST
+ * - FP_CAPTURE_RESET_TEST
+ * - FP_CAPTURE_TYPE_MAX
+ *
+ * @return
+ * - 0 on success
+ * - negative value on error
+ * - FP_SENSOR_LOW_IMAGE_QUALITY on image captured but quality is too low
+ * - FP_SENSOR_TOO_FAST on finger removed before image was captured
+ * - FP_SENSOR_LOW_SENSOR_COVERAGE on sensor not fully covered by finger
+ */
+int elan_sensor_acquire_image_with_mode(uint8_t *image_data, int mode);
+
+/**
+ * Returns the status of the finger on the sensor.
+ *
+ * @return one of the following codes:
+ * - FINGER_NONE
+ * - FINGER_PARTIAL
+ * - FINGER_PRESENT
+ */
+enum finger_state elan_sensor_finger_status(void);
+
+/**
+ * Generate a template from the finger whose enrollment has just being
+ * completed.
+ *
+ * @param templ the buffer which will receive the template.
+ * templ can be set to NULL to abort the current enrollment
+ * process.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int elan_enrollment_finish(void *templ);
+
+/**
+ * Fill the 'ec_response_fp_alg_info' buffer with the sensor alg information
+ *
+ * @param[out] resp retrieve the algorithm information
+ *
+ * @return EC_SUCCESS on success otherwise error.
+ */
+int elan_sensor_get_alg_info(struct ec_response_fp_info *resp);
+
+/**
+ * Runs a test for defective pixels.
+ *
+ * Should be triggered periodically by the client. The maintenance command can
+ * take several hundred milliseconds to run.
+ *
+ * @return EC_ERROR_HW_INTERNAL on error (such as finger on sensor)
+ * @return EC_SUCCESS on success
+ */
+int elan_fp_maintenance(uint16_t *error_state);
+#endif
diff --git a/driver/fingerprint/elan/elan_sensor_pal.c b/driver/fingerprint/elan/elan_sensor_pal.c
new file mode 100644
index 0000000000..0c8827d684
--- /dev/null
+++ b/driver/fingerprint/elan/elan_sensor_pal.c
@@ -0,0 +1,246 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+/* ELAN Platform Abstraction Layer callbacks */
+
+#include <stddef.h>
+#include "common.h"
+#include "console.h"
+#include "endian.h"
+#include "fpsensor.h"
+#include "gpio.h"
+#include "link_defs.h"
+#include "spi.h"
+#include "system.h"
+#include "timer.h"
+#include "util.h"
+#include "shared_mem.h"
+#include "math_util.h"
+#include "cryptoc/util.h"
+
+#include "elan_setting.h"
+#include "elan_sensor.h"
+#include "elan_sensor_pal.h"
+
+static uint8_t tx_buf[CONFIG_SPI_TX_BUF_SIZE] __uncached;
+static uint8_t rx_buf[CONFIG_SPI_RX_BUF_SIZE] __uncached;
+
+int elan_write_cmd(uint8_t fp_cmd)
+{
+ int rc = 0;
+
+ memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE);
+ memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE);
+
+ tx_buf[0] = fp_cmd;
+ rc = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf,
+ SPI_READBACK_ALL);
+ return rc;
+}
+
+int elan_read_cmd(uint8_t fp_cmd, uint8_t *regdata)
+{
+ int ret = 0;
+
+ memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE);
+ memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE);
+
+ tx_buf[0] = fp_cmd; /* one byte data read */
+ ret = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf,
+ SPI_READBACK_ALL);
+ *regdata = rx_buf[1];
+
+ return ret;
+}
+
+int elan_spi_transaction(uint8_t *tx, int tx_len, uint8_t *rx, int rx_len)
+{
+ int ret = 0;
+
+ memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE);
+ memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE);
+
+ memcpy(tx_buf, tx, tx_len);
+ ret = spi_transaction(&spi_devices[0], tx_buf, tx_len, rx_buf, rx_len);
+ memcpy(rx, rx_buf, rx_len);
+
+ return ret;
+}
+
+int elan_write_register(uint8_t regaddr, uint8_t regdata)
+{
+ int ret = 0;
+
+ memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE);
+ memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE);
+
+ tx_buf[0] = WRITE_REG_HEAD + regaddr; /* one byte data write */
+ tx_buf[1] = regdata;
+ ret = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf,
+ SPI_READBACK_ALL);
+ return ret;
+}
+
+int elan_write_page(uint8_t page)
+{
+ int ret = 0;
+
+ memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE);
+ memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE);
+
+ tx_buf[0] = PAGE_SEL;
+ tx_buf[1] = page;
+ ret = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf,
+ SPI_READBACK_ALL);
+
+ return ret;
+}
+
+int elan_write_reg_vector(const uint8_t *reg_table, int length)
+{
+ int ret = 0;
+ int i = 0;
+ uint8_t write_regaddr;
+ uint8_t write_regdata;
+
+ for (i = 0; i < length; i = i + 2) {
+ write_regaddr = reg_table[i];
+ write_regdata = reg_table[i + 1];
+ ret = elan_write_register(write_regaddr, write_regdata);
+ if (ret < 0)
+ break;
+ }
+ return ret;
+}
+
+int raw_capture(uint16_t *short_raw)
+{
+ int ret = 0, i = 0, image_index = 0, index = 0;
+ int cnt_timer = 0;
+ int dma_loop = 0, dma_len = 0;
+ uint8_t regdata[4] = { 0 };
+ char *img_buf;
+
+ memset(short_raw, 0, sizeof(uint16_t) * IMAGE_TOTAL_PIXEL);
+
+ ret = shared_mem_acquire(sizeof(uint8_t) * IMG_BUF_SIZE, &img_buf);
+ if (ret) {
+ LOGE_SA("%s Can't get shared mem\n", __func__);
+ return ret;
+ }
+ memset(img_buf, 0, sizeof(uint8_t) * IMG_BUF_SIZE);
+
+ /* Write start scans command to fp sensor */
+ if (elan_write_cmd(START_SCAN) < 0) {
+ ret = ELAN_ERROR_SPI;
+ LOGE_SA("%s SPISendCommand( SSP2, START_SCAN ) fail ret = %d",
+ __func__, ret);
+ goto exit;
+ }
+
+ /* Polling scan status */
+ cnt_timer = 0;
+ while (1) {
+ usleep(1000);
+ cnt_timer++;
+ regdata[0] = SENSOR_STATUS;
+ elan_spi_transaction(regdata, 2, regdata, 2);
+ if (regdata[0] & 0x04)
+ break;
+
+ if (cnt_timer > POLLING_SCAN_TIMER) {
+ ret = ELAN_ERROR_SCAN;
+ LOGE_SA("%s regdata = 0x%x, fail ret = %d", __func__,
+ regdata[0], ret);
+ goto exit;
+ }
+ }
+
+ /* Read the image from fp sensor */
+ dma_loop = 4;
+ dma_len = IMG_BUF_SIZE / dma_loop;
+
+ for (i = 0; i < dma_loop; i++) {
+ memset(tx_buf, 0, CONFIG_SPI_TX_BUF_SIZE);
+ memset(rx_buf, 0, CONFIG_SPI_RX_BUF_SIZE);
+ tx_buf[0] = START_READ_IMAGE;
+ ret = spi_transaction(&spi_devices[0], tx_buf, 2, rx_buf,
+ dma_len);
+ memcpy(&img_buf[dma_len * i], rx_buf, dma_len);
+ }
+
+ /* Remove dummy byte */
+ for (image_index = 1; image_index < IMAGE_WIDTH; image_index++)
+ memcpy(&img_buf[RAW_PIXEL_SIZE * image_index],
+ &img_buf[RAW_DATA_SIZE * image_index], RAW_PIXEL_SIZE);
+
+ for (index = 0; index < IMAGE_TOTAL_PIXEL; index++)
+ short_raw[index] =
+ (img_buf[index * 2] << 8) + img_buf[index * 2 + 1];
+
+exit:
+ if (img_buf != NULL) {
+ always_memset(img_buf, 0, sizeof(uint8_t) * IMG_BUF_SIZE);
+ shared_mem_release(img_buf);
+ }
+
+ if (ret != 0)
+ LOGE_SA("%s error = %d", __func__, ret);
+
+ return ret;
+}
+
+int elan_execute_calibration(void)
+{
+ int retry_time = 0;
+ int ret = 0;
+
+ while (retry_time < REK_TIMES) {
+ elan_write_cmd(SRST);
+ elan_write_cmd(FUSE_LOAD);
+ register_initialization();
+ elan_sensing_mode();
+
+ ret = calibration();
+ if (ret == 0)
+ break;
+
+ retry_time++;
+ }
+
+ return ret;
+}
+
+int elan_fp_maintenance(uint16_t *error_state)
+{
+ int rv;
+ fp_sensor_info_t sensor_info;
+ timestamp_t start = get_time();
+
+ if (error_state == NULL)
+ return EC_ERROR_INVAL;
+
+ sensor_info.num_defective_pixels = 0;
+ sensor_info.sensor_error_code = 0;
+ rv = fp_sensor_maintenance(&sensor_info);
+ LOGE_SA("Maintenance took %d ms", time_since32(start) / MSEC);
+
+ if (rv != 0) {
+ /*
+ * Failure can occur if any of the fingerprint detection zones
+ * are covered (i.e., finger is on sensor).
+ */
+ LOGE_SA("Failed to run maintenance: %d", rv);
+ return EC_ERROR_HW_INTERNAL;
+ }
+ if (sensor_info.num_defective_pixels >= FP_ERROR_DEAD_PIXELS_UNKNOWN)
+ *error_state = FP_ERROR_DEAD_PIXELS_UNKNOWN;
+ else
+ *error_state |=
+ FP_ERROR_DEAD_PIXELS(sensor_info.num_defective_pixels);
+ LOGE_SA("num_defective_pixels: %d", sensor_info.num_defective_pixels);
+ LOGE_SA("sensor_error_code: %d", sensor_info.sensor_error_code);
+
+ return EC_SUCCESS;
+}
diff --git a/driver/fingerprint/elan/elan_sensor_pal.h b/driver/fingerprint/elan/elan_sensor_pal.h
new file mode 100644
index 0000000000..08f0c6e2c9
--- /dev/null
+++ b/driver/fingerprint/elan/elan_sensor_pal.h
@@ -0,0 +1,126 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+/* ELAN Platform Abstraction Layer callbacks */
+
+#ifndef ELAN_SENSOR_PAL_H_
+#define ELAN_SENSOR_PAL_H_
+
+/* ELAN error codes */
+enum elan_error_code {
+ ELAN_ERROR_NONE = 0,
+ ELAN_ERROR_SPI = 1,
+ ELAN_ERROR_SCAN = 2,
+ ELAN_ERROR_CAL = 3,
+ ELAN_ERROR_DEFECT_NUM = 4,
+ ELAN_ERROR_DEFECT_X = 5,
+ ELAN_ERROR_DEFECT_Y = 6
+};
+
+/* ELAN error info */
+struct fp_sensor_info_t {
+ uint32_t num_defective_pixels;
+ uint16_t sensor_error_code;
+};
+
+/**
+ * @brief Write fp command to the sensor
+ *
+ * @param[in] fp_cmd One byte fp command to write
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_write_cmd(uint8_t fp_cmd);
+
+/**
+ * @brief Read fp register data from the sensor
+ *
+ * @param[in] fp_cmd One byte fp command to read
+ * @param[out] regdata One byte data where register's data will be stored
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_read_cmd(uint8_t fp_cmd, uint8_t *regdata);
+
+/**
+ * @brief Transfers and receives SPI data.
+ *
+ * @param[in] tx The buffer to transfer
+ * @param[in] tx_len The length to transfer
+ * @param[out] rx The buffer where read data will be stored
+ * @param[in] rx_len The length to receive
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_spi_transaction(uint8_t *tx, int tx_len, uint8_t *rx, int rx_len);
+
+/**
+ * @brief Write fp register data to sensor
+ *
+ * @param[in] regaddr One byte register address to write
+ * @param[in] regdata Data to write to register
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_write_register(uint8_t regaddr, uint8_t regdata);
+
+/**
+ * @brief Select sensor RAM page of register
+ *
+ * @param[in] page The number of RAM page control registers
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_write_page(uint8_t page);
+
+/**
+ * @brief Write register table to fp sensor
+ *
+ * Using a table to write data to sensor register.
+ * This table contains multiple pairs of address and data to
+ * be written.
+ *
+ * @param[in] reg_table The register address to write
+ * @param[in] length The data to write to register
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_write_reg_vector(const uint8_t *reg_table, int length);
+
+/**
+ * Get 14bits raw image data from ELAN fingerprint sensor
+ *
+ * @param[out] short_raw The memory buffer to receive fingerprint image
+ * raw data, buffer length is:
+ * (IMAGE_WIDTH*IMAGE_HEIGHT)*sizeof(uint16_t)
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int raw_capture(uint16_t *short_raw);
+
+/**
+ * Execute calibrate ELAN fingerprint sensor flow.
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int elan_execute_calibration(void);
+
+/**
+ * Runs a test for defective pixels.
+ *
+ * @param[out] fp_sensor_info Structure containing output data.
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int fp_sensor_maintenance(fp_sensor_info_t *fp_sensor_info);
+
+#endif
diff --git a/driver/fingerprint/elan/elan_setting.h b/driver/fingerprint/elan/elan_setting.h
new file mode 100644
index 0000000000..f7b16627b6
--- /dev/null
+++ b/driver/fingerprint/elan/elan_setting.h
@@ -0,0 +1,101 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef ELAN_SETTING_H
+#define ELAN_SETTING_H
+
+#include <stdint.h>
+
+/* The hardware ID information and FW version */
+#define VID 0x04F3
+#define PID 0x0903
+#define MID 0x01
+#define VERSION 0x100A
+
+/* SPI tx and rx buffer size */
+#define CONFIG_SPI_TX_BUF_SIZE 1024
+#define CONFIG_SPI_RX_BUF_SIZE 5120
+
+/**
+ * Elan sensor operation is controlled by sending commands and receiving
+ * through the SPI interface. There are several SPI command codes for
+ * controlling FP sensor:
+ *
+ * - START_SCAN Start scan
+ * - START_READ_IMAGE Start read the image
+ * - SRST Software reset
+ * - FUSE_LOAD Load OTP trims data to control registers
+ * - READ_REG_HEAD Register single read
+ * - WRITE_REG_HEAD Register burst write
+ * - READ_SERIER_REG_HEAD Register burst read
+ * - PAGE_SEL Register page selection
+ * - SENSOR_STATUS Read sensor status
+ */
+#define START_SCAN 0x01
+#define START_READ_IMAGE 0x10
+#define SRST 0x31
+#define FUSE_LOAD 0x04
+#define READ_REG_HEAD 0x40
+#define WRITE_REG_HEAD 0x80
+#define READ_SERIER_REG_HEAD 0xC0
+#define PAGE_SEL 0x07
+#define SENSOR_STATUS 0x03
+
+/* Sensor type name */
+#define EFSA515 1
+#define EFSA80SC 2
+#if defined(CONFIG_FP_SENSOR_ELAN80)
+#define IC_SELECTION EFSA80SC
+#elif defined(CONFIG_FP_SENSOR_ELAN515)
+#define IC_SELECTION EFSA515
+#endif
+
+/* Sensor pixel resolution */
+#if (IC_SELECTION == EFSA80SC)
+#define IMAGE_WIDTH 80
+#define IMAGE_HEIGHT 80
+#elif (IC_SELECTION == EFSA515)
+#define IMAGE_WIDTH 150
+#define IMAGE_HEIGHT 52
+#endif
+
+/**
+ * Sensor real image size:
+ * ((IMAGE_HEIGHT * ONE_PIXEL_BYTE) + FP_DUMMY_BYTE) * IMAGE_WIDTH
+ */
+#define FP_DUMMY_BYTE 2
+#define ONE_PIXEL_BYTE 2
+#define IMAGE_TOTAL_PIXEL (IMAGE_WIDTH * IMAGE_HEIGHT)
+#define RAW_PIXEL_SIZE (IMAGE_HEIGHT * ONE_PIXEL_BYTE)
+#define RAW_DATA_SIZE (RAW_PIXEL_SIZE + FP_DUMMY_BYTE)
+#define IMG_BUF_SIZE (RAW_DATA_SIZE * IMAGE_WIDTH)
+
+/* Polling scan status counter */
+#define POLLING_SCAN_TIMER 10000
+
+/* Re-calibration timer */
+#define REK_TIMES 3
+
+/* Console output macros */
+#define LOGE_SA(format, args...) cprints(CC_FP, format, ##args)
+
+/**
+ * Set ELAN fingerprint sensor register initialization
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int register_initialization(void);
+
+/**
+ * To calibrate ELAN fingerprint sensor and keep the calibration results
+ * for correcting fingerprint image data
+ *
+ * @return 0 on success.
+ * negative value on error.
+ */
+int calibration(void);
+
+#endif /* _ELAN_SETTING_H */
diff --git a/driver/fingerprint/fpsensor.h b/driver/fingerprint/fpsensor.h
index 44d989df13..ac7e31fb6a 100644
--- a/driver/fingerprint/fpsensor.h
+++ b/driver/fingerprint/fpsensor.h
@@ -8,7 +8,11 @@
#if defined(HAVE_PRIVATE) && !defined(EMU_BUILD)
#define HAVE_FP_PRIVATE_DRIVER
+#if defined(CONFIG_FP_SENSOR_ELAN80) || defined(CONFIG_FP_SENSOR_ELAN515)
+#include "elan/elan_sensor.h"
+#else
#include "fpc/fpc_sensor.h"
+#endif
#else
/* These values are used by the host (emulator) tests. */
#define FP_SENSOR_IMAGE_SIZE 0
diff --git a/include/config.h b/include/config.h
index e83cb07191..217251e661 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1846,6 +1846,8 @@
#undef CONFIG_FP_SENSOR_FPC1025
#undef CONFIG_FP_SENSOR_FPC1035
#undef CONFIG_FP_SENSOR_FPC1145
+#undef CONFIG_FP_SENSOR_ELAN80
+#undef CONFIG_FP_SENSOR_ELAN515
/*****************************************************************************/