input: Import stmvl53l5 driver
From branch: zijin-s-oss sed -i 's/\r//g' drivers/input/stmvl53l5/* Change-Id: I0acefc645fa75be2175fb6cb9747bfbf40c405b0
This commit is contained in:
parent
d4f70b25b3
commit
b79c8098b8
@ -203,6 +203,8 @@ source "drivers/input/rmi4/Kconfig"
|
||||
|
||||
source "drivers/input/fingerprint/Kconfig"
|
||||
|
||||
source "drivers/input/stmvl53l5/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
menu "Hardware I/O ports"
|
||||
|
@ -30,6 +30,7 @@ obj-$(CONFIG_INPUT_MISC) += misc/
|
||||
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
|
||||
|
||||
obj-$(CONFIG_RMI4_CORE) += rmi4/
|
||||
obj-$(CONFIG_STMVL53L5) += stmvl53l5/
|
||||
|
||||
ifeq ($(TARGET_PRODUCT), renoir)
|
||||
KBUILD_CPPFLAGS += -DQCOM_HAPTIC_BOB
|
||||
|
10
drivers/input/stmvl53l5/Kconfig
Normal file
10
drivers/input/stmvl53l5/Kconfig
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# ST SPI stmvl53l5 devices
|
||||
#
|
||||
menu "stmvl53l5"
|
||||
config STMVL53L5
|
||||
tristate "ST stmvl53l5 driver"
|
||||
help
|
||||
This enables the ST stmvl53l5 driver
|
||||
endmenu
|
||||
|
2
drivers/input/stmvl53l5/Makefile
Normal file
2
drivers/input/stmvl53l5/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_STMVL53L5) += stmvl53l5.o
|
||||
stmvl53l5-objs := stmvl53l5_spi.o stmvl53l5_i2c.o stmvl53l5_load_fw.o stmvl53l5_module.o
|
144
drivers/input/stmvl53l5/stmvl53l5_i2c.c
Normal file
144
drivers/input/stmvl53l5/stmvl53l5_i2c.c
Normal file
@ -0,0 +1,144 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2016, STMicroelectronics - All Rights Reserved
|
||||
|
||||
License terms: BSD 3-clause "New" or "Revised" License.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "stmvl53l5_i2c.h"
|
||||
|
||||
int32_t stmvl53l5_read_multi(struct i2c_client *client,
|
||||
uint8_t * i2c_buffer,
|
||||
uint16_t reg_index,
|
||||
uint8_t *pdata,
|
||||
uint32_t count)
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint32_t position = 0;
|
||||
uint32_t data_size = 0;
|
||||
struct i2c_msg message;
|
||||
|
||||
message.addr = 0x29;
|
||||
|
||||
do {
|
||||
data_size = (count - position) > VL53L5_COMMS_CHUNK_SIZE ? VL53L5_COMMS_CHUNK_SIZE : (count - position);
|
||||
|
||||
i2c_buffer[0] = (reg_index + position) >> 8;
|
||||
i2c_buffer[1] = (reg_index + position) & 0xFF;
|
||||
|
||||
message.flags = 0;
|
||||
message.buf = i2c_buffer;
|
||||
message.len = 2;
|
||||
|
||||
status = i2c_transfer(client->adapter, &message, 1);
|
||||
if (status != 1)
|
||||
return -EIO;
|
||||
|
||||
message.flags = 1;
|
||||
message.buf = pdata + position;
|
||||
message.len = data_size;
|
||||
|
||||
status = i2c_transfer(client->adapter, &message, 1);
|
||||
if (status != 1)
|
||||
return -EIO;
|
||||
|
||||
position += data_size;
|
||||
|
||||
} while (position < count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t stmvl53l5_write_multi(struct i2c_client *client,
|
||||
uint8_t *i2c_buffer,
|
||||
uint16_t reg_index,
|
||||
uint8_t *pdata,
|
||||
uint32_t count)
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint32_t position = 0;
|
||||
int32_t data_size = 0;
|
||||
struct i2c_msg message;
|
||||
|
||||
message.addr = 0x29;
|
||||
|
||||
do {
|
||||
data_size = (count - position) > (VL53L5_COMMS_CHUNK_SIZE-2) ? (VL53L5_COMMS_CHUNK_SIZE-2) : (count - position);
|
||||
|
||||
memcpy(&i2c_buffer[2], &pdata[position], data_size);
|
||||
|
||||
i2c_buffer[0] = (reg_index + position) >> 8;
|
||||
i2c_buffer[1] = (reg_index + position) & 0xFF;
|
||||
|
||||
message.flags = 0;
|
||||
message.len = data_size + 2;
|
||||
message.buf = i2c_buffer;
|
||||
|
||||
status = i2c_transfer(client->adapter, &message, 1);
|
||||
if (status != 1)
|
||||
return -EIO;
|
||||
|
||||
position += data_size;
|
||||
|
||||
} while (position < count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t stmvl53l5_write_byte(
|
||||
struct i2c_client *client, uint8_t * i2c_buffer, uint16_t address, uint8_t value)
|
||||
{
|
||||
return stmvl53l5_write_multi(client, i2c_buffer, address, &value, 1);
|
||||
}
|
||||
|
||||
int32_t stmvl53l5_read_byte(
|
||||
struct i2c_client *client, uint8_t * i2c_buffer, uint16_t address, uint8_t *p_value)
|
||||
{
|
||||
return stmvl53l5_read_multi(client, i2c_buffer, address, p_value, 1);
|
||||
}
|
63
drivers/input/stmvl53l5/stmvl53l5_i2c.h
Normal file
63
drivers/input/stmvl53l5/stmvl53l5_i2c.h
Normal file
@ -0,0 +1,63 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2016, STMicroelectronics - All Rights Reserved
|
||||
|
||||
License terms: BSD 3-clause "New" or "Revised" License.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef STMVL53L5_I2C_H
|
||||
#define STMVL53L5_I2C_H
|
||||
|
||||
#define VL53L5_COMMS_CHUNK_SIZE 1024
|
||||
|
||||
int32_t stmvl53l5_write_byte(
|
||||
struct i2c_client *client,
|
||||
uint8_t *i2c_buffer,
|
||||
uint16_t address,
|
||||
uint8_t value);
|
||||
|
||||
int32_t stmvl53l5_read_byte(
|
||||
struct i2c_client *client,
|
||||
uint8_t *i2c_buffer,
|
||||
uint16_t address,
|
||||
uint8_t *p_value);
|
||||
|
||||
int32_t stmvl53l5_read_multi(
|
||||
struct i2c_client *client,
|
||||
uint8_t *i2c_buffer,
|
||||
uint16_t reg_index,
|
||||
uint8_t *pdata,
|
||||
uint32_t count);
|
||||
|
||||
int32_t stmvl53l5_write_multi(
|
||||
struct i2c_client *client,
|
||||
uint8_t *i2c_buffer,
|
||||
uint16_t reg_index,
|
||||
uint8_t *pdata,
|
||||
uint32_t count);
|
||||
|
||||
#endif
|
635
drivers/input/stmvl53l5/stmvl53l5_load_fw.c
Normal file
635
drivers/input/stmvl53l5/stmvl53l5_load_fw.c
Normal file
@ -0,0 +1,635 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2016, STMicroelectronics - All Rights Reserved
|
||||
|
||||
License terms: BSD 3-clause "New" or "Revised" License.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "stmvl53l5_i2c.h"
|
||||
#include "stmvl53l5_spi.h"
|
||||
#include "vl53l5_fw_data.h"
|
||||
#include "stmvl53l5_load_fw.h"
|
||||
|
||||
#define VL53L5_COMMS_BUFFER_SIZE_BYTES 5052
|
||||
#define PAGE_SELECT 0x7FFF
|
||||
#define XSHUT_CTRL 0x0009
|
||||
|
||||
const uint8_t _fw_buffer[] = EWOKMZ_STXP70_TCPM_RAM_FULL;
|
||||
|
||||
uint8_t * host_dev_p_fw_buff;
|
||||
uint32_t host_dev_fw_buff_count;
|
||||
uint8_t * host_dev_p_comms_buff;
|
||||
uint32_t host_dev_comms_buff_max_count;
|
||||
|
||||
uint8_t _comms_buffer[VL53L5_COMMS_BUFFER_SIZE_BYTES] = {0};
|
||||
|
||||
#define VL53L5_ASSIGN_FW_BUFF(fw_buff_ptr, count) \
|
||||
do {\
|
||||
host_dev_p_fw_buff = (uint8_t *)(fw_buff_ptr);\
|
||||
host_dev_fw_buff_count = (count);\
|
||||
} while (0)
|
||||
|
||||
#define VL53L5_ASSIGN_COMMS_BUFF(comms_buff_ptr, max_count) \
|
||||
do {\
|
||||
host_dev_p_comms_buff = (comms_buff_ptr);\
|
||||
host_dev_comms_buff_max_count = (max_count);\
|
||||
} while (0)
|
||||
|
||||
#define MASK_XSHUT_REGISTER(reg_val, value)\
|
||||
do {\
|
||||
reg_val &= 0xf8;\
|
||||
reg_val |= (value ? 0x04 : 0x02);\
|
||||
} while (0)
|
||||
|
||||
|
||||
struct dci_ui__dev_info_t dev;
|
||||
|
||||
int32_t wait_mcu_boot(struct i2c_client *client, struct spi_data_t *spi_data, uint8_t i2c_not_spi, uint8_t *raw_data_buffer, uint8_t state)
|
||||
{
|
||||
int32_t status = 0; //STATUS_OK;
|
||||
// uint32_t start_time_ms = 0;
|
||||
// uint32_t current_time_ms = 0;
|
||||
|
||||
// status = vl53l5_get_tick_count(p_dev, &start_time_ms);
|
||||
// if (status < STATUS_OK)
|
||||
// goto exit;
|
||||
|
||||
VL53L5_GO2_STATUS_0(&dev).bytes = 0;
|
||||
|
||||
do {
|
||||
|
||||
if (i2c_not_spi)
|
||||
status = stmvl53l5_read_multi(client, raw_data_buffer, GO2_STATUS_0, &VL53L5_GO2_STATUS_0(&dev).bytes, 1);
|
||||
else
|
||||
status = stmvl53l5_spi_read(spi_data, GO2_STATUS_0, &VL53L5_GO2_STATUS_0(&dev).bytes, 1);
|
||||
if (status != 0) //< STATUS_OK)
|
||||
goto exit;
|
||||
|
||||
if (HW_TRAP(&dev)) {
|
||||
if (i2c_not_spi)
|
||||
status = stmvl53l5_read_multi(client, raw_data_buffer, GO2_STATUS_1, &VL53L5_GO2_STATUS_1(&dev).bytes, 1);
|
||||
else
|
||||
status = stmvl53l5_spi_read(spi_data, GO2_STATUS_1, &VL53L5_GO2_STATUS_1(&dev).bytes, 1);
|
||||
if (status != 0) //< STATUS_OK)
|
||||
goto exit;
|
||||
|
||||
// if (VL53L5_GO2_STATUS_1(&dev).bytes)
|
||||
// status = VL53L5_ERROR_MCU_ERROR_POWER_STATE;
|
||||
// else
|
||||
// status =
|
||||
// VL53L5_ERROR_FALSE_MCU_ERROR_POWER_STATE;
|
||||
status = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (MCU_ERROR(&dev)) {
|
||||
status = -1; //VL53L5_ERROR_MCU_ERROR_POWER_STATE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (((state == 1) && MCU_BOOT_COMPLETE(&dev)) ||
|
||||
((state == 0) && MCU_BOOT_NOT_COMPLETE(&dev)))
|
||||
break;
|
||||
|
||||
// status = vl53l5_get_tick_count(p_dev, ¤t_time_ms);
|
||||
// if (status < STATUS_OK)
|
||||
// goto exit;
|
||||
|
||||
// CHECK_FOR_TIMEOUT(
|
||||
// status, p_dev, start_time_ms, current_time_ms,
|
||||
// VL53L5_BOOT_COMPLETION_POLLING_TIMEOUT_MS);
|
||||
// if (status < STATUS_OK) {
|
||||
// status = VL53L5_ERROR_BOOT_COMPLETE_TIMEOUT;
|
||||
// goto exit;
|
||||
// }
|
||||
msleep(10);
|
||||
|
||||
} while (1);
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: wait_mcu_boot failed !\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t _check_rom_firmware_boot_cut_1_2(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
status = wait_mcu_boot(client, NULL, 1, raw_data_buffer, 1);
|
||||
if (status != 0)
|
||||
return -1;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x000E, 0x01);
|
||||
return status;
|
||||
}
|
||||
|
||||
int32_t check_rom_firmware_boot(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint8_t page = 0;
|
||||
uint8_t device_id = 0;
|
||||
uint8_t revision_id = 0;
|
||||
|
||||
//LOG_FUNCTION_START("");
|
||||
//printf("entering check rom fw boot ....\n");
|
||||
|
||||
status = stmvl53l5_write_multi(client, raw_data_buffer, PAGE_SELECT, &page, 1);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_read_multi(client, raw_data_buffer, 0x00, &device_id, 1);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
printk ("stmvl53l5: device id = 0x%x\n", device_id);
|
||||
|
||||
status = stmvl53l5_read_multi(client, raw_data_buffer, 0x01, &revision_id, 1);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
printk ("stmvl53l5: revision id = 0x%x\n", revision_id);
|
||||
|
||||
if ((device_id == 0xF0) && (revision_id == 0x02)) {
|
||||
status = _check_rom_firmware_boot_cut_1_2(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
} else {
|
||||
status = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: check_rom_firmware_boot failed : %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static int32_t _enable_host_access_to_go1_async(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
// uint32_t start_time_ms = 0;
|
||||
// uint32_t current_time_ms = 0;
|
||||
uint8_t m_status = 0;
|
||||
uint8_t revision_id = 0;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_read_byte(client, raw_data_buffer, 0x0001, &revision_id);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x02);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
if (revision_id != 2) {
|
||||
status = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x03, 0x0D);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x01);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
m_status = 0;
|
||||
// status = vl53l5_get_tick_count(p_dev, &start_time_ms);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
while ((m_status & 0x10) == 0) {
|
||||
status = stmvl53l5_read_byte(client, raw_data_buffer, 0x21, &m_status);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
// status = vl53l5_get_tick_count(p_dev, ¤t_time_ms);
|
||||
// if (status != 0)
|
||||
// goto exit;
|
||||
|
||||
// CHECK_FOR_TIMEOUT(
|
||||
// status, p_dev, start_time_ms, current_time_ms,
|
||||
// VL53L5_BOOT_COMPLETION_POLLING_TIMEOUT_MS);
|
||||
// if (status != 0) {
|
||||
// trace_print(
|
||||
// VL53L5_TRACE_LEVEL_ERRORS,
|
||||
// "ERROR: timeout waiting for mcu idle m_status %02x\n",
|
||||
// m_status);
|
||||
// status = VL53L5_ERROR_MCU_IDLE_TIMEOUT;
|
||||
// goto exit;
|
||||
//}
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x0C, 0x01);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: _enable_host_access_to_go1_async failed: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int32_t _set_to_power_on_status(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x101, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x102, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x4002, 0x01);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x4002, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x103, 0x01);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x400F, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x21A, 0x43);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x21A, 0x03);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x21A, 0x01);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x21A, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x219, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x21B, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: _set_to_power_on_status failed : %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int32_t _wake_up_mcu(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x0C, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x01);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x20, 0x07);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x20, 0x06);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: _wake_up_mcu failed : %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
int32_t _wait_for_boot_complete_before_fw_load(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
status = _enable_host_access_to_go1_async(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = _set_to_power_on_status(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = _wake_up_mcu(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: _wait_for_boot_complete_before_fw_load failed : %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
int32_t _reset_mcu_and_wait_boot(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint8_t u_start[] = {0, 0, 0x42, 0};
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_multi(client, raw_data_buffer, 0x114, u_start, 4);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x0B, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x0C, 0x00);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x0B, 0x01);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = wait_mcu_boot(client, NULL, 1, raw_data_buffer, 1);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: _reset_mcu_and_wait_boot failed : %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int32_t _wait_for_boot_complete_after_fw_load(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
status = _enable_host_access_to_go1_async(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = _reset_mcu_and_wait_boot(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: _wait_for_boot_complete_after_fw_load failed : %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int32_t _write_page(
|
||||
struct i2c_client *client, uint8_t * raw_data_buffer, uint32_t page_offset,
|
||||
uint32_t page_size, uint32_t max_chunk_size, uint32_t *p_write_count)
|
||||
{
|
||||
int32_t status;
|
||||
uint32_t write_size = 0;
|
||||
uint32_t remainder_size = 0;
|
||||
uint8_t *p_write_buff = NULL;
|
||||
|
||||
if ((page_offset + max_chunk_size) < page_size)
|
||||
write_size = max_chunk_size;
|
||||
else
|
||||
write_size = page_size - page_offset;
|
||||
|
||||
if (*p_write_count > host_dev_fw_buff_count) {
|
||||
|
||||
p_write_buff = host_dev_p_comms_buff;
|
||||
memset(p_write_buff, 0, write_size);
|
||||
} else {
|
||||
if ((host_dev_fw_buff_count - *p_write_count)
|
||||
< write_size) {
|
||||
|
||||
p_write_buff = host_dev_p_comms_buff;
|
||||
remainder_size =
|
||||
host_dev_fw_buff_count - *p_write_count;
|
||||
memcpy(p_write_buff,
|
||||
host_dev_p_fw_buff + *p_write_count,
|
||||
remainder_size);
|
||||
memset(p_write_buff + remainder_size,
|
||||
0,
|
||||
write_size - remainder_size);
|
||||
} else {
|
||||
|
||||
p_write_buff =
|
||||
host_dev_p_fw_buff + *p_write_count;
|
||||
}
|
||||
}
|
||||
|
||||
status = stmvl53l5_write_multi(client, raw_data_buffer, page_offset, p_write_buff,
|
||||
write_size);
|
||||
if (status != 0) {
|
||||
status = -1;
|
||||
goto exit;
|
||||
}
|
||||
(*p_write_count) += write_size;
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: _write_page failed : %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int32_t _download_fw_to_ram(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
uint16_t tdcm_offset = 0;
|
||||
uint8_t tdcm_page = 9;
|
||||
uint32_t tdcm_page_size = 0;
|
||||
uint32_t write_count = 0;
|
||||
|
||||
for (tdcm_page = 9; tdcm_page < 12; tdcm_page++) {
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, tdcm_page);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
if (tdcm_page == 9)
|
||||
tdcm_page_size = 0x8000;
|
||||
if (tdcm_page == 10)
|
||||
tdcm_page_size = 0x8000;
|
||||
if (tdcm_page == 11)
|
||||
tdcm_page_size = 0x5000;
|
||||
|
||||
for (tdcm_offset = 0; tdcm_offset < tdcm_page_size;
|
||||
tdcm_offset += VL53L5_COMMS_BUFFER_SIZE_BYTES) {
|
||||
status = _write_page(
|
||||
client, raw_data_buffer, tdcm_offset, tdcm_page_size,
|
||||
VL53L5_COMMS_BUFFER_SIZE_BYTES, &write_count);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (status != 0)
|
||||
printk("stmvl53l5: _download_fw_to_ram failed : %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int32_t load_firmware(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
status = _wait_for_boot_complete_before_fw_load(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = _download_fw_to_ram(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = _wait_for_boot_complete_after_fw_load(client, raw_data_buffer);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
status = stmvl53l5_write_byte(client, raw_data_buffer, 0x7FFF, 0x02);
|
||||
if (status != 0)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
printk("stmvl53l5: load_firmware : GO2s0=0x%x GO2s1=0x%x status=%d\n", VL53L5_GO2_STATUS_0(&dev).bytes, VL53L5_GO2_STATUS_1(&dev).bytes, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int32_t stmvl53l5_load_fw_stm(struct i2c_client *client, uint8_t * raw_data_buffer)
|
||||
{
|
||||
|
||||
int status = 0;
|
||||
|
||||
VL53L5_ASSIGN_FW_BUFF(_fw_buffer, sizeof(_fw_buffer));
|
||||
VL53L5_ASSIGN_COMMS_BUFF(_comms_buffer, sizeof(_comms_buffer));
|
||||
status = check_rom_firmware_boot(client, raw_data_buffer);
|
||||
status |= load_firmware(client, raw_data_buffer);
|
||||
printk("stmvl53l5: load_fw : %d\n", status);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
int32_t stmvl53l5_move_device_to_low_power(struct i2c_client *client, struct spi_data_t *spi_data, uint8_t i2c_not_spi, uint8_t * raw_data_buffer)
|
||||
{
|
||||
|
||||
int status = 0;
|
||||
uint8_t page = 0;
|
||||
uint8_t reg_val = 0;
|
||||
|
||||
// put the device in low power idle with comms enabled
|
||||
if (i2c_not_spi)
|
||||
status = stmvl53l5_write_multi(client, raw_data_buffer, PAGE_SELECT, &page, 1);
|
||||
else
|
||||
status = stmvl53l5_spi_write(spi_data, PAGE_SELECT, &page, 1);
|
||||
if (status != 0)
|
||||
return -1;
|
||||
|
||||
reg_val = 0;
|
||||
if (i2c_not_spi)
|
||||
status = stmvl53l5_read_multi(client, raw_data_buffer, XSHUT_CTRL, ®_val, 1);
|
||||
else
|
||||
status = stmvl53l5_spi_write(spi_data, XSHUT_CTRL, ®_val, 1);
|
||||
|
||||
if (status != 0)
|
||||
return -1;
|
||||
|
||||
MASK_XSHUT_REGISTER(reg_val, 0);
|
||||
|
||||
if (i2c_not_spi)
|
||||
status = stmvl53l5_write_multi(client, raw_data_buffer, XSHUT_CTRL, ®_val, 1);
|
||||
else
|
||||
status = stmvl53l5_spi_write(spi_data, XSHUT_CTRL, ®_val, 1);
|
||||
|
||||
status = wait_mcu_boot(client, spi_data, i2c_not_spi, raw_data_buffer, 0);
|
||||
if (status != 0)
|
||||
return -1;
|
||||
|
||||
printk("stmvl53l5: device set in low power (idle with comms) : %d\n", status);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
108
drivers/input/stmvl53l5/stmvl53l5_load_fw.h
Normal file
108
drivers/input/stmvl53l5/stmvl53l5_load_fw.h
Normal file
@ -0,0 +1,108 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2016, STMicroelectronics - All Rights Reserved
|
||||
|
||||
License terms: BSD 3-clause "New" or "Revised" License.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef STMVL53L5_LOAD_FW_H
|
||||
#define STMVL53L5_LOAD_FW_H
|
||||
|
||||
union dci_union__go2_status_0_go1_u {
|
||||
uint8_t bytes;
|
||||
struct {
|
||||
|
||||
uint8_t mcu__boot_complete_go1 : 1;
|
||||
|
||||
uint8_t mcu__analog_checks_ok_go1 : 1;
|
||||
|
||||
uint8_t mcu__threshold_triggered_g01 : 1;
|
||||
uint8_t mcu__error_flag_go1 : 1;
|
||||
uint8_t mcu__ui_range_data_present_go1 : 1;
|
||||
uint8_t mcu__ui_new_range_data_avail_go1 : 1;
|
||||
uint8_t mcu__ui_update_blocked_go1 : 1;
|
||||
|
||||
uint8_t mcu__hw_trap_flag_go1 : 1;
|
||||
};
|
||||
};
|
||||
|
||||
union dci_union__go2_status_1_go1_u {
|
||||
uint8_t bytes;
|
||||
struct {
|
||||
|
||||
uint8_t mcu__avdd_reg_ok_go1 : 1;
|
||||
|
||||
uint8_t mcu__pll_lock_ok_go1 : 1;
|
||||
|
||||
uint8_t mcu__ls_watchdog_pass_go1 : 1;
|
||||
|
||||
uint8_t mcu__warning_flag_go1 : 1;
|
||||
|
||||
uint8_t mcu__cp_collapse_flag_go1 : 1;
|
||||
uint8_t mcu__spare2 : 1;
|
||||
uint8_t mcu__spare3 : 1;
|
||||
uint8_t mcu__spare4 : 1;
|
||||
};
|
||||
};
|
||||
|
||||
struct dci_ui__dev_info_t {
|
||||
|
||||
union dci_union__go2_status_0_go1_u dev_info__go2_status_0;
|
||||
|
||||
union dci_union__go2_status_1_go1_u dev_info__go2_status_1;
|
||||
|
||||
uint8_t dev_info__device_status;
|
||||
|
||||
uint8_t dev_info__ui_stream_count;
|
||||
};
|
||||
|
||||
#define GO2_STATUS_0 0x6
|
||||
#define GO2_STATUS_1 0x7
|
||||
|
||||
#define VL53L5_GO2_STATUS_0(p_dev) \
|
||||
((p_dev)->dev_info__go2_status_0)
|
||||
|
||||
#define VL53L5_GO2_STATUS_1(p_dev) \
|
||||
((p_dev)->dev_info__go2_status_1)
|
||||
|
||||
#define HW_TRAP(p_dev)\
|
||||
(VL53L5_GO2_STATUS_0(p_dev).mcu__hw_trap_flag_go1 == 1)
|
||||
|
||||
#define MCU_ERROR(p_dev)\
|
||||
(VL53L5_GO2_STATUS_0(p_dev).mcu__error_flag_go1 == 1)
|
||||
|
||||
#define MCU_BOOT_COMPLETE(p_dev)\
|
||||
(VL53L5_GO2_STATUS_0(p_dev).mcu__boot_complete_go1 == 1)
|
||||
|
||||
#define MCU_BOOT_NOT_COMPLETE(p_dev)\
|
||||
(VL53L5_GO2_STATUS_0(p_dev).mcu__boot_complete_go1 == 0)
|
||||
|
||||
|
||||
int32_t stmvl53l5_load_fw_stm(struct i2c_client *client, uint8_t * i2c_buffer);
|
||||
int32_t stmvl53l5_move_device_to_low_power(struct i2c_client *client, struct spi_data_t *spi_data, uint8_t i2c_not_spi, uint8_t * raw_data_buffer);
|
||||
|
||||
#endif
|
602
drivers/input/stmvl53l5/stmvl53l5_module.c
Normal file
602
drivers/input/stmvl53l5/stmvl53l5_module.c
Normal file
@ -0,0 +1,602 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2016, STMicroelectronics - All Rights Reserved
|
||||
|
||||
License terms: BSD 3-clause "New" or "Revised" License.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "stmvl53l5_i2c.h"
|
||||
#include "stmvl53l5_spi.h"
|
||||
#include "stmvl53l5_load_fw.h"
|
||||
|
||||
#define STMVL53L5_DRV_NAME "stmvl53l5"
|
||||
#define STMVL53L5_SLAVE_ADDR 0x29
|
||||
|
||||
#define ST_TOF_IOCTL_TRANSFER _IOWR('a',0x1, void*)
|
||||
|
||||
struct stmvl53l5_comms_struct {
|
||||
__u16 len;
|
||||
__u16 reg_index;
|
||||
__u8 *buf;
|
||||
__u8 write_not_read;
|
||||
};
|
||||
|
||||
static struct miscdevice st_tof_miscdev;
|
||||
static uint8_t * raw_data_buffer = NULL;
|
||||
|
||||
static uint8_t i2c_not_spi = 1;
|
||||
|
||||
static uint8_t i2c_driver_added = 0;
|
||||
static uint8_t spi_driver_registered = 0;
|
||||
static uint8_t misc_registered = 0;
|
||||
|
||||
static struct spi_data_t spi_data;
|
||||
|
||||
// ------- i2c ---------------------------
|
||||
static const struct i2c_device_id stmvl53l5_i2c_id[] = {
|
||||
{STMVL53L5_DRV_NAME, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
// ------- spi ---------------------------
|
||||
static const struct spi_device_id stmvl53l5_spi_id[] = {
|
||||
{STMVL53L5_DRV_NAME, 0 },
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, stmvl53l5_i2c_id);
|
||||
|
||||
static const struct of_device_id st_tof_of_match[] = {
|
||||
{
|
||||
/* An older compatible */
|
||||
.compatible = "st,stmvl53l5",
|
||||
.data = STMVL53L5_DRV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, st_tof_of_match); // add to the kernel device tree table
|
||||
|
||||
static struct i2c_client *stmvl53l5_i2c_client = NULL;
|
||||
|
||||
static struct regulator *p_3v0_vreg = NULL;
|
||||
static struct regulator *p_1v8_vreg = NULL;
|
||||
|
||||
static int enable_regulator_1V8(struct device *dev, struct regulator **pp_vreg)
|
||||
{
|
||||
int ret_source = 0;
|
||||
int ret_enable = 0;
|
||||
*pp_vreg = regulator_get(dev, "_1P8_power");
|
||||
if (IS_ERR(*pp_vreg)) {
|
||||
pr_err("stmvl53l5 : Error at %s(%d)\n", __func__, __LINE__);
|
||||
ret_source = PTR_ERR(*pp_vreg);
|
||||
goto put_regulator;
|
||||
} else {
|
||||
pr_info("stmvl53l5 : 1P8 successful found\n");
|
||||
}
|
||||
ret_source = regulator_set_voltage(*pp_vreg, 1800000, 1800000);
|
||||
|
||||
if (ret_source) {
|
||||
pr_err("stmvl53l5 : Error at %s(%d)\n", __func__, __LINE__);
|
||||
goto put_regulator;
|
||||
}
|
||||
ret_source = regulator_set_load(*pp_vreg, 85000);
|
||||
if (ret_source) {
|
||||
pr_err("stmvl53l5 : Error at %s(%d)\n", __func__, __LINE__);
|
||||
goto put_regulator;
|
||||
}
|
||||
ret_enable = regulator_enable(*pp_vreg);
|
||||
if (ret_enable) {
|
||||
pr_err("stmvl53l5 : Error at %s(%d)\n", __func__, __LINE__);
|
||||
goto disable_regulator;
|
||||
}
|
||||
|
||||
disable_regulator:
|
||||
if(ret_enable) {
|
||||
regulator_disable(*pp_vreg);
|
||||
regulator_set_load(*pp_vreg, 0);
|
||||
regulator_set_voltage(*pp_vreg, 0, 1800000);
|
||||
}
|
||||
put_regulator:
|
||||
if (ret_enable || ret_source) {
|
||||
regulator_put(*pp_vreg);
|
||||
*pp_vreg = NULL;
|
||||
}
|
||||
return ret_enable || ret_source;
|
||||
}
|
||||
|
||||
static int enable_regulator_3V0(struct device *dev, struct regulator **pp_vreg)
|
||||
{
|
||||
int ret_source = 0;
|
||||
int ret_enable = 0;
|
||||
*pp_vreg = regulator_get(dev, "_3P0_power");
|
||||
if (IS_ERR(*pp_vreg)) {
|
||||
pr_err("stmvl53l5 : Error at %s(%d)\n", __func__, __LINE__);
|
||||
ret_source = PTR_ERR(*pp_vreg);
|
||||
goto put_regulator;
|
||||
} else {
|
||||
pr_info("stmvl53l5 : 3P0 successful found\n");
|
||||
}
|
||||
ret_source = regulator_set_voltage(*pp_vreg, 3008000, 3008000);
|
||||
|
||||
if (ret_source) {
|
||||
pr_err("stmvl53l5 : Error at %s(%d)\n", __func__, __LINE__);
|
||||
goto put_regulator;
|
||||
}
|
||||
ret_source = regulator_set_load(*pp_vreg, 85000);
|
||||
if (ret_source) {
|
||||
pr_err("stmvl53l5 : Error at %s(%d)\n", __func__, __LINE__);
|
||||
goto put_regulator;
|
||||
}
|
||||
ret_enable = regulator_enable(*pp_vreg);
|
||||
if (ret_enable) {
|
||||
pr_err("stmvl53l5 : Error at %s(%d)\n", __func__, __LINE__);
|
||||
goto disable_regulator;
|
||||
}
|
||||
|
||||
disable_regulator:
|
||||
if(ret_enable) {
|
||||
regulator_disable(*pp_vreg);
|
||||
regulator_set_load(*pp_vreg, 0);
|
||||
regulator_set_voltage(*pp_vreg, 0, 3008000);
|
||||
}
|
||||
put_regulator:
|
||||
if (ret_enable || ret_source) {
|
||||
regulator_put(*pp_vreg);
|
||||
*pp_vreg = NULL;
|
||||
}
|
||||
return ret_enable || ret_source;
|
||||
}
|
||||
|
||||
static int enable_power(struct spi_device *spi)
|
||||
{
|
||||
int ret = -1;
|
||||
ret = enable_regulator_3V0(&spi->dev,&p_3v0_vreg);
|
||||
ret |= enable_regulator_1V8(&spi->dev,&p_1v8_vreg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void disable_power(void)
|
||||
{
|
||||
regulator_disable(p_1v8_vreg);
|
||||
regulator_set_load(p_1v8_vreg, 0);
|
||||
regulator_set_voltage(p_1v8_vreg, 0, 1800000);
|
||||
regulator_put(p_1v8_vreg);
|
||||
p_1v8_vreg = NULL;
|
||||
|
||||
regulator_disable(p_3v0_vreg);
|
||||
regulator_set_load(p_3v0_vreg, 0);
|
||||
regulator_set_voltage(p_3v0_vreg, 0, 3008000);
|
||||
regulator_put(p_3v0_vreg);
|
||||
p_3v0_vreg = NULL;
|
||||
}
|
||||
|
||||
static int stmvl53l5_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
printk("stmvl53l5 : %s(%d)\n", __func__, __LINE__);
|
||||
if (unlikely(spi_data.nusers >= SHRT_MAX)) {
|
||||
dev_err(&spi_data.device->dev, "device busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
mutex_lock(&spi_data.mutex);
|
||||
/*if (spi_data.nusers == 0) {
|
||||
regulator_enable(p_3v0_vreg);
|
||||
regulator_enable(p_1v8_vreg);
|
||||
}*/
|
||||
spi_data.nusers++;
|
||||
printk("stmvl53l5_open : spi_data.nusers = %u\n", spi_data.nusers);
|
||||
mutex_unlock(&spi_data.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmvl53l5_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
printk("stmvl53l5 : %s(%d)\n", __func__, __LINE__);
|
||||
mutex_lock(&spi_data.mutex);
|
||||
printk("stmvl53l5_release : spi_data.nusers = %u\n", spi_data.nusers);
|
||||
spi_data.nusers--;
|
||||
/*if (spi_data.nusers == 0) {
|
||||
regulator_disable(p_1v8_vreg);
|
||||
regulator_disable(p_3v0_vreg);
|
||||
}*/
|
||||
mutex_unlock(&spi_data.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long stmvl53l5_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct i2c_msg st_i2c_message;
|
||||
struct stmvl53l5_comms_struct comms_struct;
|
||||
int32_t ret = 0;
|
||||
uint16_t index, transfer_size, chunk_size;
|
||||
u8 __user *data_ptr = NULL;
|
||||
|
||||
pr_debug("stmvl53l5_ioctl : cmd = %u\n", cmd);
|
||||
switch (cmd) {
|
||||
case ST_TOF_IOCTL_TRANSFER:
|
||||
|
||||
ret = copy_from_user(&comms_struct, (void __user *)arg, sizeof(comms_struct));
|
||||
if (ret) {
|
||||
pr_err("Error at %s(%d)\n", __func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
//printk("Transfer. write_not_read = %d, reg_index = 0x%x size = %d\n", comms_struct.write_not_read, comms_struct.reg_index, comms_struct.len);
|
||||
|
||||
if (i2c_not_spi) {
|
||||
// address and buis the same whatever the transfers to be done !
|
||||
st_i2c_message.addr = 0x29;
|
||||
// st_i2c_message.buf is the same whatever the transfers to be done
|
||||
st_i2c_message.buf = raw_data_buffer;
|
||||
}
|
||||
|
||||
if (!comms_struct.write_not_read) {
|
||||
data_ptr = (u8 __user *)(comms_struct.buf);
|
||||
}
|
||||
|
||||
// in case of i2c write, it is a single transfer with read index set in the 2 first bytes
|
||||
// the other case use fully the raw data buffer for raw data transfers
|
||||
if ((i2c_not_spi) && (comms_struct.write_not_read))
|
||||
chunk_size = VL53L5_COMMS_CHUNK_SIZE - 2;
|
||||
else
|
||||
chunk_size = VL53L5_COMMS_CHUNK_SIZE;
|
||||
|
||||
// index is the number of bytes already transfered
|
||||
index = 0;
|
||||
|
||||
do {
|
||||
// take the max number of bytes that can be transfered
|
||||
transfer_size = (comms_struct.len - index) > chunk_size ? chunk_size : (comms_struct.len - index);
|
||||
|
||||
// ----- WRITE
|
||||
if (comms_struct.write_not_read) {
|
||||
// ---- i2c
|
||||
if (i2c_not_spi) {
|
||||
// put red index at the beginning of the buffer
|
||||
raw_data_buffer[0] = (uint8_t)(((comms_struct.reg_index + index) & 0xFF00) >> 8);
|
||||
raw_data_buffer[1] = (uint8_t)((comms_struct.reg_index + index) & 0x00FF);
|
||||
|
||||
ret = copy_from_user(&raw_data_buffer[2], comms_struct.buf + index, transfer_size);
|
||||
if (ret) {
|
||||
pr_err("Error at %s(%d)\n", __func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
st_i2c_message.len = transfer_size + 2;
|
||||
st_i2c_message.flags = 0;
|
||||
ret = i2c_transfer(stmvl53l5_i2c_client->adapter, &st_i2c_message, 1);
|
||||
if (ret != 1) {
|
||||
pr_err("Error %d at %s(%d)\n",ret, __func__, __LINE__);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
// ---- spi
|
||||
else {
|
||||
ret = copy_from_user(raw_data_buffer, comms_struct.buf + index, transfer_size);
|
||||
if (ret) {
|
||||
pr_err("stmvl53l5: Error at %s(%d)\n", __func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = stmvl53l5_spi_write(&spi_data, comms_struct.reg_index + index, raw_data_buffer, transfer_size);
|
||||
if (ret) {
|
||||
pr_err("Error %d at %s(%d)\n",ret, __func__, __LINE__);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----- READ
|
||||
else {
|
||||
// ---- i2c
|
||||
if (i2c_not_spi) {
|
||||
// write reg_index
|
||||
st_i2c_message.len = 2;
|
||||
st_i2c_message.flags = 0;
|
||||
raw_data_buffer[0] = (uint8_t)(((comms_struct.reg_index + index) & 0xFF00) >> 8);
|
||||
raw_data_buffer[1] = (uint8_t)((comms_struct.reg_index + index) & 0x00FF);
|
||||
|
||||
ret = i2c_transfer(stmvl53l5_i2c_client->adapter, &st_i2c_message, 1);
|
||||
if (ret != 1) {
|
||||
pr_err("Error at %s(%d)\n", __func__, __LINE__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
st_i2c_message.len = transfer_size;
|
||||
st_i2c_message.flags = 1;
|
||||
|
||||
ret = i2c_transfer(stmvl53l5_i2c_client->adapter, &st_i2c_message, 1);
|
||||
if (ret != 1) {
|
||||
pr_err("Error at %s(%d)\n", __func__, __LINE__);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
// ---- spi
|
||||
else {
|
||||
ret = stmvl53l5_spi_read(&spi_data, comms_struct.reg_index + index, raw_data_buffer, transfer_size);
|
||||
if (ret) {
|
||||
pr_err("stmvl53l5: Error at %s(%d)\n", __func__, __LINE__);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
// copy to user buffer the read transfer
|
||||
ret = copy_to_user(data_ptr + index, raw_data_buffer, transfer_size);
|
||||
|
||||
if (ret) {
|
||||
pr_err("Error at %s(%d)\n", __func__, __LINE__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
} // ----- READ
|
||||
|
||||
index += transfer_size;
|
||||
|
||||
} while (index < comms_struct.len);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations stmvl53l5_ranging_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = stmvl53l5_ioctl,
|
||||
.open = stmvl53l5_open,
|
||||
.release = stmvl53l5_release,
|
||||
};
|
||||
|
||||
static int stmvl53l5_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
uint8_t page = 0, revision_id = 0, device_id = 0;
|
||||
stmvl53l5_i2c_client = client;
|
||||
|
||||
i2c_not_spi = 1;
|
||||
|
||||
printk("stmvl53l5: probing i2c\n");
|
||||
|
||||
raw_data_buffer = kzalloc(VL53L5_COMMS_CHUNK_SIZE, GFP_DMA | GFP_KERNEL);
|
||||
if (raw_data_buffer == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = stmvl53l5_write_multi(client, raw_data_buffer, 0x7FFF, &page, 1);
|
||||
ret |= stmvl53l5_read_multi(client, raw_data_buffer, 0x00, &device_id, 1);
|
||||
ret |= stmvl53l5_read_multi(client, raw_data_buffer, 0x01, &revision_id, 1);
|
||||
|
||||
if ((device_id != 0xF0) || (revision_id != 0x02)) {
|
||||
pr_err("stmvl53l5: Error. Could not read device and revision id registers\n");
|
||||
return ret;
|
||||
}
|
||||
printk("stmvl53l5: device_id : 0x%x. revision_id : 0x%x\n", device_id, revision_id);
|
||||
|
||||
st_tof_miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
st_tof_miscdev.name = "stmvl53l5";
|
||||
st_tof_miscdev.fops = &stmvl53l5_ranging_fops;
|
||||
st_tof_miscdev.mode = 0444;
|
||||
|
||||
ret = misc_register(&st_tof_miscdev);
|
||||
if (ret) {
|
||||
pr_err("stmvl53l5 : Failed to create misc device, err = %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
misc_registered = 1;
|
||||
|
||||
ret = stmvl53l5_load_fw_stm(client, raw_data_buffer);
|
||||
if (ret) {
|
||||
pr_err("stmvl53l5 : Failed in loading the FW into the device, err = %d\n", ret);
|
||||
}
|
||||
|
||||
ret = stmvl53l5_move_device_to_low_power(client, NULL, 1, raw_data_buffer);
|
||||
if (ret) {
|
||||
pr_err("stmvl53l5 : could not move the device to low power = %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmvl53l5_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
|
||||
if (raw_data_buffer)
|
||||
kfree(raw_data_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver stmvl53l5_i2c_driver = {
|
||||
.driver = {
|
||||
.name = STMVL53L5_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(st_tof_of_match), // for platform register to pick up the dts info
|
||||
},
|
||||
.probe = stmvl53l5_i2c_probe,
|
||||
.remove = stmvl53l5_i2c_remove,
|
||||
.id_table = stmvl53l5_i2c_id,
|
||||
};
|
||||
|
||||
static int stmvl53l5_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret = -1;
|
||||
uint8_t page = 0, revision_id = 0, device_id = 0;
|
||||
|
||||
if(enable_power(spi)) {
|
||||
pr_err("stmvl53l5: Error. Could not enable power, return -1\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_not_spi = 0;
|
||||
mutex_init(&spi_data.mutex);
|
||||
|
||||
spi_data.device = spi;
|
||||
spi_data.device->mode |= SPI_CPHA;
|
||||
spi_data.device->mode |= SPI_CPOL;
|
||||
|
||||
ret = stmvl53l5_spi_write(&spi_data, 0x7FFF, &page, 1);
|
||||
ret |= stmvl53l5_spi_read(&spi_data, 0x00, &device_id, 1);
|
||||
ret |= stmvl53l5_spi_read(&spi_data, 0x01, &revision_id, 1);
|
||||
|
||||
if ((device_id != 0xF0) || (revision_id != 0x02)) {
|
||||
pr_err("stmvl53l5: Error. Could not read device and revision id registers\n");
|
||||
ret = -1;
|
||||
goto quitpower;
|
||||
}
|
||||
printk("stmvl53l5: device_id : 0x%x. revision_id : 0x%x\n", device_id, revision_id);
|
||||
|
||||
raw_data_buffer = kzalloc(VL53L5_COMMS_CHUNK_SIZE, GFP_DMA | GFP_KERNEL);
|
||||
if (raw_data_buffer == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto quitpower;
|
||||
}
|
||||
st_tof_miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
st_tof_miscdev.name = "stmvl53l5";
|
||||
st_tof_miscdev.fops = &stmvl53l5_ranging_fops;
|
||||
st_tof_miscdev.mode = 0444;
|
||||
|
||||
ret = misc_register(&st_tof_miscdev);
|
||||
if (ret) {
|
||||
pr_err("stmvl53l5 : Failed to create misc device, err = %d\n", ret);
|
||||
ret = -2;
|
||||
goto quitmisc;
|
||||
}
|
||||
|
||||
misc_registered = 1;
|
||||
|
||||
/*regulator_disable(p_1v8_vreg);
|
||||
regulator_disable(p_3v0_vreg);*/
|
||||
quitmisc:
|
||||
if (ret == -2)
|
||||
misc_deregister(&st_tof_miscdev);
|
||||
|
||||
quitpower:
|
||||
if(ret == -1 || ret == -2 || ret == -ENOMEM)
|
||||
disable_power();
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int stmvl53l5_spi_remove(struct spi_device *device)
|
||||
{
|
||||
|
||||
if (raw_data_buffer)
|
||||
kfree(raw_data_buffer);
|
||||
disable_power();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver stmvl53l5_spi_driver = {
|
||||
.driver = {
|
||||
.name = STMVL53L5_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = stmvl53l5_spi_probe,
|
||||
.remove = stmvl53l5_spi_remove,
|
||||
.id_table = stmvl53l5_spi_id,
|
||||
};
|
||||
|
||||
static int __init st_tof_module_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
printk("stmvl53l5: module init\n");
|
||||
|
||||
/* register as a i2c client device */
|
||||
/* ret = i2c_add_driver(&stmvl53l5_i2c_driver);
|
||||
|
||||
if (ret) {
|
||||
i2c_del_driver(&stmvl53l5_i2c_driver);
|
||||
printk("stmvl53l5: could not add i2c driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_driver_added = 1;
|
||||
*/
|
||||
ret = spi_register_driver(&stmvl53l5_spi_driver);
|
||||
if (ret) {
|
||||
printk("stmvl53l5: could not register spi driver : %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_driver_registered = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit st_tof_module_exit(void)
|
||||
{
|
||||
|
||||
printk("stmvl53l5 : module exit\n");
|
||||
|
||||
if (misc_registered) {
|
||||
misc_deregister(&st_tof_miscdev);
|
||||
misc_registered = 0;
|
||||
}
|
||||
|
||||
if (spi_driver_registered) {
|
||||
spi_unregister_driver(&stmvl53l5_spi_driver);
|
||||
spi_driver_registered = 0;
|
||||
}
|
||||
|
||||
if (i2c_driver_added) {
|
||||
i2c_del_driver(&stmvl53l5_i2c_driver);
|
||||
i2c_driver_added = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module_init(st_tof_module_init);
|
||||
module_exit(st_tof_module_exit);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
|
||||
|
||||
|
88
drivers/input/stmvl53l5/stmvl53l5_spi.c
Normal file
88
drivers/input/stmvl53l5/stmvl53l5_spi.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of VL53L5 Kernel Driver
|
||||
*
|
||||
* Copyright (C) 2020, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* License terms: STMicroelectronics Proprietary in accordance with licensing
|
||||
* terms at www.st.com/sla0081
|
||||
*
|
||||
* STMicroelectronics confidential
|
||||
* Reproduction and Communication of this document is strictly prohibited unless
|
||||
* specifically authorized in writing by STMicroelectronics.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "stmvl53l5_spi.h"
|
||||
|
||||
|
||||
#define SPI_READWRITE_BIT 0x8000
|
||||
|
||||
#define SPI_WRITE_MASK(x) (x | SPI_READWRITE_BIT)
|
||||
#define SPI_READ_MASK(x) (x & ~SPI_READWRITE_BIT)
|
||||
|
||||
int stmvl53l5_spi_write(struct spi_data_t *spi_data, int index, uint8_t *data, uint16_t len)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t index_bytes[2] = {0};
|
||||
struct spi_message m;
|
||||
struct spi_transfer t[2];
|
||||
|
||||
spi_message_init(&m);
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
index_bytes[0] = ((SPI_WRITE_MASK(index) & 0xff00) >> 8);
|
||||
index_bytes[1] = (SPI_WRITE_MASK(index) & 0xff);
|
||||
|
||||
t[0].tx_buf = index_bytes;
|
||||
t[0].len = 2;
|
||||
|
||||
t[1].tx_buf = data;
|
||||
t[1].len = (unsigned int)len;
|
||||
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
status = spi_sync(spi_data->device, &m);
|
||||
if (status != 0) {
|
||||
printk("stmvl53l5 : spi_sync failed. %d", status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
int stmvl53l5_spi_read(struct spi_data_t *spi_data, int index, uint8_t *data, uint16_t len)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t index_bytes[2] = {0};
|
||||
struct spi_message m;
|
||||
struct spi_transfer t[2];
|
||||
|
||||
spi_message_init(&m);
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
index_bytes[0] = ((SPI_READ_MASK(index) >> 8) & 0xff);
|
||||
index_bytes[1] = (SPI_READ_MASK(index) & 0xff);
|
||||
|
||||
t[0].tx_buf = index_bytes;
|
||||
t[0].len = 2;
|
||||
|
||||
t[1].rx_buf = data;
|
||||
t[1].len = (unsigned int)len;
|
||||
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
status = spi_sync(spi_data->device, &m);
|
||||
if (status != 0) {
|
||||
printk("stmvl53l5 : spi_sync failed. %d", status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
44
drivers/input/stmvl53l5/stmvl53l5_spi.h
Normal file
44
drivers/input/stmvl53l5/stmvl53l5_spi.h
Normal file
@ -0,0 +1,44 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2016, STMicroelectronics - All Rights Reserved
|
||||
|
||||
License terms: BSD 3-clause "New" or "Revised" License.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef STMVL53L5_SPI_H
|
||||
#define STMVL53L5_SPI_H
|
||||
|
||||
struct spi_data_t {
|
||||
struct spi_device *device;
|
||||
u16 nusers;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
int stmvl53l5_spi_write(struct spi_data_t *spi_data, int index, uint8_t *data, uint16_t len);
|
||||
int stmvl53l5_spi_read(struct spi_data_t *spi_data, int index, uint8_t *data, uint16_t len);
|
||||
|
||||
#endif
|
43027
drivers/input/stmvl53l5/vl53l5_fw_data.h
Normal file
43027
drivers/input/stmvl53l5/vl53l5_fw_data.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user