summaryrefslogtreecommitdiff
path: root/driver/fingerprint/elan/elan_sensor_pal.c
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 /driver/fingerprint/elan/elan_sensor_pal.c
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>
Diffstat (limited to 'driver/fingerprint/elan/elan_sensor_pal.c')
-rw-r--r--driver/fingerprint/elan/elan_sensor_pal.c246
1 files changed, 246 insertions, 0 deletions
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;
+}