Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75d734e2 authored by Gidon Studinski's avatar Gidon Studinski
Browse files

msm: wigig_sensing: initial commit of wigig_sensing SPI driver



This driver adds support for sensing use cases over 60GHz frequency band.
Sensing uses 60GHz radio signal to 'sense' the environment, allowing
various use cases such as proximity detection, face recognition, gesture
detection and more.

The driver communicates with the QCA6436 HW using SPI bus. The driver
requires SPI and wil6210 drivers to operate.

Change-Id: Ieaae89de8ef77617a24efafea0f476a3546cf27f
Signed-off-by: default avatarGidon Studinski <gidons@codeaurora.org>
parent 786601f4
Loading
Loading
Loading
Loading
+11 −0
Original line number Original line Diff line number Diff line
@@ -585,6 +585,17 @@ config TEST_IRQ_REQUESTER


	  If in doubt, say N.
	  If in doubt, say N.


config WIGIG_SENSING_SPI
	tristate "Sensing over 60GHz using wil6210 / SPI bus"
	depends on SPI && WIL6210
	default n
	help
	  This module adds support for various sensing use cases, like gesture
	  detection, face recognition, proximity detection and more. The sensor
	  operates over 60GHz frequency band, using low power SPI interface.
	  The output of the driver is CIRs (Channel Impulse Response) which
	  must be processed in user space in order to get meaningful results.

source "drivers/misc/c2port/Kconfig"
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
source "drivers/misc/cb710/Kconfig"
+2 −0
Original line number Original line Diff line number Diff line
@@ -71,3 +71,5 @@ obj-$(CONFIG_TEST_IRQ_REQUESTER) += irq_requester.o
obj-$(CONFIG_OKL4_USER_VIPC)    += okl4-vipc.o
obj-$(CONFIG_OKL4_USER_VIPC)    += okl4-vipc.o
obj-$(CONFIG_OKL4_GUEST)        += okl4-panic.o
obj-$(CONFIG_OKL4_GUEST)        += okl4-panic.o
obj-$(CONFIG_OKL4_LINK_SHBUF)    += okl4-link-shbuf.o
obj-$(CONFIG_OKL4_LINK_SHBUF)    += okl4-link-shbuf.o
obj-$(CONFIG_WIGIG_SENSING_SPI)	+= wigig_sensing.o
+1421 −0

File added.

Preview size limit exceeded, changes collapsed.

+200 −0
Original line number Original line Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2019, The Linux foundation. All rights reserved.
 */

#ifndef __WIGIG_SENSING_H__
#define __WIGIG_SENSING_H__
#include <linux/cdev.h>
#include <linux/circ_buf.h>
#include <linux/slab.h>
#include <uapi/misc/wigig_sensing_uapi.h>

#ifdef pr_fmt
#undef pr_fmt
#endif

#define pr_fmt(fmt) "[wigig_sensing]: " fmt

/* Registers */
#define RGF_USER_SPI_SPI_MBOX_FILL_STATUS (0x880080)
#define RGF_USER_SPI_SPI_EXT_MBOX_OUTB    (0x880084)
#define RGF_USER_SPI_SPI_MBOX_INB         (0x880088)
#define RGF_SPI_FIFO_CONTROL_ADDR         (0x8800A0)
#define RGF_SPI_FIFO_WR_PTR_ADDR          (0x88009C)
#define RGF_SPI_FIFO_RD_PTR_ADDR          (0x880098)
#define RGF_SPI_FIFO_BASE_ADDR_ADDR       (0x880094)
#define RGF_SPI_CONTROL_ADDR              (0x880090)
#define RGF_SPI_CONFIG_ADDR               (0x88008C)

#define SPIS_TRNS_LEN_REG_ADDR          (0x50)
#define ADDR_WIDTH                      (3)
#define DUMMY_BYTES_WIDTH               (4)
#define OPCODE_WIDTH                    (1)
#define SPIS_SANITY_REG_ADDR            (0x0)
#define SPIS_SANITY_REG_VAL             (0xDEADBEEF)
#define SPIS_CFG_REG_ADDR               (0xC)
#define JTAG_ID_REG_ADDR                (0x880000)
#define JTAG_ID                         (0x1007E0E1)
/* optimized configuration with 4 dummy bytes */
#define SPIS_CONFIG_REG_OPT_VAL         (0x44200800)
#define SPIS_EXTENDED_RESET_COMMAND_LEN (225)

#define SPI_MAX_TRANSACTION_SIZE (8*1024)
#define SPI_CMD_TRANSACTION_SIZE (512)
#define SPI_BUFFER_SIZE (SPI_MAX_TRANSACTION_SIZE + OPCODE_WIDTH + \
			 ADDR_WIDTH + DUMMY_BYTES_WIDTH)
#define SPI_CMD_BUFFER_SIZE (SPI_CMD_TRANSACTION_SIZE + OPCODE_WIDTH + \
			     ADDR_WIDTH + DUMMY_BYTES_WIDTH)

#define INT_FW_READY          BIT(24)
#define INT_DATA_READY        BIT(25)
#define INT_FIFO_READY        BIT(26)
#define INT_SYSASSERT         BIT(29)
#define INT_DEEP_SLEEP_EXIT   BIT(30)
union user_rgf_spi_status {
	struct {
		u16 fill_level:16;
		int reserved1:3;
		u8 spi_fifo_thr_status:1;
		u8 spi_fifo_empty_status:1;
		u8 spi_fifo_full_status:1;
		u8 spi_fifo_underrun_status:1;
		u8 spi_fifo_overrun_status:1;

		/* mbox_outb */
		u8 int_fw_ready:1; /* FW MBOX ready */
		u8 int_data_ready:1; /* data available on FIFO */
		u8 int_fifo_ready:1; /* FIFO status update */
		u8 reserved2:1;
		u8 reserved3:1;
		u8 int_sysassert:1; /* SYSASSERT occurred */
		u8 int_deep_sleep_exit:1;
		u8 reserved4:1;
	} __packed b;
	u32 v;
} __packed;

union user_rgf_spi_mbox_inb {
	struct {
		u8 mode:4;
		u8 channel_request:4;
		u32 reserved:23;
		u8 deassert_dri:1;
	}  __packed b;
	u32 v;
} __packed;

union rgf_spi_config {
	struct {
		u16 size:16;
		u8 reserved1:8;
		u8 mbox_auto_clear_disable:1;
		u8 status_auto_clear_disable:1;
		u8 reserved2:5;
		u8 enable:1;
	} __packed b;
	u32 v;
} __packed;

union rgf_spi_control {
	struct {
		u8 read_ptr_clear:1;
		u8 fill_level_clear:1;
		u8 thresh_reach_clear:1;
		u8 status_field_clear:1;
		u8 mbox_field_clear:1;
		u32 reserved:27;
	} __packed b;
	u32 v;
} __packed;

struct cir_data {
	struct circ_buf b;
	u32 size_bytes;
	struct mutex lock;
};

struct spi_fifo {
	u32 wr_ptr;
	u32 rd_ptr;
	u32 base_addr;
	union rgf_spi_config config;
	union rgf_spi_control control;
};

/**
 * State machine states
 * TODO: Document states
 */
enum wigig_sensing_stm_e {
	WIGIG_SENSING_STATE_MIN = 0,
	WIGIG_SENSING_STATE_INITIALIZED,
	WIGIG_SENSING_STATE_SPI_READY,
	WIGIG_SENSING_STATE_READY_STOPPED,
	WIGIG_SENSING_STATE_SEARCH,
	WIGIG_SENSING_STATE_FACIAL,
	WIGIG_SENSING_STATE_GESTURE,
	WIGIG_SENSING_STATE_CUSTOM,
	WIGIG_SENSING_STATE_GET_PARAMS,
	WIGIG_SENSING_STATE_SYS_ASSERT,
	WIGIG_SENSING_STATE_MAX,
};

struct wigig_sensing_stm {
	bool auto_recovery;
	bool enabled;
	bool fw_is_ready;
	bool spi_malfunction;
	bool sys_assert;
	bool waiting_for_deep_sleep_exit;
	bool waiting_for_deep_sleep_exit_first_pass;
	bool burst_size_ready;
	bool change_mode_in_progress;
	enum wigig_sensing_stm_e state;
	enum wigig_sensing_mode mode;
	u32 burst_size;
	u32 channel_request;
};

struct wigig_sensing_ctx {
	dev_t wigig_sensing_dev;
	struct cdev cdev;
	struct class *class;
	struct device *dev;
	struct spi_device *spi_dev;

	 /* Locks */
	struct mutex ioctl_lock;
	struct mutex file_lock;
	struct mutex spi_lock;
	struct mutex dri_lock;
	wait_queue_head_t cmd_wait_q;
	wait_queue_head_t data_wait_q;

	/* DRI */
	struct gpio_desc *dri_gpio;
	int dri_irq;
	bool opened;

	/* Memory buffers for SPI transactions */
	u8 *tx_buf;
	u8 *rx_buf;
	u8 *cmd_buf;
	u8 *cmd_reply_buf;

	/* SPI FIFO parameters */
	struct spi_fifo spi_fifo;
	struct wigig_sensing_stm stm;
	u32 last_read_length;
	union user_rgf_spi_mbox_inb inb_cmd;

	/* CIR buffer */
	struct cir_data cir_data;
	u8 *temp_buffer;
	bool event_pending;
	u32 dropped_bursts;
};

#endif /* __WIGIG_SENSING_H__ */
+92 −0
Original line number Original line Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */
#ifndef __WIGIG_SENSING_UAPI_H__
#define __WIGIG_SENSING_UAPI_H__

#if !defined(__KERNEL__)
#define __user
#endif

#include <linux/types.h>
#include <linux/ioctl.h>

enum wigig_sensing_mode {
	WIGIG_SENSING_MODE_SEARCH             = 1,
	WIGIG_SENSING_MODE_FACIAL_RECOGNITION = 2,
	WIGIG_SENSING_MODE_GESTURE_DETECTION  = 3,
	WIGIG_SENSING_MODE_STOP               = 7,
	WIGIG_SENSING_MODE_CUSTOM             = 15
};

struct wigig_sensing_change_mode {
	enum wigig_sensing_mode mode;
	bool has_channel;
	uint32_t channel;
};

enum wigig_sensing_event {
	WIGIG_SENSING_EVENT_FW_READY,
	WIGIG_SENSING_EVENT_RESET,
};

#define WIGIG_SENSING_IOC_MAGIC	'r'

#define WIGIG_SENSING_IOCTL_SET_AUTO_RECOVERY      (0)
#define WIGIG_SENSING_IOCTL_GET_MODE               (1)
#define WIGIG_SENSING_IOCTL_CHANGE_MODE            (2)
#define WIGIG_SENSING_IOCTL_CLEAR_DATA             (3)
#define WIGIG_SENSING_IOCTL_GET_NUM_DROPPED_BURSTS (4)
#define WIGIG_SENSING_IOCTL_GET_EVENT              (5)

/**
 * Set auto recovery, which means that the system will go back to search mode
 *  after an error
 */
#define WIGIG_SENSING_IOC_SET_AUTO_RECOVERY \
	_IO(WIGIG_SENSING_IOC_MAGIC, WIGIG_SENSING_IOCTL_SET_AUTO_RECOVERY)

/**
 * Get current system mode of operation *
 *
 * Returns struct wigig_sensing_mode
 */
#define WIGIG_SENSING_IOC_GET_MODE \
	_IOR(WIGIG_SENSING_IOC_MAGIC, WIGIG_SENSING_IOCTL_GET_MODE, \
	     sizeof(enum wigig_sensing_mode))

/**
 * Change mode of operation and optionaly channel
 *
 * Note: Before issuing a CHANGE_MODE operation, the application must stop
 * reading data from the device node and clear any cached data. This comes to
 * prevent loss of burst boundary synchronization in the application.
 *
 * Returns burst size
 */
#define WIGIG_SENSING_IOC_CHANGE_MODE \
	_IOWR(WIGIG_SENSING_IOC_MAGIC, WIGIG_SENSING_IOCTL_CHANGE_MODE, \
	      sizeof(struct wigig_sensing_change_mode))

/**
 * Clear data buffer
 */
#define WIGIG_SENSING_IOC_CLEAR_DATA \
	_IO(WIGIG_SENSING_IOC_MAGIC, WIGIG_SENSING_IOCTL_CLEAR_DATA)

/**
 * Get number of bursts that where dropped due to data buffer overflow
 */
#define WIGIG_SENSING_IOC_GET_NUM_DROPPED_BURSTS \
	_IOR(WIGIG_SENSING_IOC_MAGIC, \
	     WIGIG_SENSING_IOCTL_GET_NUM_DROPPED_BURSTS, uint32_t)

/**
 * Get number of bursts that where dropped due to data buffer overflow
 */
#define WIGIG_SENSING_IOC_GET_EVENT \
	_IOR(WIGIG_SENSING_IOC_MAGIC, WIGIG_SENSING_IOCTL_GET_EVENT, \
	     sizeof(enum wigig_sensing_event))

#endif /* ____WIGIG_SENSING_UAPI_H__ */