kernel_samsung_a53x/drivers/soc/samsung/gnssif/gnss_prj.h
2024-06-15 16:02:09 -03:00

418 lines
10 KiB
C
Executable file

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2010 Samsung Electronics.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __GNSS_PRJ_H__
#define __GNSS_PRJ_H__
#include <linux/wait.h>
#include <linux/miscdevice.h>
#include <linux/skbuff.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/rbtree.h>
#include <linux/spinlock.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/version.h>
#if IS_ENABLED(CONFIG_EXYNOS_ITMON)
#include <soc/samsung/exynos-itmon.h>
#endif
#include "include/gnss.h"
#include "include/exynos_ipc.h"
#include "pmu-gnss.h"
#define CALLER (__builtin_return_address(0))
#define MAX_IOD_RXQ_LEN 2048
#define GNSS_IOC_MAGIC ('K')
#define GNSS_IOCTL_RESET _IO(GNSS_IOC_MAGIC, 0x00)
#define GNSS_IOCTL_LOAD_FIRMWARE _IO(GNSS_IOC_MAGIC, 0x01)
#define GNSS_IOCTL_REQ_FAULT_INFO _IO(GNSS_IOC_MAGIC, 0x02)
#define GNSS_IOCTL_REQ_BCMD _IO(GNSS_IOC_MAGIC, 0x03)
#define GNSS_IOCTL_READ_FIRMWARE _IO(GNSS_IOC_MAGIC, 0x04)
#define GNSS_IOCTL_CHANGE_SENSOR_GPIO _IO(GNSS_IOC_MAGIC, 0x05)
#define GNSS_IOCTL_CHANGE_TCXO_MODE _IO(GNSS_IOC_MAGIC, 0x06)
#define GNSS_IOCTL_SET_SENSOR_POWER _IO(GNSS_IOC_MAGIC, 0x07)
#define GNSS_IOCTL_SET_WATCHDOG_RESET _IO(GNSS_IOC_MAGIC, 0x10)
#define GNSS_IOCTL_READ_SHMEM_SIZE _IO(GNSS_IOC_MAGIC, 0x11)
#define GNSS_IOCTL_READ_RESET_COUNT _IO(GNSS_IOC_MAGIC, 0x12)
#define GNSS_IOCTL_GET_SWREG _IOWR(GNSS_IOC_MAGIC, 0x20, char *)
#define GNSS_IOCTL_GET_APREG _IOWR(GNSS_IOC_MAGIC, 0x21, char *)
#define GNSS_IOCTL_RELEASE_RESET _IO(GNSS_IOC_MAGIC, 0x13)
#define GNSS_IOCTL_POWER_ON _IO(GNSS_IOC_MAGIC, 0x14)
#define GNSS_IOCTL_LOAD_DATA _IOWR(GNSS_IOC_MAGIC, 0x15, struct kepler_data_args)
enum sensor_power {
SENSOR_OFF,
SENSOR_ON,
};
struct kepler_bcmd_args {
u16 flags;
u16 cmd_id;
u32 param1;
u32 param2;
u32 ret_val;
};
struct kepler_firmware_args {
u32 firmware_size;
u32 offset;
char *firmware_bin;
};
struct kepler_data_args {
u32 size;
u32 offset;
char *data;
};
struct kepler_fault_args {
u32 dump_size;
char *dumped_data;
};
#if IS_ENABLED(CONFIG_COMPAT)
struct kepler_firmware_args32 {
u32 firmware_size;
u32 offset;
compat_uptr_t firmware_bin;
};
struct kepler_fault_args32 {
u32 dump_size;
compat_uptr_t dumped_data;
};
#endif
/* gnss status */
#define HDLC_HEADER_MAX_SIZE 6 /* fmt 3, raw 6, rfs 6 */
#define GNSS_MAX_NAME_LEN 64
#define MAX_HEX_LEN 16
#define MAX_NAME_LEN 64
#define MAX_PREFIX_LEN 128
#define MAX_STR_LEN 256
/* Does gnss ctl structure will use state ? or status defined below ?*/
enum gnss_state {
STATE_OFFLINE,
STATE_FIRMWARE_DL, /* no firmware */
STATE_ONLINE,
STATE_HOLD_RESET,
STATE_FAULT, /* ACTIVE/WDT */
};
#if IS_ENABLED(CONFIG_USB_CONFIGFS_F_MBIM)
enum gnss_pwr {
POWER_ON,
POWER_OFF,
};
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0))
static const char * const gnss_state_str[] = {
[STATE_OFFLINE] = "OFFLINE",
[STATE_FIRMWARE_DL] = "FIRMWARE_DL",
[STATE_ONLINE] = "ONLINE",
[STATE_HOLD_RESET] = "HOLD_RESET",
[STATE_FAULT] = "FAULT",
};
#else
static const char * const gnss_state_str[] = {
[STATE_OFFLINE] = "OFFLINE",
[STATE_FIRMWARE_DL] = "FIRMWARE_DL",
[STATE_ONLINE] = "ONLINE",
[STATE_HOLD_RESET] = "HOLD_RESET",
[STATE_FAULT] = "FAULT",
};
#endif
enum direction {
TX = 0,
AP2GNSS = 0,
RX = 1,
GNSS2AP = 1,
MAX_DIR = 2
};
/*
* @brief return the gnss_state string
* @param state the state of a GNSS
*/
static const inline char *get_gnss_state_str(int state)
{
return gnss_state_str[state];
}
struct header_data {
char hdr[HDLC_HEADER_MAX_SIZE];
u32 len;
u32 frag_len;
char start; /*hdlc start header 0x7F*/
};
struct fmt_hdr {
u16 len;
u8 control;
} __packed;
/* for fragmented data from link devices */
struct fragmented_data {
struct sk_buff *skb_recv;
struct header_data h_data;
struct exynos_frame_data f_data;
/* page alloc fail retry*/
unsigned int realloc_offset;
};
#define fragdata(iod, ld) (&(iod)->fragments)
/** struct skbuff_priv - private data of struct sk_buff
* this is matched to char cb[48] of struct sk_buff
*/
struct skbuff_private {
struct io_device *iod;
struct link_device *ld;
struct io_device *real_iod; /* for rx multipdp */
/* for time-stamping */
struct timespec64 ts;
u32 lnk_hdr:1,
reserved:15,
exynos_ch:8,
frm_ctrl:8;
/* for indicating that thers is only one IPC frame in an skb */
bool single_frame;
} __packed;
static inline struct skbuff_private *skbpriv(struct sk_buff *skb)
{
BUILD_BUG_ON(sizeof(struct skbuff_private) > sizeof(skb->cb));
return (struct skbuff_private *)&skb->cb;
}
struct io_device {
/* Name of the IO device */
char *name;
/* Link to link device */
struct link_device *ld;
/* Reference count */
atomic_t opened;
/* Wait queue for the IO device */
wait_queue_head_t wq;
/* Misc and net device structures for the IO device */
struct miscdevice miscdev;
/* The name of the application that will use this IO device */
char *app;
bool link_header;
/* Rx queue of sk_buff */
struct sk_buff_head sk_rx_q;
/*
* work for each io device, when delayed work needed
* use this for private io device rx action
*/
struct delayed_work rx_work;
struct fragmented_data fragments;
/* called from linkdevice when a packet arrives for this iodevice */
int (*recv_skb)(struct io_device *iod, struct link_device *ld,
struct sk_buff *skb);
int (*recv_skb_single)(struct io_device *iod, struct link_device *ld,
struct sk_buff *skb);
struct gnss_ctl *gc;
struct wakeup_source *ws;
long waketime;
struct exynos_seq_num seq_num;
/* DO NOT use __current_link directly
* you MUST use skbpriv(skb)->ld in mc, link, etc..
*/
struct link_device *__current_link;
};
#define to_io_device(misc) container_of(misc, struct io_device, miscdev)
/* get_current_link, set_current_link don't need to use locks.
* In ARM, set_current_link and get_current_link are compiled to
* each one instruction (str, ldr) as atomic_set, atomic_read.
* And, the order of set_current_link and get_current_link is not important.
*/
#define get_current_link(iod) ((iod)->__current_link)
#define set_current_link(iod, ld) ((iod)->__current_link = (ld))
struct link_device {
struct list_head list;
char *name;
/* GNSS data */
struct gnss_pdata *pdata;
/* GNSS control */
struct gnss_ctl *gc;
/* link to io device */
struct io_device *iod;
/* TX queue of socket buffers */
struct sk_buff_head sk_fmt_tx_q;
struct sk_buff_head *skb_txq;
/* RX queue of socket buffers */
struct sk_buff_head sk_fmt_rx_q;
struct sk_buff_head *skb_rxq;
int timeout_cnt;
struct workqueue_struct *tx_wq;
struct work_struct tx_work;
struct delayed_work tx_delayed_work;
struct delayed_work *tx_dwork;
struct delayed_work fmt_tx_dwork;
struct workqueue_struct *rx_wq;
struct work_struct rx_work;
struct delayed_work rx_delayed_work;
/* called by an io_device when it has a packet to send over link
* - the io device is passed so the link device can look at id and
* format fields to determine how to route/format the packet
*/
int (*send)(struct link_device *ld, struct io_device *iod,
struct sk_buff *skb);
/* Method to clear RX/TX buffers before reset */
void (*reset_buffers)(struct link_device *ld);
/* Methods for copying to/from reserved memory */
int (*copy_reserved_from_user)(struct link_device *ld, u32 offset,
void __user *user_src, u32 size);
int (*copy_reserved_to_user)(struct link_device *ld, u32 offset,
void __user *user_dst, u32 size);
/* Method to dump fault info to user */
int (*dump_fault_to_user)(struct link_device *ld,
void __user *user_dst, u32 size);
};
/** rx_alloc_skb - allocate an skbuff and set skb's iod, ld
* @length: length to allocate
* @iod: struct io_device *
* @ld: struct link_device *
*
* %NULL is returned if there is no free memory.
*/
static inline struct sk_buff *rx_alloc_skb(unsigned int length,
struct io_device *iod, struct link_device *ld)
{
struct sk_buff *skb;
skb = alloc_skb(length, GFP_ATOMIC);
if (likely(skb)) {
skbpriv(skb)->iod = iod;
skbpriv(skb)->ld = ld;
}
return skb;
}
enum gnss_mode;
enum gnss_int_clear;
enum gnss_tcxo_mode;
struct gnssctl_ops {
int (*gnss_hold_reset)(struct gnss_ctl *gc);
int (*gnss_release_reset)(struct gnss_ctl *gc);
int (*gnss_power_on)(struct gnss_ctl *gc);
int (*gnss_req_fault_info)(struct gnss_ctl *gc);
int (*suspend)(struct gnss_ctl *gc);
int (*resume)(struct gnss_ctl *gc);
int (*change_sensor_gpio)(struct gnss_ctl *gc);
int (*set_sensor_power)(struct gnss_ctl *gc, enum sensor_power arg);
int (*req_bcmd)(struct gnss_ctl *gc, u16 cmd_id, u16 flags,
u32 param1, u32 param2);
};
struct gnss_ctl {
struct device *dev;
char *name;
struct gnss_pdata *pdata;
enum gnss_state gnss_state;
struct clk *ccore_qch_lh_gnss;
struct delayed_work dwork;
struct work_struct work;
struct gnssctl_ops ops;
struct gnssctl_pmu_ops *pmu_ops;
struct io_device *iod;
/* Wakelock for gnss_ctl */
struct wakeup_source *gc_fault_ws;
struct completion fault_cmpl;
struct completion bcmd_cmpl;
struct completion sw_init_cmpl;
struct pinctrl *gnss_gpio;
struct pinctrl_state *gnss_sensor_gpio;
struct regulator *vdd_sensor_reg;
struct gnss_irq irq_gnss_active;
struct gnss_irq irq_gnss_wdt;
struct gnss_irq irq_gnss_sw_init;
u32 reset_count;
bool use_sw_init_intr;
#if IS_ENABLED(CONFIG_USB_CONFIGFS_F_MBIM)
struct irq_chip *apwake_irq_chip;
int m2_gpio_gnss_pwr;
struct gnss_irq m2_irq_gnss_pwr;
enum gnss_pwr gnss_pwr;
bool is_irq_received;
#endif
#if IS_ENABLED(CONFIG_EXYNOS_ITMON)
struct notifier_block itmon_nb;
#endif
};
extern int exynos_init_gnss_io_device(struct io_device *iod, struct device *dev);
int init_gnssctl_device(struct gnss_ctl *mc, struct gnss_pdata *pdata);
struct link_device *create_link_device_shmem(struct platform_device *pdev);
#endif