lineage_kernel_xcoverpro/sound/soc/samsung/abox/abox_adaptation.c

282 lines
7.5 KiB
C
Raw Permalink Normal View History

2023-06-18 22:53:49 +00:00
/* sound/soc/samsung/abox/abox_adaptation.c
*
* ALSA SoC Audio Layer - Samsung Abox adaptation driver
*
* Copyright (c) 2016 Samsung Electronics Co. Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <sound/smart_amp.h>
#include <sound/sec_adaptation.h>
#include "abox.h"
#define TIMEOUT_MS 130
#define READ_WRITE_ALL_PARAM 0
#define DEBUG_ABOX_ADAPTATION
#ifdef DEBUG_ABOX_ADAPTATION
#define dbg_abox_adaptation(format, args...) \
pr_info("[ABOX_ADAPTATION] %s: " format "\n", __func__, ## args)
#else
#define dbg_abox_adaptation(format, args...)
#endif /* DEBUG_ABOX_ADAPTATION */
static DECLARE_WAIT_QUEUE_HEAD(wq_read);
static DECLARE_WAIT_QUEUE_HEAD(wq_write);
struct abox_platform_data *data;
struct maxim_dsm *read_maxdsm;
bool abox_ipc_irq_read_avail;
bool abox_ipc_irq_write_avail;
int dsm_offset;
#ifdef SMART_AMP
#define SMARTPA_ABOX_ERROR 0xF0F0F0F0
struct ti_smartpa_data *ti_smartpa_rd_data;
struct ti_smartpa_data ti_smartpa_rd_data_tmp;
struct ti_smartpa_data *ti_smartpa_wr_data;
struct ti_smartpa_data ti_smartpa_wr_data_tmp;
#endif /* SMART_AMP */
#ifdef SMART_AMP
int ti_smartpa_read(void *prm_data, int offset, int size)
{
ABOX_IPC_MSG msg;
int ret = 0;
struct IPC_ERAP_MSG *erap_msg = &msg.msg.erap;
ti_smartpa_rd_data = (struct ti_smartpa_data *)prm_data;
msg.ipcid = IPC_ERAP;
erap_msg->msgtype = REALTIME_EXTRA;
erap_msg->param.raw.params[0] = TI_SMARTPA_VENDOR_ID;
erap_msg->param.raw.params[1] = RD_DATA;
erap_msg->param.raw.params[2] = offset;
erap_msg->param.raw.params[3] = size;
dbg_abox_adaptation("");
abox_ipc_irq_read_avail = false;
if(!data)
{
pr_err("[TI-SmartPA:%s] data is NULL", __func__);
goto error;
}
ret = abox_request_ipc(&data->pdev_abox->dev, IPC_ERAP,
&msg, sizeof(msg), 0, 0);
if (ret) {
pr_err("%s: abox_request_ipc is failed: %d\n", __func__, ret);
goto error;
}
ret = wait_event_interruptible_timeout(wq_read,
abox_ipc_irq_read_avail != false, msecs_to_jiffies(TIMEOUT_MS));
if (ret == 0) {
pr_err("%s: wait_event timeout\n", __func__);
goto error;
} else if (ret < 0) {
pr_err("%s: wait_event error(%d)\n", __func__, ret);
goto error;
} else {
memcpy(&ti_smartpa_rd_data->payload[0],
&ti_smartpa_rd_data_tmp.payload[0],
size);
}
if(((int32_t*)&ti_smartpa_rd_data->payload[0])[0] == SMARTPA_ABOX_ERROR)
goto error;
return 0;
error:
return -1;
}
EXPORT_SYMBOL_GPL(ti_smartpa_read);
int ti_smartpa_write(void *prm_data, int offset, int size)
{
ABOX_IPC_MSG msg;
int ret = 0;
struct IPC_ERAP_MSG *erap_msg = &msg.msg.erap;
ti_smartpa_wr_data = (struct ti_smartpa_data *)prm_data;
msg.ipcid = IPC_ERAP;
erap_msg->msgtype = REALTIME_EXTRA;
erap_msg->param.raw.params[0] = TI_SMARTPA_VENDOR_ID;
erap_msg->param.raw.params[1] = WR_DATA;
erap_msg->param.raw.params[2] = offset;
erap_msg->param.raw.params[3] = size;
memcpy(&erap_msg->param.raw.params[4],
prm_data,
min((sizeof(uint32_t) * size)
, sizeof(erap_msg->param.raw)));
dbg_abox_adaptation("");
abox_ipc_irq_write_avail = false;
if(!data)
{
pr_err("[TI-SmartPA:%s] data is NULL", __func__);
goto error;
}
ret = abox_request_ipc(&data->pdev_abox->dev, IPC_ERAP,
&msg, sizeof(msg), 0, 0);
if (ret) {
pr_err("%s: abox_request_ipc is failed: %d\n", __func__, ret);
goto error;
}
ret = wait_event_interruptible_timeout(wq_write,
abox_ipc_irq_write_avail != false, msecs_to_jiffies(TIMEOUT_MS));
if (ret == 0)
{
pr_err("%s: wait_event timeout\n", __func__);
goto error;
} else if (ret < 0) {
pr_err("%s: wait_event err(%d)\n", __func__, ret);
goto error;
} else {
memcpy(&ti_smartpa_wr_data->payload[0],
&ti_smartpa_wr_data_tmp.payload[0],
size);
}
if(((int32_t*)&ti_smartpa_wr_data->payload[0])[0] == SMARTPA_ABOX_ERROR)
goto error;
return 0;
error:
return -1;
}
EXPORT_SYMBOL_GPL(ti_smartpa_write);
#endif /* SMART_AMP */
static irqreturn_t abox_adaptation_irq_handler(int irq,
void *dev_id, ABOX_IPC_MSG *msg)
{
struct IPC_ERAP_MSG *erap_msg = &msg->msg.erap;
dbg_abox_adaptation("irq=%d, param[0]=%d avail(%d,%d)",
irq, erap_msg->param.raw.params[0], abox_ipc_irq_read_avail, abox_ipc_irq_write_avail);
switch (irq) {
case IPC_ERAP:
switch (erap_msg->msgtype) {
case REALTIME_EXTRA:
#ifdef SMART_AMP
if(erap_msg->param.raw.params[0] == TI_SMARTPA_VENDOR_ID) {
if(erap_msg->param.raw.params[1] == RD_DATA) {
memcpy(&ti_smartpa_rd_data_tmp.payload[0], &erap_msg->param.raw.params[4],
min(sizeof(struct ti_smartpa_data), sizeof(erap_msg->param.raw)));
abox_ipc_irq_read_avail = true;
dbg_abox_adaptation("read_avail after parital read[%d]",
abox_ipc_irq_read_avail);
if (abox_ipc_irq_read_avail && waitqueue_active(&wq_read))
wake_up_interruptible(&wq_read);
}
else if(erap_msg->param.raw.params[1] == WR_DATA) {
memcpy(&ti_smartpa_wr_data_tmp.payload[0], &erap_msg->param.raw.params[4],
min(sizeof(struct ti_smartpa_data), sizeof(erap_msg->param.raw)));
abox_ipc_irq_write_avail = true;
dbg_abox_adaptation("write_avail after parital read[%d]",
abox_ipc_irq_write_avail);
if (abox_ipc_irq_write_avail && waitqueue_active(&wq_write))
wake_up_interruptible(&wq_write);
}
else {
pr_err("[TI-SmartPA] %s: Invalid callback, %d", __func__,
erap_msg->param.raw.params[1]);
}
}
#endif /* SMART_AMP */
break;
default:
pr_err("%s: unknown message type\n", __func__);
break;
}
break;
default:
pr_err("%s: unknown command\n", __func__);
break;
}
return IRQ_HANDLED;
}
static struct snd_soc_platform_driver abox_adaptation = {
};
static int samsung_abox_adaptation_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct device_node *np_abox;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(dev, "Failed to allocate memory\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, data);
dsm_offset = READ_WRITE_ALL_PARAM;
np_abox = of_parse_phandle(np, "abox", 0);
if (!np_abox) {
dev_err(dev, "Failed to get abox device node\n");
return -EPROBE_DEFER;
}
data->pdev_abox = of_find_device_by_node(np_abox);
if (!data->pdev_abox) {
dev_err(dev, "Failed to get abox platform device\n");
return -EPROBE_DEFER;
}
data->abox_data = platform_get_drvdata(data->pdev_abox);
abox_register_irq_handler(&data->pdev_abox->dev, IPC_ERAP,
abox_adaptation_irq_handler, pdev);
dev_info(dev, "%s\n", __func__);
return snd_soc_register_platform(&pdev->dev, &abox_adaptation);
}
static int samsung_abox_adaptation_remove(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
return 0;
}
static const struct of_device_id samsung_abox_adaptation_match[] = {
{
.compatible = "samsung,abox-adaptation",
},
{},
};
MODULE_DEVICE_TABLE(of, samsung_abox_adaptation_match);
static struct platform_driver samsung_abox_adaptation_driver = {
.probe = samsung_abox_adaptation_probe,
.remove = samsung_abox_adaptation_remove,
.driver = {
.name = "samsung-abox-adaptation",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(samsung_abox_adaptation_match),
},
};
module_platform_driver(samsung_abox_adaptation_driver);
/* Module information */
MODULE_AUTHOR("SeokYoung Jang, <quartz.jang@samsung.com>");
MODULE_DESCRIPTION("Samsung ASoC A-Box Adaptation Driver");
MODULE_ALIAS("platform:samsung-abox-adaptation");
MODULE_LICENSE("GPL");