unplugged-kernel/drivers/misc/mediatek/sensors-1.0/sensorHub/nanohub/nanohub-mtk.c

303 lines
6.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 MediaTek Inc.
*/
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include "main.h"
#include "bl.h"
#include "comms.h"
#include "nanohub-mtk.h"
#include "SCP_power_monitor.h"
#define CHRE_IPI_DEBUG 0
struct nanohub_ipi_rx_st {
u8 *buff;
int copy_size;
struct completion isr_comp;
};
struct nanohub_ipi_rx_st nanohub_ipi_rx;
struct iio_dev *nanohub_iio_dev;
struct semaphore scp_nano_ipi_sem;
struct nanohub_ipi_data {
struct nanohub_data data;
/* todo */
};
/*
*Add the function weak defination, to avoid the build error
*when the MTK_SENSOR_SUPPORT is not set(SOC bringup).
*/
int __attribute__((weak))
scp_power_monitor_register(struct scp_power_monitor *monitor)
{
return 0;
}
/* scp_nano_ipi_status: 1 :ready to ipi 0:not ready*/
int scp_nano_ipi_status;
enum scp_ipi_status __attribute__((weak))
scp_ipi_registration(enum ipi_id id,
void (*ipi_handler)(int id, void *data, unsigned int len),
const char *name)
{
return SCP_IPI_ERROR;
}
enum scp_ipi_status __attribute__((weak))
scp_ipi_send(enum ipi_id id, void *buf, unsigned int len,
unsigned int wait, enum scp_core_id scp_id)
{
return SCP_IPI_ERROR;
}
#define NANOHUB_IPI_SEND_RETRY 100
void mtk_ipi_scp_isr_sim(int got_size)
{
int token = got_size;
int ret;
int retry = NANOHUB_IPI_SEND_RETRY;
/* add retry to avoid SCP busy timeout */
while (retry-- && (READ_ONCE(scp_nano_ipi_status) == 1)) {
ret = scp_ipi_send(IPI_CHREX, &token, sizeof(token),
0, SCP_A_ID);
if (ret != SCP_IPI_BUSY)
break;
usleep_range(100, 200);
}
}
static void nano_ipi_start(void)
{
pr_info("%s notify\n", __func__);
WRITE_ONCE(scp_nano_ipi_status, 1);
}
static void nano_ipi_stop(void)
{
pr_info("%s notify\n", __func__);
WRITE_ONCE(scp_nano_ipi_status, 0);
}
static int nano_ipi_event(u8 event, void *ptr)
{
switch (event) {
case SENSOR_POWER_UP:
nano_ipi_start();
break;
case SENSOR_POWER_DOWN:
nano_ipi_stop();
break;
}
return 0;
}
static struct scp_power_monitor nano_ipi_notifier = {
.name = "nanohub_ipi",
.notifier_call = nano_ipi_event,
};
int nanohub_ipi_write(void *data, u8 *tx, int length, int timeout)
{
int ret;
int retry = NANOHUB_IPI_SEND_RETRY;
#if CHRE_IPI_DEBUG
int i;
pr_info("AP->(%d) ", length);
for (i = 0; i < length; i++)
pr_info("%02x ", tx[i]);
pr_info("\n");
#endif
ret = SCP_IPI_ERROR;
while (retry-- && (READ_ONCE(scp_nano_ipi_status) == 1)) {
ret = scp_ipi_send(IPI_CHRE, tx, length, 0, SCP_A_ID);
if (ret != SCP_IPI_BUSY)
break;
usleep_range(100, 200);
}
if (ret == SCP_IPI_BUSY)
pr_info("%s ipi busy, ret=%d\n", __func__, ret);
if (ret == SCP_IPI_DONE)
return length;
else
return ERROR_NACK;
}
int nanohub_ipi_read(void *data, u8 *rx, int max_length, int timeout)
{
int ret;
const int min_size = sizeof(struct nanohub_packet) +
sizeof(struct nanohub_packet_crc);
if (max_length < min_size)
return -1;
/* todo: support interruptible? please check it! */
if (wait_for_completion_interruptible_timeout(&nanohub_ipi_rx.isr_comp,
timeout) == 0) {
ret = 0; /* return as empty packet */
} else {
ret = nanohub_ipi_rx.copy_size;
memcpy(rx, g_nanohub_data_p->comms.rx_buffer, ret);
/* send back isr sim */
mtk_ipi_scp_isr_sim(ret);
}
#if CHRE_IPI_DEBUG
pr_info("%s ret %d\n", __func__, ret);
#endif
return ret; /* return packet size */
}
static int nanohub_ipi_open(void *data)
{
down(&scp_nano_ipi_sem);
reinit_completion(&nanohub_ipi_rx.isr_comp); /*reset when retry start*/
return 0;
}
static void nanohub_ipi_close(void *data)
{
up(&scp_nano_ipi_sem);
}
void nanohub_ipi_comms_init(struct nanohub_ipi_data *ipi_data)
{
struct nanohub_comms *comms = &ipi_data->data.comms;
comms->seq = 1;
comms->timeout_write = msecs_to_jiffies(512);
comms->timeout_ack = msecs_to_jiffies(3);
comms->timeout_reply = msecs_to_jiffies(3);
comms->open = nanohub_ipi_open;
comms->close = nanohub_ipi_close;
comms->write = nanohub_ipi_write;
comms->read = nanohub_ipi_read;
/* comms->tx_buffer = kmalloc(4096, GFP_KERNEL | GFP_DMA); */
comms->rx_buffer = kmalloc(4096, GFP_KERNEL | GFP_DMA);
nanohub_ipi_rx.buff = comms->rx_buffer;
sema_init(&scp_nano_ipi_sem, 1);
}
static int nanohub_ipi_remove(struct platform_device *pdev);
struct platform_device nanohub_ipi_pdev = {
.name = "nanohub_ipi",
.id = -1,
};
int nanohub_ipi_suspend(struct platform_device *dev, pm_message_t state)
{
int ret = 0;
if (READ_ONCE(scp_nano_ipi_status) == 1)
ret = nanohub_suspend(nanohub_iio_dev);
else
ret = 0;
return ret;
}
int nanohub_ipi_resume(struct platform_device *dev)
{
int ret = 0;
if (READ_ONCE(scp_nano_ipi_status) == 1)
ret = nanohub_resume(nanohub_iio_dev);
else
ret = 0;
return ret;
}
void scp_to_ap_ipi_handler(int id, void *data, unsigned int len)
{
#if CHRE_IPI_DEBUG
int i;
unsigned char *data_p = data;
pr_info("->AP(%d):", len);
for (i = 0; i < len; i++)
pr_info("%02x ", data_p[i]);
pr_info("\n");
#endif
nanohub_ipi_rx.copy_size = len;
memcpy(g_nanohub_data_p->comms.rx_buffer, data, len);
/*todo: check size ? */
complete(&nanohub_ipi_rx.isr_comp);
}
int nanohub_ipi_probe(struct platform_device *pdev)
{
struct nanohub_ipi_data *ipi_data;
struct iio_dev *iio_dev;
enum scp_ipi_status status;
iio_dev = iio_device_alloc(sizeof(struct nanohub_ipi_data));
if (!iio_dev)
return -ENOMEM;
nanohub_iio_dev = iio_dev;
/*iio_dev = nanohub_probe(&pdev->dev, iio_dev);*/
nanohub_probe(&nanohub_ipi_pdev.dev, iio_dev);
ipi_data = iio_priv(iio_dev);
nanohub_ipi_comms_init(ipi_data);
init_completion(&nanohub_ipi_rx.isr_comp);
status = scp_ipi_registration(IPI_CHRE,
scp_to_ap_ipi_handler, "chre_ap_rx");
/*init nano scp ipi status*/
WRITE_ONCE(scp_nano_ipi_status, 1);
scp_power_monitor_register(&nano_ipi_notifier);
return 0;
}
static int nanohub_ipi_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver nanohub_ipi_pdrv = {
.probe = nanohub_ipi_probe,
.remove = nanohub_ipi_remove,
.suspend = nanohub_ipi_suspend,
.resume = nanohub_ipi_resume,
.driver = {
.name = "nanohub_ipi",
.owner = THIS_MODULE,
/*.of_match_table = scpdvfs_of_ids,*/
},
};
int __init nanohub_ipi_init(void)
{
int ret = 0;
ret = platform_device_register(&nanohub_ipi_pdev);
if (ret) {
pr_debug("nanohub_ipi_pdev fail\n");
goto _nanohub_ipi_init_exit;
}
ret = platform_driver_register(&nanohub_ipi_pdrv);
if (ret) {
pr_debug("nanohub_ipi_pdrv fail\n");
platform_device_unregister(&nanohub_ipi_pdev);
goto _nanohub_ipi_init_exit;
}
platform_set_drvdata(&nanohub_ipi_pdev, g_nanohub_data_p);
_nanohub_ipi_init_exit:
return ret;
}