Update from product codes
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / media / sprd_scale / common / img_scale.c
1 /*
2  * Copyright (C) 2012 Spreadtrum Communications Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/miscdevice.h>
16 #include <linux/platform_device.h>
17 #include <linux/proc_fs.h>
18 #include <linux/slab.h>
19 #include <linux/delay.h>
20 #include <asm/uaccess.h>
21 #include <video/sprd_scale_k.h>
22 #include <linux/kthread.h>
23 #include <linux/of.h>
24 #include <linux/of_device.h>
25 #include <linux/vmalloc.h>
26
27 #include "img_scale.h"
28 #include "compat_img_scale.h"
29 #include "dcam_drv.h"
30
31 #ifndef CONFIG_64BIT
32 #include <soc/sprd/hardware.h>
33 #endif
34
35 #define SCALE_DEVICE_NAME "sprd_scale"
36 #define SCALE_TIMEOUT 5000/*ms*/
37 #define SCALE_MINOR MISC_DYNAMIC_MINOR
38 #define SC_COEFF_BUF_SIZE (24 << 10)
39
40 static void scale_k_irq(void *fd)
41 {
42         struct scale_k_file *scale_file = (struct scale_k_file *)fd;
43
44         if (!scale_file) {
45                 printk("scale_k_irq error: hand is null");
46                 return;
47         }
48
49         SCALE_TRACE("sc done.\n");
50
51         up(&scale_file->scale_done_sem);
52 }
53
54 static void scale_k_file_init(struct scale_k_file *fd, struct scale_k_private *scale_private)
55 {
56         fd->scale_private = scale_private;
57
58         sema_init(&fd->scale_done_sem, 0);
59
60         fd->drv_private.scale_fd = (void*)fd;
61         fd->drv_private.path_info.coeff_addr = scale_private->coeff_addr;
62
63         spin_lock_init(&fd->drv_private.scale_drv_lock);
64         sema_init(&fd->drv_private.path_info.done_sem, 0);
65 }
66
67 static int scale_k_open(struct inode *node, struct file *file)
68 {
69         int ret = 0;
70         struct scale_k_file *fd = NULL;
71         struct scale_k_private *scale_private = NULL;
72         struct miscdevice *md = file->private_data;
73
74         if (!md) {
75                 ret = -EFAULT;
76                 printk("scale_k_open error: miscdevice is null \n");
77                 goto exit;
78         }
79         scale_private = (struct scale_k_private *)md->this_device->platform_data;
80         if (!scale_private) {
81                 ret = -EFAULT;
82                 printk("scale_k_open error: scale_private is null \n");
83                 goto exit;
84         }
85
86         fd = vzalloc(sizeof(*fd));
87         if (!fd) {
88                 ret = -ENOMEM;
89                 printk("scale_k_open error: alloc \n");
90                 goto exit;
91         }
92         fd->dn = md->this_device->of_node;
93         scale_k_file_init(fd, scale_private);
94
95         file->private_data = fd;
96
97         SCALE_TRACE("scale_k_open fd=%p ret=%d\n", fd, ret);
98
99 exit:
100         return ret;
101 }
102
103 ssize_t scale_k_read(struct file *file, char __user *u_data, size_t cnt, loff_t *cnt_ret)
104 {
105         uint32_t rt_word[2];
106
107         (void)file; (void)cnt; (void)cnt_ret;
108
109         if (cnt < sizeof(uint32_t)) {
110                 printk("scale_k_read error: wrong size of u_data: %ld \n", cnt);
111                 return -1;
112         }
113
114         rt_word[0] = SCALE_LINE_BUF_LENGTH;
115         rt_word[1] = SCALE_SC_COEFF_MAX;
116
117         return copy_to_user(u_data, (void*)rt_word, (uint32_t)(2 * sizeof(uint32_t)));
118 }
119
120 static int scale_k_release(struct inode *node, struct file *file)
121 {
122         struct scale_k_file *fd = NULL;
123         struct scale_k_private *scale_private = NULL;
124
125         fd = file->private_data;
126         if (!fd) {
127                 goto exit;
128         }
129
130         scale_private = fd->scale_private;
131         if (!scale_private) {
132                 goto fd_free;
133         }
134
135         down(&scale_private->start_sem);
136         up(&scale_private->start_sem);
137
138 fd_free:
139         vfree(fd);
140         fd = NULL;
141         file->private_data = NULL;
142
143 exit:
144         SCALE_TRACE("scale_k_release\n");
145
146         return 0;
147 }
148
149 static void sprd_img_print_reg(void)
150 {
151         uint32_t*                reg_buf = NULL;
152         uint32_t                 reg_buf_len = 0x400;
153         int                      ret;
154         uint32_t                 print_len = 0, print_cnt = 0;
155         reg_buf = (uint32_t*)vzalloc(reg_buf_len);
156         if (NULL == reg_buf)
157                 return;
158         ret = dcam_read_registers(reg_buf, &reg_buf_len);
159         if (ret) {
160                 vfree(reg_buf);
161                 return;
162         }
163         printk("dcam registers \n");
164         while (print_len < reg_buf_len) {
165                 printk("offset 0x%03x : 0x%08x, 0x%08x, 0x%08x, 0x%08x \n",
166                         print_len,
167                         reg_buf[print_cnt],
168                         reg_buf[print_cnt+1],
169                         reg_buf[print_cnt+2],
170                         reg_buf[print_cnt+3]);
171                 print_cnt += 4;
172                 print_len += 16;
173         }
174         udelay(1);
175         vfree(reg_buf);
176         return;
177 }
178 static long scale_k_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
179 {
180         int ret = 0;
181         struct scale_k_private *scale_private;
182         struct scale_k_file *fd;
183         struct scale_frame_param_t frame_params;
184         struct scale_slice_param_t slice_params;
185
186         fd = file->private_data;
187         if (!fd) {
188                 ret = - EFAULT;
189                 printk("scale_k_ioctl error:  fd null \n");
190                 goto ioctl_exit;
191         }
192
193         scale_private = fd->scale_private;
194         if (!scale_private) {
195                 ret = -EFAULT;
196                 printk("scale_k_ioctl erro: scale private null \n");
197                 goto ioctl_exit;
198         }
199
200         switch (cmd) {
201         case SCALE_IO_START:
202
203                 down(&scale_private->start_sem);
204
205                 ret = scale_k_module_en(fd->dn);
206                 if (unlikely(ret)) {
207                         printk("rot_k_ioctl erro: scale_module_en\n");
208                         up(&scale_private->start_sem);
209                         goto ioctl_exit;
210                 }
211
212                 ret = scale_k_isr_reg(scale_k_irq, &fd->drv_private);
213                 if (unlikely(ret)) {
214                         printk("rot_k_ioctl error:  scale_k_isr_reg\n");
215                         scale_k_module_dis(fd->dn);
216                         up(&scale_private->start_sem);
217                         goto ioctl_exit;
218
219                 }
220
221                 ret = copy_from_user(&frame_params, (struct scale_frame_param_t *)arg, sizeof(frame_params));
222                 if (ret) {
223                         printk("rot_k_ioctl error: get frame param info \n");
224                         scale_k_module_dis(fd->dn);
225                         up(&scale_private->start_sem);
226                         goto ioctl_exit;
227                 }
228
229                 ret = scale_k_start(&frame_params, &fd->drv_private.path_info);
230                 if (ret) {
231                         printk("rot_k_ioctl error: frame start \n");
232                         scale_k_module_dis(fd->dn);
233                         up(&scale_private->start_sem);
234                         goto ioctl_exit;
235                 }
236
237                 break;
238         case SCALE_IO_DONE:
239                 ret = down_timeout(&fd->scale_done_sem, msecs_to_jiffies(SCALE_TIMEOUT));
240                 if (ret) {
241                         printk("scale_k_ioctl error:  interruptible time out\n");
242                         sprd_img_print_reg();
243                         goto ioctl_out;
244                 }
245
246                 scale_k_stop();
247
248                 scale_k_module_dis(fd->dn);
249
250                 up(&scale_private->start_sem);
251                 break;
252         case SCALE_IO_CONTINUE:
253                 /*Caution: slice scale is not supported by current driver.Please do not use it*/
254                 ret = copy_from_user(&slice_params, (struct scale_slice_param_t *)arg, sizeof(slice_params));
255                 if (ret) {
256                         printk("rot_k_ioctl error: get slice param info \n");
257                         goto ioctl_exit;
258                 }
259
260                 ret = scale_k_continue(&slice_params, &fd->drv_private.path_info);
261                 if (ret) {
262                         printk("rot_k_ioctl error: continue \n");
263                 }
264                 break;
265
266         default:
267                 break;
268         }
269
270 ioctl_exit:
271         return ret;
272
273 ioctl_out:
274         dcam_resize_end();
275         scale_k_stop();
276         scale_k_module_dis(fd->dn);
277         up(&scale_private->start_sem);
278         return ret;
279 }
280
281 static struct file_operations scale_fops = {
282         .owner = THIS_MODULE,
283         .open = scale_k_open,
284         .read = scale_k_read,
285         .unlocked_ioctl = scale_k_ioctl,
286         .compat_ioctl = compat_scale_k_ioctl,
287         .release = scale_k_release,
288 };
289
290 static struct miscdevice scale_dev = {
291         .minor = SCALE_MINOR,
292         .name = SCALE_DEVICE_NAME,
293         .fops = &scale_fops,
294 };
295
296 int scale_k_probe(struct platform_device *pdev)
297 {
298         int ret;
299         struct scale_k_private *scale_private;
300
301         scale_private = devm_kzalloc(&pdev->dev, sizeof(*scale_private), GFP_KERNEL);
302         if (!scale_private) {
303                 return -ENOMEM;
304         }
305         scale_private->coeff_addr = (void *)vzalloc(SC_COEFF_BUF_SIZE);
306         if (!scale_private->coeff_addr) {
307                 devm_kfree(&pdev->dev, scale_private);
308                 return -ENOMEM;
309         }
310         sema_init(&scale_private->start_sem, 1);
311
312         platform_set_drvdata(pdev, scale_private);
313
314         ret = misc_register(&scale_dev);
315         if (ret) {
316                 printk("scale_k_probe error: ret=%d\n", ret);
317                 ret = -EACCES;
318                 goto probe_out;
319         }
320
321         scale_dev.this_device->of_node = pdev->dev.of_node;
322         scale_dev.this_device->platform_data = (void *)scale_private;
323
324         goto exit;
325
326 probe_out:
327         vfree(scale_private->coeff_addr);
328         devm_kfree(&pdev->dev, scale_private);
329         platform_set_drvdata(pdev, NULL);
330 exit:
331         return 0;
332 }
333
334 static int scale_k_remove(struct platform_device *pdev)
335 {
336         struct scale_k_private *scale_private;
337
338         scale_private = platform_get_drvdata(pdev);
339
340         if (!scale_private)
341                 goto remove_exit;
342
343         misc_deregister(&scale_dev);
344         if (scale_private->coeff_addr) {
345                 vfree(scale_private->coeff_addr);
346         }
347         devm_kfree(&pdev->dev, scale_private);
348         platform_set_drvdata(pdev, NULL);
349
350 remove_exit:
351         return 0;
352 }
353
354 static const struct of_device_id of_match_table_scale[] = {
355         { .compatible = "sprd,sprd_scale", },
356         { },
357 };
358
359 static struct platform_driver scale_driver =
360 {
361         .probe = scale_k_probe,
362         .remove = scale_k_remove,
363         .driver = {
364                 .owner = THIS_MODULE,
365                 .name = SCALE_DEVICE_NAME,
366                 .of_match_table = of_match_ptr(of_match_table_scale),
367         }
368 };
369
370 int __init scale_k_init(void)
371 {
372         if (platform_driver_register(&scale_driver) != 0) {
373                 printk("platform scale device register Failed \n");
374                 return -1;
375         }
376
377         return 0;
378 }
379
380 void scale_k_exit(void)
381 {
382         platform_driver_unregister(&scale_driver);
383 }
384
385 module_init(scale_k_init);
386 module_exit(scale_k_exit);
387 MODULE_DESCRIPTION("Sprd Scale Driver");
388 MODULE_LICENSE("GPL");