blob: 437af72a6a556c71a1761f3785e20f61290591c9 [file] [log] [blame]
/* Copyright (c) 2012-2015, The Linux Foundation. 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 version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <media/msm_jpeg.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include "msm_jpeg_sync.h"
#include "msm_jpeg_common.h"
#define MSM_JPEG_NAME "jpeg"
#define DEV_NAME_LEN 10
static int msm_jpeg_open(struct inode *inode, struct file *filp)
{
int rc = 0;
struct msm_jpeg_device *pgmn_dev = container_of(inode->i_cdev,
struct msm_jpeg_device, cdev);
filp->private_data = pgmn_dev;
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
rc = __msm_jpeg_open(pgmn_dev);
JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
return rc;
}
static int msm_jpeg_release(struct inode *inode, struct file *filp)
{
int rc;
struct msm_jpeg_device *pgmn_dev = filp->private_data;
JPEG_DBG(KERN_INFO "%s:%d]\n", __func__, __LINE__);
rc = __msm_jpeg_release(pgmn_dev);
JPEG_DBG(KERN_INFO "%s:%d] %s open_count = %d\n", __func__, __LINE__,
filp->f_path.dentry->d_name.name, pgmn_dev->open_count);
return rc;
}
#ifdef CONFIG_COMPAT
static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int rc;
struct msm_jpeg_device *pgmn_dev = filp->private_data;
JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%lx arg=0x%lx\n", __func__,
__LINE__, _IOC_NR(cmd), (unsigned long)pgmn_dev,
(unsigned long)arg);
rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg);
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return rc;
}
#endif
static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int rc;
struct msm_jpeg_device *pgmn_dev = filp->private_data;
JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%lx arg=0x%lx\n", __func__,
__LINE__, _IOC_NR(cmd), (unsigned long)pgmn_dev,
(unsigned long)arg);
rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg);
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return rc;
}
static const struct file_operations msm_jpeg_fops = {
.owner = THIS_MODULE,
.open = msm_jpeg_open,
.release = msm_jpeg_release,
.unlocked_ioctl = msm_jpeg_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = msm_jpeg_compat_ioctl,
#endif
};
int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd)
{
int rc;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *)jpeg_sd->host_priv;
JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%lx\n",
__func__, __LINE__, (unsigned long)jpeg_sd,
(unsigned long)pgmn_dev);
rc = __msm_jpeg_open(pgmn_dev);
JPEG_DBG("%s:%d: rc=%d\n",
__func__, __LINE__, rc);
return rc;
}
static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
long rc;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *)sd->host_priv;
JPEG_DBG("%s: cmd=%d\n", __func__, cmd);
JPEG_DBG("%s: pgmn_dev 0x%lx", __func__, (unsigned long)pgmn_dev);
JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__);
rc = __msm_jpeg_ioctl(pgmn_dev, cmd, (unsigned long)arg);
pr_debug("%s: X\n", __func__);
return rc;
}
void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd)
{
int rc;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *)jpeg_sd->host_priv;
JPEG_DBG("%s:pgmn_dev=0x%lx", __func__, (unsigned long)pgmn_dev);
rc = __msm_jpeg_release(pgmn_dev);
JPEG_DBG("%s:rc=%d", __func__, rc);
}
static const struct v4l2_subdev_core_ops msm_jpeg_subdev_core_ops = {
.ioctl = msm_jpeg_subdev_ioctl,
};
static const struct v4l2_subdev_ops msm_jpeg_subdev_ops = {
.core = &msm_jpeg_subdev_core_ops,
};
struct msm_jpeg_priv_data {
enum msm_jpeg_core_type core_type;
};
static const struct msm_jpeg_priv_data msm_jpeg_priv_data_jpg = {
.core_type = MSM_JPEG_CORE_CODEC
};
static const struct msm_jpeg_priv_data msm_jpeg_priv_data_dma = {
.core_type = MSM_JPEG_CORE_DMA
};
static const struct of_device_id msm_jpeg_dt_match[] = {
{.compatible = "qcom,jpeg", .data = &msm_jpeg_priv_data_jpg},
{.compatible = "qcom,jpeg_dma", .data = &msm_jpeg_priv_data_dma},
{}
};
MODULE_DEVICE_TABLE(of, msm_jpeg_dt_match);
static int msm_jpeg_init_dev(struct platform_device *pdev)
{
int rc = -1;
struct device *dev;
struct msm_jpeg_device *msm_jpeg_device_p;
const struct of_device_id *device_id;
const struct msm_jpeg_priv_data *priv_data;
char devname[DEV_NAME_LEN];
msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
if (!msm_jpeg_device_p) {
JPEG_PR_ERR("%s: no mem\n", __func__);
return -EFAULT;
}
msm_jpeg_device_p->pdev = pdev;
device_id = of_match_device(msm_jpeg_dt_match, &pdev->dev);
if (!device_id) {
JPEG_PR_ERR("%s: device_id is NULL\n", __func__);
goto fail;
}
priv_data = device_id->data;
msm_jpeg_device_p->core_type = priv_data->core_type;
if (pdev->dev.of_node)
of_property_read_u32((&pdev->dev)->of_node, "cell-index",
&pdev->id);
snprintf(devname, sizeof(devname), "%s%d", MSM_JPEG_NAME, pdev->id);
rc = __msm_jpeg_init(msm_jpeg_device_p);
if (rc < -1) {
JPEG_PR_ERR("%s: initialization failed\n", __func__);
goto fail;
}
v4l2_subdev_init(&msm_jpeg_device_p->subdev, &msm_jpeg_subdev_ops);
v4l2_set_subdev_hostdata(&msm_jpeg_device_p->subdev, msm_jpeg_device_p);
JPEG_DBG("%s: msm_jpeg_device_p 0x%lx", __func__,
(unsigned long)msm_jpeg_device_p);
rc = alloc_chrdev_region(&msm_jpeg_device_p->msm_jpeg_devno, 0, 1,
devname);
if (rc < 0) {
JPEG_PR_ERR("%s: failed to allocate chrdev\n", __func__);
goto fail_1;
}
if (!msm_jpeg_device_p->msm_jpeg_class) {
msm_jpeg_device_p->msm_jpeg_class =
class_create(THIS_MODULE, devname);
if (IS_ERR(msm_jpeg_device_p->msm_jpeg_class)) {
rc = PTR_ERR(msm_jpeg_device_p->msm_jpeg_class);
JPEG_PR_ERR("%s: create device class failed\n",
__func__);
goto fail_2;
}
}
dev = device_create(msm_jpeg_device_p->msm_jpeg_class, NULL,
MKDEV(MAJOR(msm_jpeg_device_p->msm_jpeg_devno),
MINOR(msm_jpeg_device_p->msm_jpeg_devno)), NULL,
"%s%d", MSM_JPEG_NAME, pdev->id);
if (IS_ERR(dev)) {
JPEG_PR_ERR("%s: error creating device\n", __func__);
rc = -ENODEV;
goto fail_3;
}
cdev_init(&msm_jpeg_device_p->cdev, &msm_jpeg_fops);
msm_jpeg_device_p->cdev.owner = THIS_MODULE;
msm_jpeg_device_p->cdev.ops =
(const struct file_operations *) &msm_jpeg_fops;
rc = cdev_add(&msm_jpeg_device_p->cdev,
msm_jpeg_device_p->msm_jpeg_devno, 1);
if (rc < 0) {
JPEG_PR_ERR("%s: error adding cdev\n", __func__);
rc = -ENODEV;
goto fail_4;
}
platform_set_drvdata(pdev, &msm_jpeg_device_p);
JPEG_DBG("%s %s%d: success\n", __func__, MSM_JPEG_NAME, pdev->id);
return rc;
fail_4:
device_destroy(msm_jpeg_device_p->msm_jpeg_class,
msm_jpeg_device_p->msm_jpeg_devno);
fail_3:
class_destroy(msm_jpeg_device_p->msm_jpeg_class);
fail_2:
unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
fail_1:
__msm_jpeg_exit(msm_jpeg_device_p);
return rc;
fail:
kfree(msm_jpeg_device_p);
return rc;
}
static void msm_jpeg_exit(struct msm_jpeg_device *msm_jpeg_device_p)
{
cdev_del(&msm_jpeg_device_p->cdev);
device_destroy(msm_jpeg_device_p->msm_jpeg_class,
msm_jpeg_device_p->msm_jpeg_devno);
class_destroy(msm_jpeg_device_p->msm_jpeg_class);
unregister_chrdev_region(msm_jpeg_device_p->msm_jpeg_devno, 1);
cam_smmu_destroy_handle(msm_jpeg_device_p->iommu_hdl);
__msm_jpeg_exit(msm_jpeg_device_p);
}
static int __msm_jpeg_probe(struct platform_device *pdev)
{
return msm_jpeg_init_dev(pdev);
}
static int __msm_jpeg_remove(struct platform_device *pdev)
{
struct msm_jpeg_device *msm_jpegd_device_p;
msm_jpegd_device_p = platform_get_drvdata(pdev);
if (msm_jpegd_device_p)
msm_jpeg_exit(msm_jpegd_device_p);
return 0;
}
static struct platform_driver msm_jpeg_driver = {
.probe = __msm_jpeg_probe,
.remove = __msm_jpeg_remove,
.driver = {
.name = "msm_jpeg",
.owner = THIS_MODULE,
.of_match_table = msm_jpeg_dt_match,
},
};
static int __init msm_jpeg_driver_init(void)
{
int rc;
rc = platform_driver_register(&msm_jpeg_driver);
return rc;
}
static void __exit msm_jpeg_driver_exit(void)
{
platform_driver_unregister(&msm_jpeg_driver);
}
MODULE_DESCRIPTION("msm jpeg jpeg driver");
module_init(msm_jpeg_driver_init);
module_exit(msm_jpeg_driver_exit);