blob: e26a162fe34acc98a74908eef659cb2352842c79 [file] [edit]
/* SPDX-License-Identifier: GPL-2.0
*
* Synaptics TouchCom touchscreen driver
*
* Copyright (C) 2017-2020 Synaptics Incorporated. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
/**
* @file syna_tcm2_runtime.h
*
* This file abstracts platform-specific headers and C runtime APIs being used
* on the target platform.
*/
#ifndef _SYNAPTICS_TCM2_C_RUNTIME_H_
#define _SYNAPTICS_TCM2_C_RUNTIME_H_
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/input/mt.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#if defined(USE_DRM_BRIDGE)
#include <drm/drm_bridge.h>
#elif defined(CONFIG_DRM_PANEL)
#include <drm/drm_panel.h>
#elif CONFIG_FB
#include <linux/fb.h>
#include <linux/notifier.h>
#endif
#include <linux/fs.h>
#include <linux/moduleparam.h>
#include <linux/kfifo.h>
/**
* @brief: DEV_MANAGED_API
*
* For linux kernel, managed interface was created for resources commonly
* used by device drivers using devres.
*
* Open if willing to use managed-APIs rather than legacy APIs.
*/
#define DEV_MANAGED_API
#if defined(DEV_MANAGED_API) || defined(USE_DRM_PANEL_NOTIFIER)
extern struct device *syna_request_managed_device(void);
#endif
/**
* @section: Log helpers
*
* @brief: LOGD
* Output the debug message
*
* @brief: LOGI
* Output the info message
*
* @brief: LOGN
* Output the notice message
*
* @brief: LOGW
* Output the warning message
*
* @brief: LOGE
* Output the error message
*/
#define LOGD(log, ...) \
pr_debug("[ debug] %s: " log, __func__, ##__VA_ARGS__)
#define LOGI(log, ...) \
pr_info("[ info] %s: " log, __func__, ##__VA_ARGS__)
#define LOGN(log, ...) \
pr_notice("[ info] %s: " log, __func__, ##__VA_ARGS__)
#define LOGW(log, ...) \
pr_warn("[warning] %s: " log, __func__, ##__VA_ARGS__)
#define LOGE(log, ...) \
pr_err("[ error] %s: " log, __func__, ##__VA_ARGS__)
/**
* @section: Error Codes returned
* Functions usually return 0 or positive value on success.
* Thus, please defines negative value here.
*/
#define _EIO (-EIO) /* I/O errors */
#define _ENOMEM (-ENOMEM) /* Out of memory */
#define _EINVAL (-EINVAL) /* Invalid parameters */
#define _ENODEV (-ENODEV) /* No such device */
#define _ETIMEDOUT (-ETIMEDOUT) /* execution timeout */
/**
* @section: Data Comparison helpers
*
* @brief: MAX
* Find the maximum value between
*
* @brief: MIN:
* Find the minimum value between
*
* @brief: GET_BIT
* Return the value of target bit
*/
#define MAX(a, b) \
({__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a > _b ? _a : _b; })
#define MIN(a, b) \
({__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a < _b ? _a : _b; })
#define GET_BIT(var, pos) \
(((var) & (1 << (pos))) >> (pos))
/**
* @section: C Atomic operations
*
* @brief: ATOMIC_SET
* Set an atomic data
*
* @brief: ATOMIC_GET:
* Get an atomic data
*/
typedef atomic_t syna_pal_atomic_t;
#define ATOMIC_SET(atomic, value) \
atomic_set(&atomic, value)
#define ATOMIC_GET(atomic) \
atomic_read(&atomic)
/**
* @section: C Integer Calculation helpers
*
* @brief: syna_pal_le2_to_uint
* Convert 2-byte data to an unsigned integer
*
* @brief: syna_pal_le4_to_uint
* Convert 4-byte data to an unsigned integer
*
* @brief: syna_pal_ceil_div
* Calculate the ceiling of the integer division
*/
/**
* syna_pal_le2_to_uint()
*
* Convert 2-byte data in little-endianness to an unsigned integer
*
* @param
* [ in] src: 2-byte data in little-endianness
*
* @return
* an unsigned integer converted
*/
static inline unsigned int syna_pal_le2_to_uint(const unsigned char *src)
{
return (unsigned int)src[0] +
(unsigned int)src[1] * 0x100;
}
/**
* syna_pal_le4_to_uint()
*
* Convert 4-byte data in little-endianness to an unsigned integer
*
* @param
* [ in] src: 4-byte data in little-endianness
*
* @return
* an unsigned integer converted
*/
static inline unsigned int syna_pal_le4_to_uint(const unsigned char *src)
{
return (unsigned int)src[0] +
(unsigned int)src[1] * 0x100 +
(unsigned int)src[2] * 0x10000 +
(unsigned int)src[3] * 0x1000000;
}
/**
* syna_pal_ceil_div()
*
* Calculate the ceiling of the integer division
*
* @param
* [ in] dividend: the dividend value
* [ in] divisor: the divisor value
*
* @return
* the ceiling of the integer division
*/
static inline unsigned int syna_pal_ceil_div(unsigned int dividend,
unsigned int divisor)
{
return (dividend + divisor - 1) / divisor;
}
/**
* @section: C Runtime for Memory Management helpers
*
* @brief: syna_pal_mem_calloc
* Allocate a block of memory space
*
* @brief: syna_pal_mem_free
* Deallocate a block of memory previously allocated
*
* @brief: syna_pal_mem_set
* Fill memory with a constant byte
*
* @brief: syna_pal_mem_cpy
* Ensure the safe size before doing memory copy
*/
/**
* syna_pal_mem_calloc()
*
* Allocates a block of memory for an array of 'num' elements,
* each of them has 'size' bytes long, and initializes all its bits to zero.
*
* @param
* [ in] num: number of elements for an array
* [ in] size: number of bytes for each elements
*
* @return
* On success, a pointer to the memory block allocated by the function.
*/
static inline void *syna_pal_mem_alloc(unsigned int num, unsigned int size)
{
#ifdef DEV_MANAGED_API
struct device *dev = syna_request_managed_device();
if (!dev) {
LOGE("Invalid managed device\n");
return NULL;
}
#endif
if ((int)(num * size) <= 0) {
LOGE("Invalid parameter\n");
return NULL;
}
#ifdef DEV_MANAGED_API
return devm_kcalloc(dev, num, size, GFP_KERNEL);
#else /* Legacy API */
return kcalloc(num, size, GFP_KERNEL);
#endif
}
/**
* syna_pal_mem_free()
*
* Deallocate a block of memory previously allocated.
*
* @param
* [ in] ptr: a memory block previously allocated
*
* @return
* none.
*/
static inline void syna_pal_mem_free(void *ptr)
{
#ifdef DEV_MANAGED_API
struct device *dev = syna_request_managed_device();
if (!dev) {
LOGE("Invalid managed device\n");
return;
}
if (ptr)
devm_kfree(dev, ptr);
#else /* Legacy API */
kfree(ptr);
#endif
}
/**
* syna_pal_mem_set()
*
* Fill memory with a constant byte
*
* @param
* [ in] ptr: pointer to a memory block
* [ in] c: the constant value
* [ in] n: number of byte being set
*
* @return
* none.
*/
static inline void syna_pal_mem_set(void *ptr, int c, unsigned int n)
{
memset(ptr, c, n);
}
/**
* syna_pal_mem_cpy()
*
* Ensure the safe size before copying the values of num bytes from the
* location to the memory block pointed to by destination.
*
* @param
* [out] dest: pointer to the destination space
* [ in] dest_size: size of destination array
* [ in] src: pointer to the source of data to be copied
* [ in] src_size: size of source array
* [ in] num: number of bytes to copy
*
* @return
* 0 on success; otherwise, on error.
*/
static inline int syna_pal_mem_cpy(void *dest, unsigned int dest_size,
const void *src, unsigned int src_size, unsigned int num)
{
if (dest == NULL || src == NULL)
return -1;
if (num > dest_size || num > src_size) {
LOGE("Invalid size. src:%d, dest:%d, num:%d\n",
src_size, dest_size, num);
return -1;
}
memcpy((void *)dest, (const void *)src, num);
return 0;
}
/**
* @section: C Runtime for Muxtex Control helpers
*
* @brief: syna_pal_mutex_alloc
* Create a mutex object
*
* @brief: syna_pal_mutex_free
* Release the mutex object previously allocated
*
* @brief: syna_pal_mutex_lock
* Lock the mutex
*
* @brief: syna_pal_mutex_unlock
* Unlock the mutex previously locked
*/
typedef struct mutex syna_pal_mutex_t;
/**
* syna_pal_mutex_alloc()
*
* Create a mutex object.
*
* @param
* [out] ptr: pointer to the mutex handle being allocated
*
* @return
* 0 on success; otherwise, on error.
*/
static inline int syna_pal_mutex_alloc(syna_pal_mutex_t *ptr)
{
mutex_init((struct mutex *)ptr);
return 0;
}
/**
* syna_pal_mutex_free()
*
* Release the mutex object previously allocated.
*
* @param
* [ in] ptr: mutex handle previously allocated
*
* @return
* none.
*/
static inline void syna_pal_mutex_free(syna_pal_mutex_t *ptr)
{
/* do nothing */
}
/**
* syna_pal_mutex_lock()
*
* Acquire/lock the mutex.
*
* @param
* [ in] ptr: a mutex handle
*
* @return
* none.
*/
static inline void syna_pal_mutex_lock(syna_pal_mutex_t *ptr)
{
mutex_lock((struct mutex *)ptr);
}
/**
* syna_pal_mutex_unlock()
*
* Unlock the locked mutex.
*
* @param
* [ in] ptr: a mutex handle
*
* @return
* none.
*/
static inline void syna_pal_mutex_unlock(syna_pal_mutex_t *ptr)
{
mutex_unlock((struct mutex *)ptr);
}
/**
* @section: C Runtime for Completion Event
*
* @brief: syna_pal_completion_alloc
* Allocate a completion event
*
* @brief: syna_pal_completion_free
* Release the completion event previously allocated
*
* @brief: syna_pal_completion_complete
* Complete the completion event being waiting for
*
* @brief: syna_pal_completion_reset
* Reset or reinitialize the completion event
*
* @brief: syna_pal_completion_wait_for
* Wait for the completion event
*/
typedef struct completion syna_pal_completion_t;
/**
* syna_pal_completion_alloc()
*
* Allocate a completion event, and the default state is not set.
* Caller must reset the event before each use.
*
* @param
* [out] ptr: pointer to the completion handle being allocated
*
* @return
* 0 on success; otherwise, on error.
*/
static inline int syna_pal_completion_alloc(syna_pal_completion_t *ptr)
{
init_completion((struct completion *)ptr);
return 0;
}
/**
* syna_pal_completion_free()
*
* Release the completion event previously allocated
*
* @param
* [ in] ptr: the completion event previously allocated
event
* @return
* none.
*/
static inline void syna_pal_completion_free(syna_pal_completion_t *ptr)
{
/* do nothing */
}
/**
* syna_pal_completion_complete()
*
* Complete the completion event being waiting for
*
* @param
* [ in] ptr: the completion event
*
* @return
* none.
*/
static inline void syna_pal_completion_complete(syna_pal_completion_t *ptr)
{
complete_all((struct completion *)ptr);
}
/**
* syna_pal_completion_reset()
*
* Reset or reinitialize the completion event
*
* @param
* [ in] ptr: the completion event
*
* @return
* none.
*/
static inline void syna_pal_completion_reset(syna_pal_completion_t *ptr)
{
#if (KERNEL_VERSION(3, 13, 0) > LINUX_VERSION_CODE)
init_completion((struct completion *)ptr);
#else
reinit_completion((struct completion *)ptr);
#endif
}
/**
* syna_pal_completion_wait_for()
*
* Wait for the completion event during the given time slot
*
* @param
* [ in] ptr: the completion event
* [ in] timeout_ms: time frame in milliseconds
*
* @return
* 0 if a signal is received; otherwise, on timeout or error occurs.
*/
static inline int syna_pal_completion_wait_for(syna_pal_completion_t *ptr,
unsigned int timeout_ms)
{
int retval;
retval = wait_for_completion_timeout((struct completion *)ptr,
msecs_to_jiffies(timeout_ms));
if (retval == 0) /* timeout occurs */
return -1;
return 0;
}
/**
* @section: C Runtime to Pause the Execution
*
* @brief: syna_pal_sleep_ms
* Sleep for a fixed amount of time in milliseconds
*
* @brief: syna_pal_sleep_us
* Sleep for a range of time in microseconds
*
* @brief: syna_pal_busy_delay_ms
* Busy wait for a fixed amount of time in milliseconds
*/
/**
* syna_pal_sleep_ms()
*
* Sleep for a fixed amount of time in milliseconds
*
* @param
* [ in] time_ms: time frame in milliseconds
*
* @return
* none.
*/
static inline void syna_pal_sleep_ms(int time_ms)
{
msleep(time_ms);
}
/**
* syna_pal_sleep_us()
*
* Sleep for a range of time in microseconds
*
* @param
* [ in] time_us_min: the min. time frame in microseconds
* [ in] time_us_max: the max. time frame in microseconds
*
* @return
* none.
*/
static inline void syna_pal_sleep_us(int time_us_min, int time_us_max)
{
usleep_range(time_us_min, time_us_max);
}
/**
* syna_pal_busy_delay_ms()
*
* Busy wait for a fixed amount of time in milliseconds
*
* @param
* [ in] time_ms: time frame in milliseconds
*
* @return
* none.
*/
static inline void syna_pal_busy_delay_ms(int time_ms)
{
mdelay(time_ms);
}
/**
* @section: C Runtime for String operations
*
* @brief: syna_pal_str_len
* Return the length of C string
*
* @brief: syna_pal_str_cpy:
* Ensure the safe size before doing C string copy
*
* @brief: syna_pal_str_cmp:
* Compare whether the given C strings are equal or not
*/
/**
* syna_pal_str_len()
*
* Return the length of C string
*
* @param
* [ in] str: an array of characters
*
* @return
* the length of given string
*/
static inline unsigned int syna_pal_str_len(const char *str)
{
return (unsigned int)strlen(str);
}
/**
* syna_pal_str_cpy()
*
* Copy the C string pointed by source into the array pointed by destination.
*
* @param
* [ in] dest: pointer to the destination C string
* [ in] dest_size: size of destination C string
* [out] src: pointer to the source of C string to be copied
* [ in] src_size: size of source C string
* [ in] num: number of bytes to copy
*
* @return
* 0 on success; otherwise, on error.
*/
static inline int syna_pal_str_cpy(char *dest, unsigned int dest_size,
const char *src, unsigned int src_size, unsigned int num)
{
if (dest == NULL || src == NULL)
return -1;
if (num > dest_size || num > src_size) {
LOGE("Invalid size. src:%d, dest:%d, num:%d\n",
src_size, dest_size, num);
return -1;
}
strncpy(dest, src, num);
return 0;
}
/**
* syna_pal_str_cmp()
*
* Compares up to num characters of the C string str1 to those of the
* C string str2.
*
* @param
* [ in] str1: C string to be compared
* [ in] str2: C string to be compared
* [ in] num: number of characters to compare
*
* @return
* 0 if both strings are equal; otherwise, not equal.
*/
static inline int syna_pal_str_cmp(const char *str1, const char *str2,
unsigned int num)
{
return strncmp(str1, str2, num);
}
/**
* syna_pal_hex_to_uint()
*
* Convert the given string in hex to an integer returned
*
* @param
* [ in] str: C string to be converted
* [ in] length: target length
*
* @return
* An integer converted
*/
static inline unsigned int syna_pal_hex_to_uint(char *str, int length)
{
unsigned int result = 0;
char *ptr = NULL;
for (ptr = str; ptr != str + length; ++ptr) {
result <<= 4;
if (*ptr >= 'A')
result += *ptr - 'A' + 10;
else
result += *ptr - '0';
}
return result;
}
/**
* @section: C Runtime for Checksum Calculation
*
* @brief: syna_pal_crc32
* Calculates the CRC32 value
*/
/**
* syna_pal_crc32()
*
* Calculates the CRC32 value of the data
*
* @param
* [ in] seed: the previous crc32 value
* [ in] data: byte data for the calculation
* [ in] len: the byte length of the data.
*
* @return
* 0 if both strings are equal; otherwise, not equal.
*/
static inline unsigned int syna_pal_crc32(unsigned int seed,
const char *data, unsigned int len)
{
return crc32(seed, data, len);
}
#endif /* end of _SYNAPTICS_TCM2_C_RUNTIME_H_ */