class pah8011 for mbed

Files at this revision

API Documentation at this revision

Comitter:
bell_huang
Date:
Wed Jan 23 08:01:57 2019 +0000
Parent:
5:37451de228e4
Commit message:
Remove mbed

Changed in this revision

mbed-os.lib Show diff for this revision Revisions of this file
pah8011/pah_comm.c Show annotated file Show diff for this revision Revisions of this file
pah8011/pah_comm.h Show annotated file Show diff for this revision Revisions of this file
pah8011/pah_comm_i2c.c Show diff for this revision Revisions of this file
pah8011/pah_driver.h Show annotated file Show diff for this revision Revisions of this file
pah8011/pah_driver_types.h Show annotated file Show diff for this revision Revisions of this file
pah8011/pah_drv_comm.h Show annotated file Show diff for this revision Revisions of this file
pah8011/pah_platform_functions.h Show annotated file Show diff for this revision Revisions of this file
pah8011/pah_ret.h Show annotated file Show diff for this revision Revisions of this file
pah8011/pah_util.h Show annotated file Show diff for this revision Revisions of this file
pixart_pah8011.cpp Show annotated file Show diff for this revision Revisions of this file
pixart_pah8011.h Show annotated file Show diff for this revision Revisions of this file
--- a/mbed-os.lib	Fri Oct 27 08:21:32 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-https://github.com/ARMmbed/mbed-os/#e62a1b9236b44e70ae3b0902dc538481c04d455b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pah8011/pah_comm.c	Wed Jan 23 08:01:57 2019 +0000
@@ -0,0 +1,60 @@
+#include "pah_comm.h"
+
+#include "pah_util.h"
+
+
+/*============================================================================
+STATIC VARIABLE DEFINITIONS
+============================================================================*/
+static bool _has_drv_comm = false;
+static pah_drv_comm_s   _drv_comm;
+
+
+/*============================================================================
+PUBLIC FUNCTION DEFINITIONS
+============================================================================*/
+void pah_comm_set_drv_comm(const pah_drv_comm_s *drv_comm)
+{
+    memcpy(&_drv_comm, drv_comm, sizeof(*drv_comm));
+    _has_drv_comm = true;
+}
+
+bool pah_comm_write(uint8_t addr, uint8_t data)
+{
+    if (!_has_drv_comm)
+        return false;
+
+    if (_drv_comm.type == pah_drv_comm_spi)
+        PAH_CLEAR_BIT(addr, 7); //write, bit7 = 0
+    
+    return PAH_SUCCEEDED(_drv_comm.write(&_drv_comm, addr, data));
+}
+
+bool pah_comm_read(uint8_t addr, uint8_t *data)
+{
+    if (!_has_drv_comm)
+        return false;
+
+    if (_drv_comm.type == pah_drv_comm_spi)
+        PAH_SET_BIT(addr, 7); //read, bit7 = 1
+
+    return PAH_SUCCEEDED(_drv_comm.read(&_drv_comm, addr, data));
+}
+
+bool pah_comm_burst_read(uint8_t addr, uint8_t *data, uint16_t num)
+{
+    if (!_has_drv_comm)
+        return false;
+
+    if (_drv_comm.type == pah_drv_comm_spi)
+        PAH_SET_BIT(addr, 7); //read, bit7 = 1
+
+    return PAH_SUCCEEDED(_drv_comm.burst_read(&_drv_comm, addr, data, num));
+}
+
+pah_comm_bus_e pah_comm_get_bus_type(void)
+{
+    if (_drv_comm.type == pah_drv_comm_spi)
+        return pah_comm_bus_spi;
+    return pah_comm_bus_i2c;
+}
--- a/pah8011/pah_comm.h	Fri Oct 27 08:21:32 2017 +0000
+++ b/pah8011/pah_comm.h	Wed Jan 23 08:01:57 2019 +0000
@@ -1,23 +1,8 @@
-/*==============================================================================
-* Edit History
-* 
-* This section contains comments describing changes made to the module. Notice
-* that changes are listed in reverse chronological order. Please use ISO format
-* for dates.
-* 
-* when       who       what, where, why
-* ---------- ---       -----------------------------------------------------------
-* 2016-10-18 bh        - Add enum: pah_comm_bus_e.
-*                      - Add function: pah_comm_get_bus_type().
-* 2016-04-12 bh        - Add license information and revision information
-* 2016-04-07 bh        - Initial revision.
-==============================================================================*/
-
-#ifndef __pah_comm_h__
-#define __pah_comm_h__
+#pragma once
 
 
 #include "pah_platform_types.h"
+#include "pah_drv_comm.h"
 
 
 typedef enum {
@@ -28,11 +13,11 @@
 } pah_comm_bus_e;
 
 
+void  pah_comm_set_drv_comm(const pah_drv_comm_s *drv_comm);
+
 bool  pah_comm_write(uint8_t addr, uint8_t data);
 bool  pah_comm_read(uint8_t addr, uint8_t *data);
 bool  pah_comm_burst_read(uint8_t addr, uint8_t *data, uint16_t num);
 
 pah_comm_bus_e     pah_comm_get_bus_type(void);
 
-
-#endif  // header guard
--- a/pah8011/pah_comm_i2c.c	Fri Oct 27 08:21:32 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*==============================================================================
-* Edit History
-* 
-* This section contains comments describing changes made to the module. Notice
-* that changes are listed in reverse chronological order. Please use ISO format
-* for dates.
-* 
-* when       who       what, where, why
-* ---------- ---       -----------------------------------------------------------
-* 2016-10-18 bh        - Add pah_comm_get_bus_type() function.
-* 2016-04-12 bh        - Add license information and revision information
-* 2016-04-07 bh        - Initial revision.
-==============================================================================*/
-
-#include "pah_comm.h"
-
-// platform support
-#include "pah_platform_functions.h"
-
-
-/*============================================================================
-STATIC VARIABLE DEFINITIONS
-============================================================================*/
-
-// valid bank range: 0x00 ~ 0x03
-static uint8_t _curr_bank = 0xFF;
-
-
-/*============================================================================
-PUBLIC FUNCTION DEFINITIONS
-============================================================================*/
-bool pah_comm_write(uint8_t addr, uint8_t data)
-{
-    if (addr == 0x7F)
-    {
-        if (_curr_bank == data)
-            return true;
-
-        if (!i2c_write_reg(0x7F, data))
-            return false;
-
-        _curr_bank = data;
-        return true;
-    }
-
-    return i2c_write_reg(addr, data);
-}
-
-bool pah_comm_read(uint8_t addr, uint8_t *data)
-{
-    return i2c_read_reg(addr, data);
-}
-
-bool pah_comm_burst_read(uint8_t addr, uint8_t *data, uint16_t num)
-{
-    return i2c_burst_read_reg(addr, data, num);
-}
-
-pah_comm_bus_e pah_comm_get_bus_type(void)
-{
-    return pah_comm_bus_i2c;
-}
--- a/pah8011/pah_driver.h	Fri Oct 27 08:21:32 2017 +0000
+++ b/pah8011/pah_driver.h	Wed Jan 23 08:01:57 2019 +0000
@@ -1,3 +1,11 @@
+/**
+ * @file sns_dd_pah_driver.h
+ *
+ * Copyright (c) 2016-2017 PixArt Imaging Inc.
+ * All Rights Reserved.
+ * Confidential and Proprietary - PixArt Imaging Inc.
+ **/
+
 /*==============================================================================
 * Edit History
 * 
@@ -7,29 +15,27 @@
 * 
 * when       who       what, where, why
 * ---------- ---       -----------------------------------------------------------
-* 2016-10-20 bh        - Move some public types to new file pah_driver_types.h for reuse.
-*                      - Add function: pah_fifo_data_num_per_ch().
-* 2016-09-08 bh        - Add functions: pah_init_with_flags().
+* 2016-10-14 bell      - Add functions: pah_init_with_flags().
 *                      - Add pah_ppg_led_on_e flag.
-* 2016-06-07 bh        - Add functions: pah_set_mode(), pah_run_device().
+* 2016-06-07 bell      - Add functions: pah_set_mode(), pah_run_device().
 *                      - Add enum: pah_device.
 *                      - Add comments.
-* 2016-04-29 bh        - Add PPG 200Hz modes.
+* 2016-04-29 bell      - Add PPG 200Hz modes.
 *                      - Add helper functions: pah_is_ppg_mode(), pah_is_ppg_20hz_mode(), pah_fifo_data_num_per_ch().
 *                      - Add pah_stop_mode
 *                      - Remove pah_suspend_mode.
 *                      - Fix setting pah_set_report_sample_num_per_ch() after enter_mode() causes bad behavior.
-* 2016-04-20 bh        Add pah_stop_mode. pah_none can be regarded as pah_stop_mode.
-* 2016-04-12 bh        Add license information and revision information.
-* 2016-04-07 bh        Initial revision.
+* 2016-04-20 bell      Add pah_stop_mode. pah_none can be regarded as pah_stop_mode.
+* 2016-04-12 bell      Add license information and revision information.
+* 2016-04-07 bell      Initial revision.
 ==============================================================================*/
 
-#ifndef __pah_driver_h__
-#define __pah_driver_h__
+#ifndef __sns_dd_pah_driver_h__
+#define __sns_dd_pah_driver_h__
 
-
+#include "pah_platform_types.h"
 #include "pah_driver_types.h"
-#include "pah_platform_types.h"
+#include "pah_ret.h"
 
 
 typedef struct {
@@ -42,12 +48,6 @@
 } pah_flags_s;
 
 
-/**
- * @brief Get default pah_flags_s.
- * 
- * @param[out] flags        Refer to struct pah_flags_s.
- */
-void        pah_flags_default(pah_flags_s *flags);
 
 /**
  * @brief Initialize the driver.
@@ -59,14 +59,14 @@
 bool        pah_init(void);
 
 /**
- * @brief Initialize the driver.
- * 
- * It should been called once before any other function calls.
- *
- * @param[in]  flags        Refer to struct pah_flags_s.
- *
- * @return True if successful.
- */
+* @brief Initialize the driver.
+*
+* It should been called once before any other function calls.
+*
+* @param[in]  flags        Refer to struct pah_flags_s.
+*
+* @return True if successful.
+*/
 bool        pah_init_with_flags(const pah_flags_s *flags);
 
 /**
@@ -280,6 +280,7 @@
  */
 uint32_t    pah_get_bytes_per_sample(void);
 
+
 /**
  * @brief Check if the driver is valid to the device.
  * 
@@ -303,3 +304,4 @@
 
 
 #endif  // header guard
+
--- a/pah8011/pah_driver_types.h	Fri Oct 27 08:21:32 2017 +0000
+++ b/pah8011/pah_driver_types.h	Wed Jan 23 08:01:57 2019 +0000
@@ -16,6 +16,7 @@
 #define __pah_driver_types_h__
 
 
+#include "pah_ret.h"
 #include "pah_platform_types.h"
 
 
@@ -129,39 +130,22 @@
 } pah_device;
 
 
-typedef enum {
-
-    pah_success,                // Success
-    pah_pending,                // Do nothing. Usually happens when task() detected no interrupt in dri mode or fifo number is not enough.
-
-    pah_err_unknown,            // Unknown error
-    pah_err_invalid_argument,   // Invalid argument to function
-    pah_err_invalid_operation,  // Invalid operation to function
-    pah_err_not_init,           // Driver isn't initialized
-    pah_err_not_implement,      // Not implemented in this driver
-    pah_err_platform_fail,      // Platform function failed (For example, I2C, SPI, ...)
-
-    pah_err_invalid_program,    // Generally this indicates a bug in the driver
-
-    pah_err_verify_device_fail, // Verify device failed
-
-    pah_err_fifo_checksum_fail, // Failed to compare check sum with fifo data
-                                // Usually happens to bad data communication
-
-    pah_err_fifo_overflow,      // Fifo in device is overflow
-                                // Usually happens when pah_task() was too late to be called
-    
-    pah_err_fifo_underflow,     // Fifo in device is underflow
-
-} pah_ret;
-#define PAH_SUCCEEDED(ret)              (ret == pah_success)
-#define PAH_SUCCEEDED_OR_PENDING(ret)   (ret == pah_success || ret == pah_pending)
-#define PAH_FAILED(ret)                 (ret != pah_success)
-
-
-// deprecated names
-#define pah_no_interrupt    pah_pending
-#define pah_err_comm_fail   pah_err_platform_fail
+// legacy pah_ret
+#define pah_success                 PAH_RET_SUCCESS             // Success
+#define pah_pending                 PAH_RET_SUCCESS             // Do nothing. Usually happens when task() detected no interrupt in dri mode or fifo number is not enough.
+#define pah_no_interrupt            PAH_RET_SUCCESS
+#define pah_err_unknown             PAH_RET_FAILED              // Unknown error
+#define pah_err_invalid_argument    PAH_RET_INVALID_ARGUMENT    // Invalid argument to function
+#define pah_err_invalid_operation   PAH_RET_INVALID_OPERATION   // Invalid operation to function
+#define pah_err_not_init            PAH_RET_INVALID_OPERATION   // Driver isn't initialized
+#define pah_err_not_implement       PAH_RET_NOT_IMPLEMENTED     // Not implemented in this driver
+#define pah_err_platform_fail       PAH_RET_PLAT_FAILED         // Platform function failed (For example, I2C, SPI, ...)
+#define pah_err_comm_fail           PAH_RET_PLAT_FAILED         // Platform function failed (For example, I2C, SPI, ...)
+#define pah_err_invalid_program     PAH_RET_FAILED              // Generally this indicates a bug in the driver
+#define pah_err_verify_device_fail  PAH_RET_VERIFY_FAILED       // Verify device failed
+#define pah_err_fifo_checksum_fail  PAH_RET_VERIFY_FAILED       // Failed to compare check sum with fifo data, usually happens to bad data communication
+#define pah_err_fifo_overflow       PAH_RET_FIFO_OVERFLOW       // Fifo in device is overflow, usually happens when pah_task() was too late to be called
+#define pah_err_fifo_underflow      PAH_RET_FAILED              // Fifo in device is underflow
 
 
 typedef struct {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pah8011/pah_drv_comm.h	Wed Jan 23 08:01:57 2019 +0000
@@ -0,0 +1,29 @@
+#pragma once
+
+
+#include "pah_ret.h"
+#include <stdint.h>
+
+
+struct pah_drv_comm_s;
+
+typedef enum {
+    pah_drv_comm_i2c,
+    pah_drv_comm_spi,
+} pah_drv_comm_type_e;
+
+
+typedef struct pah_drv_comm_s {
+
+    void                    *user_data;
+    pah_drv_comm_type_e     type;
+    uint32_t                max_length;
+
+    pah_ret (*write)(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t data);
+    pah_ret (*write_delay)(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t data, uint32_t delay_ms);
+    pah_ret (*read)(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t *data);
+    pah_ret (*burst_read)(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t *data, uint32_t rx_size);
+
+} pah_drv_comm_s;
+
+
--- a/pah8011/pah_platform_functions.h	Fri Oct 27 08:21:32 2017 +0000
+++ b/pah8011/pah_platform_functions.h	Wed Jan 23 08:01:57 2019 +0000
@@ -17,9 +17,6 @@
 #include <stdbool.h>
 
 
-bool  	i2c_write_reg(uint8_t addr, uint8_t data);
-bool   	i2c_read_reg(uint8_t addr, uint8_t *data);
-bool    i2c_burst_read_reg(uint8_t addr, uint8_t *data, uint32_t rx_size);
 void    delay_ms(uint64_t ms);
 
 typedef void (*DEBUG_PRINT_HANDLE)(const char *fmt, ...);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pah8011/pah_ret.h	Wed Jan 23 08:01:57 2019 +0000
@@ -0,0 +1,48 @@
+/**
+ * @file pah_ret.h
+ *
+ * Copyright (c) 2016-2017 PixArt Imaging Inc.
+ * All Rights Reserved.
+ * Confidential and Proprietary - PixArt Imaging Inc.
+ **/
+#ifndef __pah_ret_h__
+#define __pah_ret_h__
+
+
+typedef enum {
+
+    PAH_RET_SUCCESS = 0,            // Success
+
+    PAH_RET_FAILED,                 // Unknown error, generally there exists bug in this driver
+
+    PAH_RET_PLAT_FAILED,            // Platform API failed
+    PAH_RET_VERIFY_FAILED,          // Verify device failed
+
+    PAH_RET_NOT_IMPLEMENTED,        // This API is not supported or is not implemented
+
+    PAH_RET_INVALID_ARGUMENT,       // Invalid argument to API
+    PAH_RET_INVALID_OPERATION,      // This operation is not available at this time
+
+    PAH_RET_FIFO_CKS_FAILED,        // Failed to compare check sum with fifo data
+    PAH_RET_FIFO_OVERFLOW,          // Fifo in device is overflow
+
+} pah_ret;
+
+
+#define PAH_SUCCEEDED(ret)              (ret == PAH_RET_SUCCESS)
+#define PAH_FAILED(ret)                 (!PAH_SUCCEEDED(ret))
+
+
+#define PAH_CHECK_RET(ret) \
+    if (PAH_FAILED(ret)) { \
+        return ret; \
+    }
+
+#define PAH_CHECK_NULL(p) \
+    if (!p) { \
+        return PAH_RET_INVALID_ARGUMENT; \
+    }
+
+
+#endif  // header guard
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pah8011/pah_util.h	Wed Jan 23 08:01:57 2019 +0000
@@ -0,0 +1,26 @@
+/**
+ * @file pah_util.h
+ *
+ * Copyright (c) 2016-2017 PixArt Imaging Inc.
+ * All Rights Reserved.
+ * Confidential and Proprietary - PixArt Imaging Inc.
+ **/
+#ifndef __pah_util_h__
+#define __pah_util_h__
+
+
+#include <stdint.h>
+
+
+#define PAH_ARRAY_SIZE(arr)         (sizeof(arr) / sizeof(arr[0]))
+
+#define PAH_SET_BIT(var,pos)        do { ((var) |= (1 << (pos))); } while(0)
+#define PAH_CLEAR_BIT(var,pos)      do { ((var) &= ~(1 << (pos))); } while(0)
+#define PAH_CHECK_BIT(var,pos)      (((var) >> (pos)) & 1)
+
+#define PAH_UINT64_HIGH(var)  ((uint32_t)(var >> 32))
+#define PAH_UINT64_LOW(var)   ((uint32_t)(var & UINT32_MAX))
+
+
+#endif  // header guard
+
--- a/pixart_pah8011.cpp	Fri Oct 27 08:21:32 2017 +0000
+++ b/pixart_pah8011.cpp	Wed Jan 23 08:01:57 2019 +0000
@@ -4,46 +4,18 @@
 extern "C" {
     
     
+    #include "pah_comm.h"
     #include "pah_driver.h"
     #include "pah_platform_functions.h"
-    
+    #include <string.h>
     
-    static I2C      *g_i2c = NULL;
-    static uint8_t  g_slave_id = 0x15;
     
     void disable_debug_printf(const char *fmt, ...)
     {
         // do nothing
     }
 
-    DEBUG_PRINT_HANDLE debug_printf = disable_debug_printf;    
-    
-    
-    bool i2c_write_reg(uint8_t addr, uint8_t data)
-    {
-        char data_write[2];
-    
-        data_write[0] = addr;
-        data_write[1] = data;
-        
-        return 0 == g_i2c->write((g_slave_id << 1), data_write, 2, 0);
-    }
-    
-    bool i2c_burst_read_reg(uint8_t addr, uint8_t *data, uint32_t rx_size)
-    {
-        if (0 != g_i2c->write((g_slave_id << 1), (const char*)&addr, 1, 1))
-            return false;
-        
-        if (0 != g_i2c->read((g_slave_id << 1), (char*)data, rx_size, 0))
-            return false;
-        
-        return true;
-    }
-    
-    bool i2c_read_reg(uint8_t addr, uint8_t *data)
-    {
-        return i2c_burst_read_reg(addr, data, 1);
-    }
+    DEBUG_PRINT_HANDLE debug_printf = disable_debug_printf;
     
     void delay_ms(uint64_t ms)
     {
@@ -56,11 +28,136 @@
 namespace pixart {
     
     
-    pah8011::pah8011()
-        : m_is_ppg_enabled(false)
+    static pah_ret mbed_i2c_write(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t data)
+    {
+        pah8011 *pah8011_state = (pah8011*)comm->user_data;
+        I2C *i2c = pah8011_state->get_i2c();
+        int rc = 0;
+        char data_write[2];
+    
+        data_write[0] = addr;
+        data_write[1] = data;
+        
+        rc = i2c->write((pah8011_state->get_i2c_slave_id() << 1), data_write, 2, 0);
+        if (rc != 0)
+            return PAH_RET_PLAT_FAILED;
+        
+        return PAH_RET_SUCCESS;
+    }
+    
+    static pah_ret mbed_i2c_burst_read(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t *data, uint32_t rx_size)
+    {
+        pah8011 *pah8011_state = (pah8011*)comm->user_data;
+        I2C *i2c = pah8011_state->get_i2c();
+        int rc = 0;
+        
+        rc = i2c->write((pah8011_state->get_i2c_slave_id() << 1), (const char*)&addr, 1, 1);
+        if (rc != 0)
+            return PAH_RET_PLAT_FAILED;
+        
+        rc = i2c->read((pah8011_state->get_i2c_slave_id() << 1), (char*)data, rx_size, 0);
+        if (rc != 0)
+            return PAH_RET_PLAT_FAILED;
+        
+        return PAH_RET_SUCCESS;
+    }
+    
+    static pah_ret mbed_i2c_read(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t *data)
+    {
+        return mbed_i2c_burst_read(comm, addr, data, 1);
+    }
+    
+    static pah_ret mbed_spi_write(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t data)
+    {
+        pah8011 *pah8011_state = (pah8011*)comm->user_data;
+        SPI *spi = pah8011_state->get_spi();
+        DigitalOut *spi_cs = pah8011_state->get_spi_cs();
+        
+        *spi_cs = 1;
+        
+        char data_write[2];
+        data_write[0] = addr;
+        data_write[1] = data;
+        
+        spi->write(data_write, 2, NULL, 0);
+        
+        *spi_cs = 0;
+        return PAH_RET_SUCCESS;
+    }
+    
+    static pah_ret mbed_spi_burst_read(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t *data, uint32_t rx_size)
+    {
+        pah8011 *pah8011_state = (pah8011*)comm->user_data;
+        SPI *spi = pah8011_state->get_spi();
+        DigitalOut *spi_cs = pah8011_state->get_spi_cs();
+        
+        *spi_cs = 1;
+        /*
+        spi->write(addr);
+        
+        for (uint32_t i = 0; i < rx_size; ++i)
+            data[i] = spi->write(0x00);
+        */
+        
+        static char buf[256];
+        buf[0] = addr;
+        
+        static const uint8_t WRITE_LENGTH = 1;
+        spi->write(buf, WRITE_LENGTH, buf, WRITE_LENGTH + rx_size);
+        
+        memcpy(data, &buf[WRITE_LENGTH], rx_size);
+        
+        *spi_cs = 0;
+        return PAH_RET_SUCCESS;
+    }
+    
+    static pah_ret mbed_spi_read(struct pah_drv_comm_s *comm, uint8_t addr, uint8_t *data)
+    {
+        return mbed_spi_burst_read(comm, addr, data, 1);
+    }
+    
+    
+    pah8011::pah8011(I2C &i2c, uint8_t slave_id)
+        : m_i2c(&i2c)
+        , m_i2c_slave_id(slave_id)
+        , m_spi(NULL)
+        , m_spi_cs(NULL)
+        , m_is_ppg_enabled(false)
         , m_is_touch_enabled(false)
     {
-    }    
+        pah_drv_comm_s pah_drv_comm = {
+            .type           = pah_drv_comm_i2c,
+            .user_data      = this,
+            .max_length     = 256,
+            .write          = mbed_i2c_write,
+            .write_delay    = NULL,
+            .read           = mbed_i2c_read,
+            .burst_read     = mbed_i2c_burst_read,
+        };
+        pah_comm_set_drv_comm(&pah_drv_comm);
+    }
+    
+    pah8011::pah8011(SPI &spi, DigitalOut &cs)
+        : m_i2c(NULL)
+        , m_i2c_slave_id(0x15)
+        , m_spi(&spi)
+        , m_spi_cs(&cs)
+        , m_is_ppg_enabled(false)
+        , m_is_touch_enabled(false)
+    {
+        m_spi->format(8, 3);
+        
+        pah_drv_comm_s pah_drv_comm = {
+            .type           = pah_drv_comm_spi,
+            .user_data      = this,
+            .max_length     = 256,
+            .write          = mbed_spi_write,
+            .write_delay    = NULL,
+            .read           = mbed_spi_read,
+            .burst_read     = mbed_spi_burst_read,
+        };
+        pah_comm_set_drv_comm(&pah_drv_comm);
+    }
     
     pah8011::~pah8011()
     {
@@ -75,10 +172,8 @@
             debug_printf = disable_debug_printf;
     }
     
-    bool pah8011::init(I2C &i2c, uint8_t slave_id)
+    bool pah8011::init()
     {
-        g_i2c = &i2c;
-        
         pah_flags_s flags;
         memset(&flags, 0, sizeof(flags));
         
@@ -138,6 +233,23 @@
             
         return true;
     }
+    
+    I2C* pah8011::get_i2c() const
+    {
+        return m_i2c;
+    }
+    uint8_t pah8011::get_i2c_slave_id() const
+    {
+        return m_i2c_slave_id;
+    }
+    SPI* pah8011::get_spi() const
+    {
+        return m_spi;
+    }
+    DigitalOut* pah8011::get_spi_cs() const
+    {
+        return m_spi_cs;
+    }
  
     bool pah8011::select_mode()
     {
--- a/pixart_pah8011.h	Fri Oct 27 08:21:32 2017 +0000
+++ b/pixart_pah8011.h	Wed Jan 23 08:01:57 2019 +0000
@@ -25,12 +25,13 @@
         };
     
     public:
-        pah8011();
+        pah8011(I2C &i2c, uint8_t slave_id = 0x15);
+        pah8011(SPI &spi, DigitalOut &cs);
         ~pah8011();
         
         void    enable_debug_print(DEBUG_PRINT_HANDLE handler);
         
-        bool    init(I2C &i2c, uint8_t slave_id = 0x15);
+        bool    init();
         
         // operations
         bool    enable_ppg();
@@ -41,6 +42,12 @@
         // tasking
         bool    task();
         bool    get_result(task_result &result);
+        
+        // access
+        I2C*        get_i2c() const;
+        uint8_t     get_i2c_slave_id() const;
+        SPI*        get_spi() const;
+        DigitalOut* get_spi_cs() const;
     
     private:
         pah8011(const pah8011&); // = delete;
@@ -49,8 +56,17 @@
         bool    select_mode();
 
     private:
-        bool    m_is_ppg_enabled;
-        bool    m_is_touch_enabled;
+        // i2c
+        I2C         *m_i2c;
+        uint8_t     m_i2c_slave_id;
+        
+        // spi
+        SPI         *m_spi;
+        DigitalOut  *m_spi_cs;
+        
+        // state
+        bool        m_is_ppg_enabled;
+        bool        m_is_touch_enabled;
 
     };