This source file includes following definitions.
- mcam_to_cam
- mmpcam_add_device
- mmpcam_remove_device
- mmpcam_find_device
- mmpcam_calc_dphy
- mmpcam_irq
- mcam_init_clk
- mmpcam_probe
- mmpcam_remove
- mmpcam_platform_remove
- mmpcam_suspend
- mmpcam_resume
- mmpcam_init_module
- mmpcam_exit_module
1
2
3
4
5
6
7
8
9
10 #include <linux/init.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/interrupt.h>
14 #include <linux/spinlock.h>
15 #include <linux/slab.h>
16 #include <linux/videodev2.h>
17 #include <media/v4l2-device.h>
18 #include <linux/platform_data/media/mmp-camera.h>
19 #include <linux/device.h>
20 #include <linux/of.h>
21 #include <linux/of_platform.h>
22 #include <linux/platform_device.h>
23 #include <linux/io.h>
24 #include <linux/list.h>
25 #include <linux/pm.h>
26 #include <linux/clk.h>
27
28 #include "mcam-core.h"
29
30 MODULE_ALIAS("platform:mmp-camera");
31 MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
32 MODULE_LICENSE("GPL");
33
34 static char *mcam_clks[] = {"axi", "func", "phy"};
35
36 struct mmp_camera {
37 struct platform_device *pdev;
38 struct mcam_camera mcam;
39 struct list_head devlist;
40 struct clk *mipi_clk;
41 int irq;
42 };
43
44 static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam)
45 {
46 return container_of(mcam, struct mmp_camera, mcam);
47 }
48
49
50
51
52
53
54
55 static LIST_HEAD(mmpcam_devices);
56 static struct mutex mmpcam_devices_lock;
57
58 static void mmpcam_add_device(struct mmp_camera *cam)
59 {
60 mutex_lock(&mmpcam_devices_lock);
61 list_add(&cam->devlist, &mmpcam_devices);
62 mutex_unlock(&mmpcam_devices_lock);
63 }
64
65 static void mmpcam_remove_device(struct mmp_camera *cam)
66 {
67 mutex_lock(&mmpcam_devices_lock);
68 list_del(&cam->devlist);
69 mutex_unlock(&mmpcam_devices_lock);
70 }
71
72
73
74
75
76
77 static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
78 {
79 struct mmp_camera *cam;
80
81 mutex_lock(&mmpcam_devices_lock);
82 list_for_each_entry(cam, &mmpcam_devices, devlist) {
83 if (cam->pdev == pdev) {
84 mutex_unlock(&mmpcam_devices_lock);
85 return cam;
86 }
87 }
88 mutex_unlock(&mmpcam_devices_lock);
89 return NULL;
90 }
91
92
93
94
95
96
97
98
99
100
101 static void mmpcam_calc_dphy(struct mcam_camera *mcam)
102 {
103 struct mmp_camera *cam = mcam_to_cam(mcam);
104 struct mmp_camera_platform_data *pdata = cam->pdev->dev.platform_data;
105 struct device *dev = &cam->pdev->dev;
106 unsigned long tx_clk_esc;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 switch (pdata->dphy3_algo) {
137 case DPHY3_ALGO_PXA910:
138
139
140
141 pdata->dphy[0] =
142 (((1 + (pdata->lane_clk * 80) / 1000) & 0xff) << 8)
143 | (1 + pdata->lane_clk * 35 / 1000);
144 break;
145 case DPHY3_ALGO_PXA2128:
146
147
148
149 pdata->dphy[0] =
150 (((2 + (pdata->lane_clk * 110) / 1000) & 0xff) << 8)
151 | (1 + pdata->lane_clk * 35 / 1000);
152 break;
153 default:
154
155
156
157 dev_dbg(dev, "camera: use the default CSI2_DPHY3 value\n");
158 }
159
160
161
162
163 if (IS_ERR(cam->mipi_clk))
164 return;
165
166
167 clk_prepare_enable(cam->mipi_clk);
168 tx_clk_esc = (clk_get_rate(cam->mipi_clk) / 1000000) / 12;
169 clk_disable_unprepare(cam->mipi_clk);
170
171
172
173
174
175
176
177
178
179
180
181 pdata->dphy[2] =
182 ((((534 * tx_clk_esc) / 2000 - 1) & 0xff) << 8)
183 | (((38 * tx_clk_esc) / 1000 - 1) & 0xff);
184
185 dev_dbg(dev, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n",
186 pdata->dphy[0], pdata->dphy[1], pdata->dphy[2]);
187 }
188
189 static irqreturn_t mmpcam_irq(int irq, void *data)
190 {
191 struct mcam_camera *mcam = data;
192 unsigned int irqs, handled;
193
194 spin_lock(&mcam->dev_lock);
195 irqs = mcam_reg_read(mcam, REG_IRQSTAT);
196 handled = mccic_irq(mcam, irqs);
197 spin_unlock(&mcam->dev_lock);
198 return IRQ_RETVAL(handled);
199 }
200
201 static void mcam_init_clk(struct mcam_camera *mcam)
202 {
203 unsigned int i;
204
205 for (i = 0; i < NR_MCAM_CLK; i++) {
206 if (mcam_clks[i] != NULL) {
207
208
209
210 mcam->clk[i] = devm_clk_get(mcam->dev, mcam_clks[i]);
211 if (IS_ERR(mcam->clk[i]))
212 dev_warn(mcam->dev, "Could not get clk: %s\n",
213 mcam_clks[i]);
214 }
215 }
216 }
217
218 static int mmpcam_probe(struct platform_device *pdev)
219 {
220 struct mmp_camera *cam;
221 struct mcam_camera *mcam;
222 struct resource *res;
223 struct fwnode_handle *ep;
224 struct mmp_camera_platform_data *pdata;
225 int ret;
226
227 cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL);
228 if (cam == NULL)
229 return -ENOMEM;
230 cam->pdev = pdev;
231 INIT_LIST_HEAD(&cam->devlist);
232
233 mcam = &cam->mcam;
234 mcam->calc_dphy = mmpcam_calc_dphy;
235 mcam->dev = &pdev->dev;
236 pdata = pdev->dev.platform_data;
237 if (pdata) {
238 mcam->mclk_src = pdata->mclk_src;
239 mcam->mclk_div = pdata->mclk_div;
240 mcam->bus_type = pdata->bus_type;
241 mcam->dphy = pdata->dphy;
242 mcam->lane = pdata->lane;
243 } else {
244
245
246
247
248
249
250 mcam->mclk_src = 3;
251 mcam->mclk_div = 2;
252 }
253 if (mcam->bus_type == V4L2_MBUS_CSI2_DPHY) {
254 cam->mipi_clk = devm_clk_get(mcam->dev, "mipi");
255 if ((IS_ERR(cam->mipi_clk) && mcam->dphy[2] == 0))
256 return PTR_ERR(cam->mipi_clk);
257 }
258 mcam->mipi_enabled = false;
259 mcam->chip_id = MCAM_ARMADA610;
260 mcam->buffer_mode = B_DMA_sg;
261 strscpy(mcam->bus_info, "platform:mmp-camera", sizeof(mcam->bus_info));
262 spin_lock_init(&mcam->dev_lock);
263
264
265
266 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
267 mcam->regs = devm_ioremap_resource(&pdev->dev, res);
268 if (IS_ERR(mcam->regs))
269 return PTR_ERR(mcam->regs);
270 mcam->regs_size = resource_size(res);
271
272 mcam_init_clk(mcam);
273
274
275
276
277 ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(pdev->dev.of_node),
278 NULL);
279 if (!ep)
280 return -ENODEV;
281
282 mcam->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
283 mcam->asd.match.fwnode = fwnode_graph_get_remote_port_parent(ep);
284
285 fwnode_handle_put(ep);
286
287
288
289
290 ret = mccic_register(mcam);
291 if (ret)
292 return ret;
293
294
295
296
297 ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
298 mcam->mclk);
299 if (ret) {
300 dev_err(&pdev->dev, "can't add DT clock provider\n");
301 goto out;
302 }
303
304
305
306
307
308 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
309 if (res == NULL) {
310 ret = -ENODEV;
311 goto out;
312 }
313 cam->irq = res->start;
314 ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED,
315 "mmp-camera", mcam);
316 if (ret == 0) {
317 mmpcam_add_device(cam);
318 return 0;
319 }
320
321 out:
322 fwnode_handle_put(mcam->asd.match.fwnode);
323 mccic_shutdown(mcam);
324
325 return ret;
326 }
327
328
329 static int mmpcam_remove(struct mmp_camera *cam)
330 {
331 struct mcam_camera *mcam = &cam->mcam;
332
333 mmpcam_remove_device(cam);
334 mccic_shutdown(mcam);
335 return 0;
336 }
337
338 static int mmpcam_platform_remove(struct platform_device *pdev)
339 {
340 struct mmp_camera *cam = mmpcam_find_device(pdev);
341
342 if (cam == NULL)
343 return -ENODEV;
344 return mmpcam_remove(cam);
345 }
346
347
348
349
350 #ifdef CONFIG_PM
351
352 static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state)
353 {
354 struct mmp_camera *cam = mmpcam_find_device(pdev);
355
356 if (state.event != PM_EVENT_SUSPEND)
357 return 0;
358 mccic_suspend(&cam->mcam);
359 return 0;
360 }
361
362 static int mmpcam_resume(struct platform_device *pdev)
363 {
364 struct mmp_camera *cam = mmpcam_find_device(pdev);
365
366 return mccic_resume(&cam->mcam);
367 }
368
369 #endif
370
371 static const struct of_device_id mmpcam_of_match[] = {
372 { .compatible = "marvell,mmp2-ccic", },
373 {},
374 };
375 MODULE_DEVICE_TABLE(of, mmpcam_of_match);
376
377 static struct platform_driver mmpcam_driver = {
378 .probe = mmpcam_probe,
379 .remove = mmpcam_platform_remove,
380 #ifdef CONFIG_PM
381 .suspend = mmpcam_suspend,
382 .resume = mmpcam_resume,
383 #endif
384 .driver = {
385 .name = "mmp-camera",
386 .of_match_table = of_match_ptr(mmpcam_of_match),
387 }
388 };
389
390
391 static int __init mmpcam_init_module(void)
392 {
393 mutex_init(&mmpcam_devices_lock);
394 return platform_driver_register(&mmpcam_driver);
395 }
396
397 static void __exit mmpcam_exit_module(void)
398 {
399 platform_driver_unregister(&mmpcam_driver);
400
401
402
403 if (!list_empty(&mmpcam_devices))
404 printk(KERN_ERR "mmp_camera leaving devices behind\n");
405 }
406
407 module_init(mmpcam_init_module);
408 module_exit(mmpcam_exit_module);