blob: a4ee1040e4c86388a73cef7050f2c1660778eed4 [file] [log] [blame]
Jigarkumar Zala8c26cab2018-07-23 15:55:07 -07001/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
Junzhe Zoucc79a572017-08-22 16:18:57 -07002 *
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_lrme_context.h"
22#include "cam_lrme_hw_mgr.h"
23#include "cam_lrme_hw_mgr_intf.h"
24
25#define CAM_LRME_DEV_NAME "cam-lrme"
26
27/**
28 * struct cam_lrme_dev
29 *
30 * @sd : Subdev information
31 * @ctx : List of base contexts
32 * @lrme_ctx : List of LRME contexts
33 * @lock : Mutex for LRME subdev
34 * @open_cnt : Open count of LRME subdev
35 */
36struct cam_lrme_dev {
37 struct cam_subdev sd;
38 struct cam_context ctx[CAM_CTX_MAX];
39 struct cam_lrme_context lrme_ctx[CAM_CTX_MAX];
40 struct mutex lock;
41 uint32_t open_cnt;
42};
43
44static struct cam_lrme_dev *g_lrme_dev;
45
46static int cam_lrme_dev_buf_done_cb(void *ctxt_to_hw_map, uint32_t evt_id,
47 void *evt_data)
48{
49 uint64_t index;
50 struct cam_context *ctx;
51 int rc;
52
53 index = CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map);
54 CAM_DBG(CAM_LRME, "ctx index %llu, evt_id %u\n", index, evt_id);
55 ctx = &g_lrme_dev->ctx[index];
56 rc = ctx->irq_cb_intf(ctx, evt_id, evt_data);
57 if (rc)
58 CAM_ERR(CAM_LRME, "irq callback failed");
59
60 return rc;
61}
62
63static int cam_lrme_dev_open(struct v4l2_subdev *sd,
64 struct v4l2_subdev_fh *fh)
65{
66 struct cam_lrme_dev *lrme_dev = g_lrme_dev;
67
68 if (!lrme_dev) {
69 CAM_ERR(CAM_LRME,
70 "LRME Dev not initialized, dev=%pK", lrme_dev);
71 return -ENODEV;
72 }
73
74 mutex_lock(&lrme_dev->lock);
75 lrme_dev->open_cnt++;
76 mutex_unlock(&lrme_dev->lock);
77
78 return 0;
79}
80
81static int cam_lrme_dev_close(struct v4l2_subdev *sd,
82 struct v4l2_subdev_fh *fh)
83{
84 struct cam_lrme_dev *lrme_dev = g_lrme_dev;
85 struct cam_node *node = v4l2_get_subdevdata(sd);
86
87 if (!lrme_dev) {
88 CAM_ERR(CAM_LRME, "Invalid args");
89 return -ENODEV;
90 }
91
92 mutex_lock(&lrme_dev->lock);
93 lrme_dev->open_cnt--;
94 mutex_unlock(&lrme_dev->lock);
95
96 if (!node) {
97 CAM_ERR(CAM_LRME, "Node is NULL");
98 return -EINVAL;
99 }
100
101 if (lrme_dev->open_cnt == 0)
102 cam_node_shutdown(node);
103
104 return 0;
105}
106
107static const struct v4l2_subdev_internal_ops cam_lrme_subdev_internal_ops = {
108 .open = cam_lrme_dev_open,
109 .close = cam_lrme_dev_close,
110};
111
112static int cam_lrme_dev_probe(struct platform_device *pdev)
113{
114 int rc;
115 int i;
116 struct cam_hw_mgr_intf hw_mgr_intf;
117 struct cam_node *node;
118
119 g_lrme_dev = kzalloc(sizeof(struct cam_lrme_dev), GFP_KERNEL);
120 if (!g_lrme_dev) {
121 CAM_ERR(CAM_LRME, "No memory");
122 return -ENOMEM;
123 }
124 g_lrme_dev->sd.internal_ops = &cam_lrme_subdev_internal_ops;
125
126 mutex_init(&g_lrme_dev->lock);
127
128 rc = cam_subdev_probe(&g_lrme_dev->sd, pdev, CAM_LRME_DEV_NAME,
129 CAM_LRME_DEVICE_TYPE);
130 if (rc) {
131 CAM_ERR(CAM_LRME, "LRME cam_subdev_probe failed");
132 goto free_mem;
133 }
134 node = (struct cam_node *)g_lrme_dev->sd.token;
135
136 rc = cam_lrme_hw_mgr_init(&hw_mgr_intf, cam_lrme_dev_buf_done_cb);
137 if (rc) {
138 CAM_ERR(CAM_LRME, "Can not initialized LRME HW manager");
139 goto unregister;
140 }
141
142 for (i = 0; i < CAM_CTX_MAX; i++) {
143 rc = cam_lrme_context_init(&g_lrme_dev->lrme_ctx[i],
144 &g_lrme_dev->ctx[i],
145 &node->hw_mgr_intf, i);
146 if (rc) {
147 CAM_ERR(CAM_LRME, "LRME context init failed");
148 goto deinit_ctx;
149 }
150 }
151
152 rc = cam_node_init(node, &hw_mgr_intf, g_lrme_dev->ctx, CAM_CTX_MAX,
153 CAM_LRME_DEV_NAME);
154 if (rc) {
155 CAM_ERR(CAM_LRME, "LRME node init failed");
156 goto deinit_ctx;
157 }
158
159 CAM_DBG(CAM_LRME, "%s probe complete", g_lrme_dev->sd.name);
160
161 return 0;
162
163deinit_ctx:
164 for (--i; i >= 0; i--) {
165 if (cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i]))
166 CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i);
167 }
168unregister:
169 if (cam_subdev_remove(&g_lrme_dev->sd))
170 CAM_ERR(CAM_LRME, "Failed in subdev remove");
171free_mem:
172 kfree(g_lrme_dev);
173
174 return rc;
175}
176
177static int cam_lrme_dev_remove(struct platform_device *pdev)
178{
179 int i;
180 int rc = 0;
181
182 for (i = 0; i < CAM_CTX_MAX; i++) {
183 rc = cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i]);
184 if (rc)
185 CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i);
186 }
187
188 rc = cam_lrme_hw_mgr_deinit();
189 if (rc)
190 CAM_ERR(CAM_LRME, "Failed in hw mgr deinit, rc=%d", rc);
191
192 rc = cam_subdev_remove(&g_lrme_dev->sd);
193 if (rc)
194 CAM_ERR(CAM_LRME, "Unregister failed");
195
196 mutex_destroy(&g_lrme_dev->lock);
197 kfree(g_lrme_dev);
198 g_lrme_dev = NULL;
199
200 return rc;
201}
202
203static const struct of_device_id cam_lrme_dt_match[] = {
204 {
205 .compatible = "qcom,cam-lrme"
206 },
207 {}
208};
209
210static struct platform_driver cam_lrme_driver = {
211 .probe = cam_lrme_dev_probe,
212 .remove = cam_lrme_dev_remove,
213 .driver = {
214 .name = "cam_lrme",
215 .owner = THIS_MODULE,
216 .of_match_table = cam_lrme_dt_match,
Jigarkumar Zala8c26cab2018-07-23 15:55:07 -0700217 .suppress_bind_attrs = true,
Junzhe Zoucc79a572017-08-22 16:18:57 -0700218 },
219};
220
221static int __init cam_lrme_dev_init_module(void)
222{
223 return platform_driver_register(&cam_lrme_driver);
224}
225
226static void __exit cam_lrme_dev_exit_module(void)
227{
228 platform_driver_unregister(&cam_lrme_driver);
229}
230
231module_init(cam_lrme_dev_init_module);
232module_exit(cam_lrme_dev_exit_module);
233MODULE_DESCRIPTION("MSM LRME driver");
234MODULE_LICENSE("GPL v2");