diff options
author | Chiehchun Yu <chiehchun.yu@elan.corp-partner.google.com> | 2020-01-16 14:44:50 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-01-12 20:47:52 +0000 |
commit | 3775fdbf7e863603eb65ec52348a45d7139db628 (patch) | |
tree | 9b9bc902067543a51db1d7772e348a2a15f9e437 | |
parent | 4167ccc6fc40b865d5eb9f6e13b7a95f9aba0f19 (diff) | |
download | chrome-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.mk | 1 | ||||
-rw-r--r-- | driver/fingerprint/elan/build.mk | 20 | ||||
-rw-r--r-- | driver/fingerprint/elan/elan_private.c | 248 | ||||
-rw-r--r-- | driver/fingerprint/elan/elan_sensor.h | 164 | ||||
-rw-r--r-- | driver/fingerprint/elan/elan_sensor_pal.c | 246 | ||||
-rw-r--r-- | driver/fingerprint/elan/elan_sensor_pal.h | 126 | ||||
-rw-r--r-- | driver/fingerprint/elan/elan_setting.h | 101 | ||||
-rw-r--r-- | driver/fingerprint/fpsensor.h | 4 | ||||
-rw-r--r-- | include/config.h | 2 |
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 /*****************************************************************************/ |