blob: 27f551876f59e12eedd01242fb7d96576f8e8d3e [file] [log] [blame]
Pavan Kumar Chilamkurthi5719f212017-07-20 15:02:21 -07001/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/device.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/kernel.h>
18
19#include "cam_subdev.h"
20#include "cam_node.h"
21#include "cam_fd_context.h"
22#include "cam_fd_hw_mgr.h"
23#include "cam_fd_hw_mgr_intf.h"
24
25#define CAM_FD_DEV_NAME "cam-fd"
26
27/**
28 * struct cam_fd_dev - FD device information
29 *
30 * @sd: Subdev information
31 * @base_ctx: List of base contexts
32 * @fd_ctx: List of FD contexts
33 * @lock: Mutex handle
34 * @open_cnt: FD subdev open count
35 * @probe_done: Whether FD probe is completed
36 */
37struct cam_fd_dev {
38 struct cam_subdev sd;
39 struct cam_context base_ctx[CAM_CTX_MAX];
40 struct cam_fd_context fd_ctx[CAM_CTX_MAX];
41 struct mutex lock;
42 uint32_t open_cnt;
43 bool probe_done;
44};
45
46static struct cam_fd_dev g_fd_dev;
47
48static int cam_fd_dev_open(struct v4l2_subdev *sd,
49 struct v4l2_subdev_fh *fh)
50{
51 struct cam_fd_dev *fd_dev = &g_fd_dev;
52
53 if (!fd_dev->probe_done) {
54 CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev);
55 return -ENODEV;
56 }
57
58 mutex_lock(&fd_dev->lock);
59 fd_dev->open_cnt++;
60 CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt);
61 mutex_unlock(&fd_dev->lock);
62
63 return 0;
64}
65
66static int cam_fd_dev_close(struct v4l2_subdev *sd,
67 struct v4l2_subdev_fh *fh)
68{
69 struct cam_fd_dev *fd_dev = &g_fd_dev;
70
71 if (!fd_dev->probe_done) {
72 CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev);
73 return -ENODEV;
74 }
75
76 mutex_lock(&fd_dev->lock);
77 fd_dev->open_cnt--;
78 CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt);
79 mutex_unlock(&fd_dev->lock);
80
81 return 0;
82}
83
84static const struct v4l2_subdev_internal_ops cam_fd_subdev_internal_ops = {
85 .open = cam_fd_dev_open,
86 .close = cam_fd_dev_close,
87};
88
89static int cam_fd_dev_probe(struct platform_device *pdev)
90{
91 int rc;
92 int i;
93 struct cam_hw_mgr_intf hw_mgr_intf;
94 struct cam_node *node;
95
96 g_fd_dev.sd.internal_ops = &cam_fd_subdev_internal_ops;
97
98 /* Initialze the v4l2 subdevice first. (create cam_node) */
99 rc = cam_subdev_probe(&g_fd_dev.sd, pdev, CAM_FD_DEV_NAME,
100 CAM_FD_DEVICE_TYPE);
101 if (rc) {
102 CAM_ERR(CAM_FD, "FD cam_subdev_probe failed, rc=%d", rc);
103 return rc;
104 }
105 node = (struct cam_node *) g_fd_dev.sd.token;
106
107 rc = cam_fd_hw_mgr_init(pdev->dev.of_node, &hw_mgr_intf);
108 if (rc) {
109 CAM_ERR(CAM_FD, "Failed in initializing FD HW manager, rc=%d",
110 rc);
111 goto unregister_subdev;
112 }
113
114 for (i = 0; i < CAM_CTX_MAX; i++) {
115 rc = cam_fd_context_init(&g_fd_dev.fd_ctx[i],
116 &g_fd_dev.base_ctx[i], &node->hw_mgr_intf);
117 if (rc) {
118 CAM_ERR(CAM_FD, "FD context init failed i=%d, rc=%d",
119 i, rc);
120 goto deinit_ctx;
121 }
122 }
123
124 rc = cam_node_init(node, &hw_mgr_intf, g_fd_dev.base_ctx, CAM_CTX_MAX,
125 CAM_FD_DEV_NAME);
126 if (rc) {
127 CAM_ERR(CAM_FD, "FD node init failed, rc=%d", rc);
128 goto deinit_ctx;
129 }
130
131 mutex_init(&g_fd_dev.lock);
132 g_fd_dev.probe_done = true;
133
134 CAM_DBG(CAM_FD, "Camera FD probe complete");
135
136 return 0;
137
138deinit_ctx:
139 for (--i; i >= 0; i--) {
140 if (cam_fd_context_deinit(&g_fd_dev.fd_ctx[i]))
141 CAM_ERR(CAM_FD, "FD context %d deinit failed", i);
142 }
143unregister_subdev:
144 if (cam_subdev_remove(&g_fd_dev.sd))
145 CAM_ERR(CAM_FD, "Failed in subdev remove");
146
147 return rc;
148}
149
150static int cam_fd_dev_remove(struct platform_device *pdev)
151{
152 int i, rc;
153
154 for (i = 0; i < CAM_CTX_MAX; i++) {
155 rc = cam_fd_context_deinit(&g_fd_dev.fd_ctx[i]);
156 if (rc)
157 CAM_ERR(CAM_FD, "FD context %d deinit failed, rc=%d",
158 i, rc);
159 }
160
161 rc = cam_fd_hw_mgr_deinit(pdev->dev.of_node);
162 if (rc)
163 CAM_ERR(CAM_FD, "Failed in hw mgr deinit, rc=%d", rc);
164
165 rc = cam_subdev_remove(&g_fd_dev.sd);
166 if (rc)
167 CAM_ERR(CAM_FD, "Unregister failed, rc=%d", rc);
168
169 mutex_destroy(&g_fd_dev.lock);
170 g_fd_dev.probe_done = false;
171
172 return rc;
173}
174
175static const struct of_device_id cam_fd_dt_match[] = {
176 {
177 .compatible = "qcom,cam-fd"
178 },
179 {}
180};
181
182static struct platform_driver cam_fd_driver = {
183 .probe = cam_fd_dev_probe,
184 .remove = cam_fd_dev_remove,
185 .driver = {
186 .name = "cam_fd",
187 .owner = THIS_MODULE,
188 .of_match_table = cam_fd_dt_match,
189 },
190};
191
192static int __init cam_fd_dev_init_module(void)
193{
194 return platform_driver_register(&cam_fd_driver);
195}
196
197static void __exit cam_fd_dev_exit_module(void)
198{
199 platform_driver_unregister(&cam_fd_driver);
200}
201
202module_init(cam_fd_dev_init_module);
203module_exit(cam_fd_dev_exit_module);
204MODULE_DESCRIPTION("MSM FD driver");
205MODULE_LICENSE("GPL v2");