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:
Giovanni Ricca 2022-09-10 14:55:11 +05:30
parent d4f70b25b3
commit b79c8098b8
No known key found for this signature in database
12 changed files with 44726 additions and 0 deletions

View File

@ -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"

View File

@ -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

View 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

View 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

View 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);
}

View 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

View 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, &current_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, &current_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, &reg_val, 1);
else
status = stmvl53l5_spi_write(spi_data, XSHUT_CTRL, &reg_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, &reg_val, 1);
else
status = stmvl53l5_spi_write(spi_data, XSHUT_CTRL, &reg_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;
}

View 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

View 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");

View 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;
}

View 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

File diff suppressed because it is too large Load Diff