blob: 1591c6a00be1171af2a7223fdc8b40b151c33907 [file] [log] [blame] [edit]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/of_address.h>
#include "auto_write.h"
#include "auto_gdc.h"
#define AUTOWR_MODULE_NAME "autowrite"
#define AUTOWR_IOC_MAGIC 'W'
#define AUTOWR_GET_FRMINFO _IOWR(AUTOWR_IOC_MAGIC, \
0x00, struct autowr_frm_info)
#define AUTOWR_STOP_CAPTURE _IOWR(AUTOWR_IOC_MAGIC, \
0x01, struct autowr_frm_info)
#define AUTOWR_MMAP_FLAG _IOWR(AUTOWR_IOC_MAGIC, \
0x02, struct autowr_frmbuf_info)
#define AUTOWR_GDC_CONFIG _IOWR(AUTOWR_IOC_MAGIC, \
0x03, struct autowr_gdc_cfg)
static struct autowr_dev_base autowr_dev;
static void *autowr_get_devbase(void)
{
return (void *)&autowr_dev;
}
static int autowr_fops_open(struct inode *p_inode, struct file *p_file)
{
s32 rtn = 0;
p_file->private_data = autowr_get_devbase();
return rtn;
}
static int autowr_fops_release(struct inode *p_inode, struct file *p_file)
{
s32 rtn = 0;
p_file->private_data = NULL;
return rtn;
}
static long autowr_fops_ioctl(struct file *p_file, u32 cmd, unsigned long arg)
{
long rtn = 0;
void __user *argp = (void __user *)arg;
struct autowr_frm_info frm_info;
struct autowr_frmbuf_info frmbuf_info;
struct autowr_gdc_cfg gdc_cfg;
struct autowr_dev_base *dev_base = NULL;
memset(&frm_info, 0, sizeof(frm_info));
dev_base = p_file->private_data;
switch (cmd) {
case AUTOWR_MMAP_FLAG:
mutex_lock(&dev_base->pmutex);
if (copy_from_user(&frmbuf_info, argp, sizeof(frmbuf_info))) {
rtn = -1;
mutex_unlock(&dev_base->pmutex);
pr_err("Failed to copy\n");
break;
}
if (dev_base->f_mmap == AUTOWR_MAX_PATH) {
dev_base->f_mmap = frmbuf_info.path_type;
autowr_get_frmbuf_info(dev_base, &frmbuf_info);
} else {
pr_err("Error mmap flag\n");
}
if (copy_to_user(argp, &frmbuf_info, sizeof(frmbuf_info))) {
rtn = -1;
pr_err("Failed to copy\n");
}
mutex_unlock(&dev_base->pmutex);
break;
case AUTOWR_GDC_CONFIG:
if (copy_from_user(&gdc_cfg, argp, sizeof(gdc_cfg))) {
rtn = -1;
pr_err("Failed to copy\n");
break;
}
rtn = autowr_gdc_init(dev_base, &gdc_cfg);
if (rtn) {
pr_err("Failed to init auto gdc\n");
break;
}
auto_gdc_cfg_setting(dev_base, &gdc_cfg);
break;
case AUTOWR_GET_FRMINFO:
if (copy_from_user(&frm_info, argp, sizeof(frm_info))) {
rtn = -1;
pr_err("Failed to copy\n");
break;
}
rtn = autowr_get_frminfo(dev_base, &frm_info);
autowr_gdc_process(dev_base, &frm_info);
if (copy_to_user(argp, &frm_info, sizeof(frm_info))) {
rtn = -1;
pr_err("Failed to copy\n");
}
break;
case AUTOWR_STOP_CAPTURE:
if (copy_from_user(&frm_info, argp, sizeof(frm_info))) {
rtn = -1;
pr_err("Failed to copy\n");
break;
}
rtn = autowr_stop_capture(dev_base, &frm_info);
autowr_gdc_deinit(dev_base, &frm_info);
break;
default:
rtn = -1;
pr_err("Faile to support this cmd\n");
break;
}
return rtn;
}
static int autowr_fops_mmap(struct file *p_file, struct vm_area_struct *vma)
{
s32 rtn = 0;
struct autowr_dev_base *dev_base = NULL;
dev_base = p_file->private_data;
mutex_lock(&dev_base->pmutex);
rtn = autowr_mmap_frmbuf_base(dev_base, vma);
dev_base->f_mmap = AUTOWR_MAX_PATH;
mutex_unlock(&dev_base->pmutex);
return rtn;
}
static const struct file_operations autowr_fops = {
.owner = THIS_MODULE,
.open = autowr_fops_open,
.release = autowr_fops_release,
.mmap = autowr_fops_mmap,
.unlocked_ioctl = autowr_fops_ioctl,
};
static struct miscdevice autowr_misc_dev = {
.name = "autowr",
.minor = MISC_DYNAMIC_MINOR,
.fops = &autowr_fops,
};
static void autowr_iounmap(void *base)
{
struct autowr_dev_base *autowr_base = NULL;
if (!base) {
pr_err("Error input param\n");
return;
}
autowr_base = base;
if (autowr_base->fr_base) {
iounmap(autowr_base->fr_base);
autowr_base->fr_base = NULL;
}
if (autowr_base->ds1_base) {
iounmap(autowr_base->ds1_base);
autowr_base->ds1_base = NULL;
}
if (autowr_base->ds2_base) {
iounmap(autowr_base->ds2_base);
autowr_base->ds2_base = NULL;
}
}
static int autowr_probe(struct platform_device *pdev)
{
s32 i = 0;
s32 rtn = -1;
struct resource rs;
struct autowr_dev_base *autowr_base = NULL;
autowr_base = &autowr_dev;
memset(autowr_base, 0, sizeof(*autowr_base));
while (!of_address_to_resource(pdev->dev.of_node, i, &rs)) {
if (!strcmp(rs.name, "fr_autowrite")) {
autowr_base->fr_base =
ioremap_nocache(rs.start, resource_size(&rs));
} else if (!strcmp(rs.name, "ds1_autowrite")) {
autowr_base->ds1_base =
ioremap_nocache(rs.start, resource_size(&rs));
} else if (!strcmp(rs.name, "ds2_autowrite")) {
autowr_base->ds2_base =
ioremap_nocache(rs.start, resource_size(&rs));
} else {
pr_err("Error index, please check\n");
}
i++;
}
mutex_init(&autowr_base->pmutex);
autowr_base->f_mmap = AUTOWR_MAX_PATH;
autowr_base->pdev = pdev;
rtn = misc_register(&autowr_misc_dev);
if (rtn != 0) {
autowr_iounmap(autowr_base);
pr_err("Failed to register misc dev node");
return rtn;
}
platform_set_drvdata(pdev, autowr_base);
pr_info("Success autowr probe\n");
return rtn;
}
static int autowr_remove(struct platform_device *pdev)
{
misc_deregister(&autowr_misc_dev);
pr_info("success remove\n");
return 0;
}
static const struct of_device_id autowrite_dt_match[] = {
{.compatible = "amlogic, autowrite"},
{}
};
static struct platform_driver p_autowr_drv = {
.probe = autowr_probe,
.remove = autowr_remove,
.driver = {
.name = AUTOWR_MODULE_NAME,
.owner = THIS_MODULE,
.of_match_table = autowrite_dt_match,
},
};
static int __init autowr_module_init(void)
{
s32 rtn = -1;
rtn = platform_driver_register(&p_autowr_drv);
if (rtn != 0) {
pr_err("Failed to register autowr driver\n");
}
return rtn;
}
static void __exit autowr_module_exit(void)
{
platform_driver_unregister(&p_autowr_drv);
}
module_init(autowr_module_init);
module_exit(autowr_module_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Amlogic");