blob: bb31b6aa8a12010578ba92ca54e32ba6ef6d1f05 [file] [log] [blame]
Nagamalleswararao Ganjibcdea002011-09-13 15:43:47 -07001/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -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/platform_device.h>
14#include <linux/cdev.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/interrupt.h>
19#include <linux/sched.h>
20#include <linux/uaccess.h>
21#include <linux/clk.h>
22#include <mach/clk.h>
23#include <linux/android_pmem.h>
24#include <linux/msm_rotator.h>
25#include <linux/io.h>
26#include <mach/msm_rotator_imem.h>
27#include <linux/ktime.h>
28#include <linux/workqueue.h>
29#include <linux/file.h>
30#include <linux/major.h>
31#include <linux/regulator/consumer.h>
32
33#define DRIVER_NAME "msm_rotator"
34
35#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
36#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
37#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
38#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
39#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
40#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
41#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
42#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
43#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
44#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070045#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
47#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
48#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
49#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
50#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
51#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
52#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
53#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070054#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
56#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
57#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
58#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
59
60#define MSM_ROTATOR_MAX_ROT 0x07
61#define MSM_ROTATOR_MAX_H 0x1fff
62#define MSM_ROTATOR_MAX_W 0x1fff
63
64/* from lsb to msb */
65#define GET_PACK_PATTERN(a, x, y, z, bit) \
66 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
67#define CLR_G 0x0
68#define CLR_B 0x1
69#define CLR_R 0x2
70#define CLR_ALPHA 0x3
71
72#define CLR_Y CLR_G
73#define CLR_CB CLR_B
74#define CLR_CR CLR_R
75
76#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
77 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
78 (((r) & MDP_FLIP_UD) ? 4 : 0))
79
80#define IMEM_NO_OWNER -1;
81
82#define MAX_SESSIONS 16
83#define INVALID_SESSION -1
84#define VERSION_KEY_MASK 0xFFFFFF00
85
86struct tile_parm {
87 unsigned int width; /* tile's width */
88 unsigned int height; /* tile's height */
89 unsigned int row_tile_w; /* tiles per row's width */
90 unsigned int row_tile_h; /* tiles per row's height */
91};
92
Adrian Salido-Moreno88411862011-09-20 18:54:03 -070093struct msm_rotator_mem_planes {
94 unsigned int num_planes;
95 unsigned int plane_size[4];
96 unsigned int total_size;
97};
98
99#define checkoffset(offset, size, max_size) \
100 ((size) > (max_size) || (offset) > ((max_size) - (size)))
101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102struct msm_rotator_dev {
103 void __iomem *io_base;
104 int irq;
105 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
106 struct clk *core_clk;
107 int pid_list[MAX_SESSIONS];
108 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 int rot_clk_state;
110 struct regulator *regulator;
111 struct delayed_work rot_clk_work;
112 struct clk *imem_clk;
113 int imem_clk_state;
114 struct delayed_work imem_clk_work;
115 struct platform_device *pdev;
116 struct cdev cdev;
117 struct device *device;
118 struct class *class;
119 dev_t dev_num;
120 int processing;
121 int last_session_idx;
122 struct mutex rotator_lock;
123 struct mutex imem_lock;
124 int imem_owner;
125 wait_queue_head_t wq;
126};
127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128#define COMPONENT_5BITS 1
129#define COMPONENT_6BITS 2
130#define COMPONENT_8BITS 3
131
132static struct msm_rotator_dev *msm_rotator_dev;
133
134enum {
135 CLK_EN,
136 CLK_DIS,
137 CLK_SUSPEND,
138};
139
140int msm_rotator_imem_allocate(int requestor)
141{
142 int rc = 0;
143
144#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
145 switch (requestor) {
146 case ROTATOR_REQUEST:
147 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
148 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
149 rc = 1;
150 } else
151 rc = 0;
152 break;
153 case JPEG_REQUEST:
154 mutex_lock(&msm_rotator_dev->imem_lock);
155 msm_rotator_dev->imem_owner = JPEG_REQUEST;
156 rc = 1;
157 break;
158 default:
159 rc = 0;
160 }
161#else
162 if (requestor == JPEG_REQUEST)
163 rc = 1;
164#endif
165 if (rc == 1) {
166 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
167 if (msm_rotator_dev->imem_clk_state != CLK_EN
168 && msm_rotator_dev->imem_clk) {
169 clk_enable(msm_rotator_dev->imem_clk);
170 msm_rotator_dev->imem_clk_state = CLK_EN;
171 }
172 }
173
174 return rc;
175}
176EXPORT_SYMBOL(msm_rotator_imem_allocate);
177
178void msm_rotator_imem_free(int requestor)
179{
180#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
181 if (msm_rotator_dev->imem_owner == requestor) {
182 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
183 mutex_unlock(&msm_rotator_dev->imem_lock);
184 }
185#else
186 if (requestor == JPEG_REQUEST)
187 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
188#endif
189}
190EXPORT_SYMBOL(msm_rotator_imem_free);
191
192static void msm_rotator_imem_clk_work_f(struct work_struct *work)
193{
194#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
195 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
196 if (msm_rotator_dev->imem_clk_state == CLK_EN
197 && msm_rotator_dev->imem_clk) {
198 clk_disable(msm_rotator_dev->imem_clk);
199 msm_rotator_dev->imem_clk_state = CLK_DIS;
200 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
201 msm_rotator_dev->imem_clk_state = CLK_DIS;
202 mutex_unlock(&msm_rotator_dev->imem_lock);
203 }
204#endif
205}
206
207/* enable clocks needed by rotator block */
208static void enable_rot_clks(void)
209{
210 if (msm_rotator_dev->regulator)
211 regulator_enable(msm_rotator_dev->regulator);
212 if (msm_rotator_dev->core_clk != NULL)
213 clk_enable(msm_rotator_dev->core_clk);
214 if (msm_rotator_dev->pclk != NULL)
215 clk_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216}
217
218/* disable clocks needed by rotator block */
219static void disable_rot_clks(void)
220{
221 if (msm_rotator_dev->core_clk != NULL)
222 clk_disable(msm_rotator_dev->core_clk);
223 if (msm_rotator_dev->pclk != NULL)
224 clk_disable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 if (msm_rotator_dev->regulator)
226 regulator_disable(msm_rotator_dev->regulator);
227}
228
229static void msm_rotator_rot_clk_work_f(struct work_struct *work)
230{
231 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
232 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
233 disable_rot_clks();
234 msm_rotator_dev->rot_clk_state = CLK_DIS;
235 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
236 msm_rotator_dev->rot_clk_state = CLK_DIS;
237 mutex_unlock(&msm_rotator_dev->rotator_lock);
238 }
239}
240
241static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
242{
243 if (msm_rotator_dev->processing) {
244 msm_rotator_dev->processing = 0;
245 wake_up(&msm_rotator_dev->wq);
246 } else
247 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
248
249 return IRQ_HANDLED;
250}
251
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700252static unsigned int tile_size(unsigned int src_width,
253 unsigned int src_height,
254 const struct tile_parm *tp)
255{
256 unsigned int tile_w, tile_h;
257 unsigned int row_num_w, row_num_h;
258 tile_w = tp->width * tp->row_tile_w;
259 tile_h = tp->height * tp->row_tile_h;
260 row_num_w = (src_width + tile_w - 1) / tile_w;
261 row_num_h = (src_height + tile_h - 1) / tile_h;
262 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
263}
264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265static int get_bpp(int format)
266{
267 switch (format) {
268 case MDP_RGB_565:
269 case MDP_BGR_565:
270 return 2;
271
272 case MDP_XRGB_8888:
273 case MDP_ARGB_8888:
274 case MDP_RGBA_8888:
275 case MDP_BGRA_8888:
276 case MDP_RGBX_8888:
277 return 4;
278
279 case MDP_Y_CBCR_H2V2:
280 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700281 case MDP_Y_CB_CR_H2V2:
282 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530283 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 case MDP_Y_CRCB_H2V2_TILE:
285 case MDP_Y_CBCR_H2V2_TILE:
286 return 1;
287
288 case MDP_RGB_888:
289 return 3;
290
291 case MDP_YCRYCB_H2V1:
292 return 2;/* YCrYCb interleave */
293
294 case MDP_Y_CRCB_H2V1:
295 case MDP_Y_CBCR_H2V1:
296 return 1;
297
298 default:
299 return -1;
300 }
301
302}
303
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700304static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
305 struct msm_rotator_mem_planes *p)
306{
307 /*
308 * each row of samsung tile consists of two tiles in height
309 * and two tiles in width which means width should align to
310 * 64 x 2 bytes and height should align to 32 x 2 bytes.
311 * video decoder generate two tiles in width and one tile
312 * in height which ends up height align to 32 X 1 bytes.
313 */
314 const struct tile_parm tile = {64, 32, 2, 1};
315 int i;
316
317 if (p == NULL)
318 return -EINVAL;
319
320 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
321 return -ERANGE;
322
323 memset(p, 0, sizeof(*p));
324
325 switch (format) {
326 case MDP_XRGB_8888:
327 case MDP_ARGB_8888:
328 case MDP_RGBA_8888:
329 case MDP_BGRA_8888:
330 case MDP_RGBX_8888:
331 case MDP_RGB_888:
332 case MDP_RGB_565:
333 case MDP_BGR_565:
334 case MDP_YCRYCB_H2V1:
335 p->num_planes = 1;
336 p->plane_size[0] = w * h * get_bpp(format);
337 break;
338 case MDP_Y_CRCB_H2V1:
339 case MDP_Y_CBCR_H2V1:
340 p->num_planes = 2;
341 p->plane_size[0] = w * h;
342 p->plane_size[1] = w * h;
343 break;
344 case MDP_Y_CBCR_H2V2:
345 case MDP_Y_CRCB_H2V2:
346 p->num_planes = 2;
347 p->plane_size[0] = w * h;
348 p->plane_size[1] = w * h / 2;
349 break;
350 case MDP_Y_CRCB_H2V2_TILE:
351 case MDP_Y_CBCR_H2V2_TILE:
352 p->num_planes = 2;
353 p->plane_size[0] = tile_size(w, h, &tile);
354 p->plane_size[1] = tile_size(w, h/2, &tile);
355 break;
356 case MDP_Y_CB_CR_H2V2:
357 case MDP_Y_CR_CB_H2V2:
358 p->num_planes = 3;
359 p->plane_size[0] = w * h;
360 p->plane_size[1] = (w / 2) * (h / 2);
361 p->plane_size[2] = (w / 2) * (h / 2);
362 break;
363 case MDP_Y_CR_CB_GH2V2:
364 p->num_planes = 3;
365 p->plane_size[0] = ALIGN(w, 16) * h;
366 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
367 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
368 break;
369 default:
370 return -EINVAL;
371 }
372
373 for (i = 0; i < p->num_planes; i++)
374 p->total_size += p->plane_size[i];
375
376 return 0;
377}
378
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
380 unsigned int in_paddr,
381 unsigned int out_paddr,
382 unsigned int use_imem,
383 int new_session,
384 unsigned int in_chroma_paddr,
385 unsigned int out_chroma_paddr)
386{
387 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388
389 if (info->src.format != info->dst.format)
390 return -EINVAL;
391
392 bpp = get_bpp(info->src.format);
393 if (bpp < 0)
394 return -ENOTTY;
395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700397 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 iowrite32(out_paddr +
399 ((info->dst_y * info->dst.width) + info->dst_x),
400 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700401 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700402 ((info->dst_y * info->dst.width) + info->dst_x),
403 MSM_ROTATOR_OUTP1_ADDR);
404
405 if (new_session) {
406 iowrite32(info->src.width |
407 info->src.width << 16,
408 MSM_ROTATOR_SRC_YSTRIDE1);
409 if (info->rotations & MDP_ROT_90)
410 iowrite32(info->dst.width |
411 info->dst.width*2 << 16,
412 MSM_ROTATOR_OUT_YSTRIDE1);
413 else
414 iowrite32(info->dst.width |
415 info->dst.width << 16,
416 MSM_ROTATOR_OUT_YSTRIDE1);
417 if (info->src.format == MDP_Y_CBCR_H2V1) {
418 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
419 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
420 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
421 MSM_ROTATOR_OUT_PACK_PATTERN1);
422 } else {
423 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
424 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
425 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
426 MSM_ROTATOR_OUT_PACK_PATTERN1);
427 }
428 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
429 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
430 1 << 8, /* ROT_EN */
431 MSM_ROTATOR_SUB_BLOCK_CFG);
432 iowrite32(0 << 29 | /* frame format 0 = linear */
433 (use_imem ? 0 : 1) << 22 | /* tile size */
434 2 << 19 | /* fetch planes 2 = pseudo */
435 0 << 18 | /* unpack align */
436 1 << 17 | /* unpack tight */
437 1 << 13 | /* unpack count 0=1 component */
438 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
439 0 << 8 | /* has alpha */
440 0 << 6 | /* alpha bits 3=8bits */
441 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
442 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
443 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
444 MSM_ROTATOR_SRC_FORMAT);
445 }
446
447 return 0;
448}
449
450static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
451 unsigned int in_paddr,
452 unsigned int out_paddr,
453 unsigned int use_imem,
454 int new_session,
455 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700456 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700457 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700459 uint32_t dst_format;
460 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700462 switch (info->src.format) {
463 case MDP_Y_CRCB_H2V2_TILE:
464 is_tile = 1;
465 case MDP_Y_CR_CB_H2V2:
466 case MDP_Y_CR_CB_GH2V2:
467 case MDP_Y_CRCB_H2V2:
468 dst_format = MDP_Y_CRCB_H2V2;
469 break;
470 case MDP_Y_CBCR_H2V2_TILE:
471 is_tile = 1;
472 case MDP_Y_CB_CR_H2V2:
473 case MDP_Y_CBCR_H2V2:
474 dst_format = MDP_Y_CBCR_H2V2;
475 break;
476 default:
477 return -EINVAL;
478 }
479 if (info->dst.format != dst_format)
480 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481
482 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700483 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
484 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486 iowrite32(out_paddr +
487 ((info->dst_y * info->dst.width) + info->dst_x),
488 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700489 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 ((info->dst_y * info->dst.width)/2 + info->dst_x),
491 MSM_ROTATOR_OUTP1_ADDR);
492
493 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700494 if (in_chroma2_paddr) {
495 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530496 iowrite32(ALIGN(info->src.width, 16) |
497 ALIGN((info->src.width / 2), 16) << 16,
498 MSM_ROTATOR_SRC_YSTRIDE1);
499 iowrite32(ALIGN((info->src.width / 2), 16),
500 MSM_ROTATOR_SRC_YSTRIDE2);
501 } else {
502 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700503 (info->src.width / 2) << 16,
504 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530505 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700506 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530507 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700508 } else {
509 iowrite32(info->src.width |
510 info->src.width << 16,
511 MSM_ROTATOR_SRC_YSTRIDE1);
512 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700514 info->dst.width << 16,
515 MSM_ROTATOR_OUT_YSTRIDE1);
516
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700517 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700518 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
519 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
520 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
521 MSM_ROTATOR_OUT_PACK_PATTERN1);
522 } else {
523 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
524 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
525 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
526 MSM_ROTATOR_OUT_PACK_PATTERN1);
527 }
528 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
529 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
530 1 << 8, /* ROT_EN */
531 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700532
533 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700535 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700536 0 << 18 | /* unpack align */
537 1 << 17 | /* unpack tight */
538 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700539 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700540 0 << 8 | /* has alpha */
541 0 << 6 | /* alpha bits 3=8bits */
542 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
543 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
544 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
545 MSM_ROTATOR_SRC_FORMAT);
546 }
547 return 0;
548}
549
550static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
551 unsigned int in_paddr,
552 unsigned int out_paddr,
553 unsigned int use_imem,
554 int new_session)
555{
556 int bpp;
557
558 if (info->src.format != info->dst.format)
559 return -EINVAL;
560
561 bpp = get_bpp(info->src.format);
562 if (bpp < 0)
563 return -ENOTTY;
564
565 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
566 iowrite32(out_paddr +
567 ((info->dst_y * info->dst.width) + info->dst_x),
568 MSM_ROTATOR_OUTP0_ADDR);
569
570 if (new_session) {
571 iowrite32(info->src.width,
572 MSM_ROTATOR_SRC_YSTRIDE1);
573 iowrite32(info->dst.width,
574 MSM_ROTATOR_OUT_YSTRIDE1);
575 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
576 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
577 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
578 MSM_ROTATOR_OUT_PACK_PATTERN1);
579 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
580 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
581 1 << 8, /* ROT_EN */
582 MSM_ROTATOR_SUB_BLOCK_CFG);
583 iowrite32(0 << 29 | /* frame format 0 = linear */
584 (use_imem ? 0 : 1) << 22 | /* tile size */
585 0 << 19 | /* fetch planes 0=interleaved */
586 0 << 18 | /* unpack align */
587 1 << 17 | /* unpack tight */
588 3 << 13 | /* unpack count 0=1 component */
589 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
590 0 << 8 | /* has alpha */
591 0 << 6 | /* alpha bits 3=8bits */
592 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
593 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
594 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
595 MSM_ROTATOR_SRC_FORMAT);
596 }
597
598 return 0;
599}
600
601static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
602 unsigned int in_paddr,
603 unsigned int out_paddr,
604 unsigned int use_imem,
605 int new_session)
606{
607 int bpp, abits, rbits, gbits, bbits;
608
609 if (info->src.format != info->dst.format)
610 return -EINVAL;
611
612 bpp = get_bpp(info->src.format);
613 if (bpp < 0)
614 return -ENOTTY;
615
616 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
617 iowrite32(out_paddr +
618 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
619 MSM_ROTATOR_OUTP0_ADDR);
620
621 if (new_session) {
622 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
623 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
624 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
625 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
626 1 << 8, /* ROT_EN */
627 MSM_ROTATOR_SUB_BLOCK_CFG);
628 switch (info->src.format) {
629 case MDP_RGB_565:
630 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
631 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
632 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
633 MSM_ROTATOR_OUT_PACK_PATTERN1);
634 abits = 0;
635 rbits = COMPONENT_5BITS;
636 gbits = COMPONENT_6BITS;
637 bbits = COMPONENT_5BITS;
638 break;
639
640 case MDP_BGR_565:
641 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
642 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
643 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
644 MSM_ROTATOR_OUT_PACK_PATTERN1);
645 abits = 0;
646 rbits = COMPONENT_5BITS;
647 gbits = COMPONENT_6BITS;
648 bbits = COMPONENT_5BITS;
649 break;
650
651 case MDP_RGB_888:
652 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
653 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
654 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
655 MSM_ROTATOR_OUT_PACK_PATTERN1);
656 abits = 0;
657 rbits = COMPONENT_8BITS;
658 gbits = COMPONENT_8BITS;
659 bbits = COMPONENT_8BITS;
660 break;
661
662 case MDP_ARGB_8888:
663 case MDP_RGBA_8888:
664 case MDP_XRGB_8888:
665 case MDP_RGBX_8888:
666 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
667 CLR_B, 8),
668 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
669 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
670 CLR_B, 8),
671 MSM_ROTATOR_OUT_PACK_PATTERN1);
672 abits = COMPONENT_8BITS;
673 rbits = COMPONENT_8BITS;
674 gbits = COMPONENT_8BITS;
675 bbits = COMPONENT_8BITS;
676 break;
677
678 case MDP_BGRA_8888:
679 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
680 CLR_R, 8),
681 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
682 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
683 CLR_R, 8),
684 MSM_ROTATOR_OUT_PACK_PATTERN1);
685 abits = COMPONENT_8BITS;
686 rbits = COMPONENT_8BITS;
687 gbits = COMPONENT_8BITS;
688 bbits = COMPONENT_8BITS;
689 break;
690
691 default:
692 return -EINVAL;
693 }
694 iowrite32(0 << 29 | /* frame format 0 = linear */
695 (use_imem ? 0 : 1) << 22 | /* tile size */
696 0 << 19 | /* fetch planes 0=interleaved */
697 0 << 18 | /* unpack align */
698 1 << 17 | /* unpack tight */
699 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
700 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
701 (abits ? 1 : 0) << 8 | /* has alpha */
702 abits << 6 | /* alpha bits 3=8bits */
703 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
704 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
705 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
706 MSM_ROTATOR_SRC_FORMAT);
707 }
708
709 return 0;
710}
711
712static int get_img(int memory_id, unsigned long *start, unsigned long *len,
713 struct file **pp_file)
714{
715 int ret = 0;
716#ifdef CONFIG_FB
717 struct file *file;
718 int put_needed, fb_num;
719#endif
720#ifdef CONFIG_ANDROID_PMEM
721 unsigned long vstart;
722#endif
723
724#ifdef CONFIG_ANDROID_PMEM
725 if (!get_pmem_file(memory_id, start, &vstart, len, pp_file))
726 return 0;
727#endif
728#ifdef CONFIG_FB
729 file = fget_light(memory_id, &put_needed);
730 if (file == NULL)
731 return -1;
732
733 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
734 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
735 if (get_fb_phys_info(start, len, fb_num))
736 ret = -1;
737 else
738 *pp_file = file;
739 } else
740 ret = -1;
741 if (ret)
742 fput_light(file, put_needed);
743#endif
744 return ret;
745}
746
747static int msm_rotator_do_rotate(unsigned long arg)
748{
749 int rc = 0;
750 unsigned int status;
751 struct msm_rotator_data_info info;
752 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700753 unsigned long src_len, dst_len;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754 struct file *src_file = 0;
755 struct file *dst_file = 0;
756 int use_imem = 0;
757 int s;
758 struct file *src_chroma_file = 0;
759 struct file *dst_chroma_file = 0;
760 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700761 unsigned int in_chroma2_paddr = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700762 uint32_t format;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700763 struct msm_rotator_img_info *img_info;
764 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765
766 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
767 return -EFAULT;
768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700769 mutex_lock(&msm_rotator_dev->rotator_lock);
770 for (s = 0; s < MAX_SESSIONS; s++)
771 if ((msm_rotator_dev->img_info[s] != NULL) &&
772 (info.session_id ==
773 (unsigned int)msm_rotator_dev->img_info[s]
774 ))
775 break;
776
777 if (s == MAX_SESSIONS) {
778 dev_dbg(msm_rotator_dev->device,
779 "%s() : Attempt to use invalid session_id %d\n",
780 __func__, s);
781 rc = -EINVAL;
782 goto do_rotate_unlock_mutex;
783 }
784
785 if (msm_rotator_dev->img_info[s]->enable == 0) {
786 dev_dbg(msm_rotator_dev->device,
787 "%s() : Session_id %d not enabled \n",
788 __func__, s);
789 rc = -EINVAL;
790 goto do_rotate_unlock_mutex;
791 }
792
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700793 img_info = msm_rotator_dev->img_info[s];
794 if (msm_rotator_get_plane_sizes(img_info->src.format,
795 img_info->src.width,
796 img_info->src.height,
797 &src_planes)) {
798 pr_err("%s: invalid src format\n", __func__);
799 rc = -EINVAL;
800 goto do_rotate_unlock_mutex;
801 }
802 if (msm_rotator_get_plane_sizes(img_info->dst.format,
803 img_info->dst.width,
804 img_info->dst.height,
805 &dst_planes)) {
806 pr_err("%s: invalid dst format\n", __func__);
807 rc = -EINVAL;
808 goto do_rotate_unlock_mutex;
809 }
810
811 rc = get_img(info.src.memory_id, (unsigned long *)&in_paddr,
812 (unsigned long *)&src_len, &src_file);
813 if (rc) {
814 pr_err("%s: in get_img() failed id=0x%08x\n",
815 DRIVER_NAME, info.src.memory_id);
816 goto do_rotate_unlock_mutex;
817 }
818
819 rc = get_img(info.dst.memory_id, (unsigned long *)&out_paddr,
820 (unsigned long *)&dst_len, &dst_file);
821 if (rc) {
822 pr_err("%s: out get_img() failed id=0x%08x\n",
823 DRIVER_NAME, info.dst.memory_id);
824 goto do_rotate_unlock_mutex;
825 }
826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 format = msm_rotator_dev->img_info[s]->src.format;
828 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700829 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
830 (src_planes.num_planes == 2)) {
831 if (checkoffset(info.src.offset,
832 src_planes.plane_size[0],
833 src_len)) {
834 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
835 __func__, src_len, info.src.offset);
836 rc = -ERANGE;
837 goto do_rotate_unlock_mutex;
838 }
839 if (checkoffset(info.dst.offset,
840 dst_planes.plane_size[0],
841 dst_len)) {
842 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
843 __func__, dst_len, info.dst.offset);
844 rc = -ERANGE;
845 goto do_rotate_unlock_mutex;
846 }
847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 rc = get_img(info.src_chroma.memory_id,
849 (unsigned long *)&in_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700850 (unsigned long *)&src_len, &src_chroma_file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700852 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853 DRIVER_NAME, info.src_chroma.memory_id);
854 goto do_rotate_unlock_mutex;
855 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856
857 rc = get_img(info.dst_chroma.memory_id,
858 (unsigned long *)&out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700859 (unsigned long *)&dst_len, &dst_chroma_file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700861 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700863 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700865
866 if (checkoffset(info.src_chroma.offset,
867 src_planes.plane_size[1],
868 src_len)) {
869 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
870 __func__, src_len, info.src_chroma.offset);
871 rc = -ERANGE;
872 goto do_rotate_unlock_mutex;
873 }
874
875 if (checkoffset(info.dst_chroma.offset,
876 src_planes.plane_size[1],
877 dst_len)) {
878 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
879 __func__, dst_len, info.dst_chroma.offset);
880 rc = -ERANGE;
881 goto do_rotate_unlock_mutex;
882 }
883
884 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700886 } else {
887 if (checkoffset(info.src.offset,
888 src_planes.total_size,
889 src_len)) {
890 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
891 __func__, src_len, info.src.offset);
892 rc = -ERANGE;
893 goto do_rotate_unlock_mutex;
894 }
895 if (checkoffset(info.dst.offset,
896 dst_planes.total_size,
897 dst_len)) {
898 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
899 __func__, dst_len, info.dst.offset);
900 rc = -ERANGE;
901 goto do_rotate_unlock_mutex;
902 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903 }
904
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700905 in_paddr += info.src.offset;
906 out_paddr += info.dst.offset;
907
908 if (!in_chroma_paddr && src_planes.num_planes >= 2)
909 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
910 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
911 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
912 if (src_planes.num_planes >= 3)
913 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
916 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
917 enable_rot_clks();
918 msm_rotator_dev->rot_clk_state = CLK_EN;
919 }
920 enable_irq(msm_rotator_dev->irq);
921
922#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
923 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
924#else
925 use_imem = 0;
926#endif
927 /*
928 * workaround for a hardware bug. rotator hardware hangs when we
929 * use write burst beat size 16 on 128X128 tile fetch mode. As a
930 * temporary fix use 0x42 for BURST_SIZE when imem used.
931 */
932 if (use_imem)
933 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
934
935 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
936 << 16) |
937 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
938 MSM_ROTATOR_SRC_SIZE);
939 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
940 << 16) |
941 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
942 MSM_ROTATOR_SRC_XY);
943 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
944 << 16) |
945 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
946 MSM_ROTATOR_SRC_IMAGE_SIZE);
947
948 switch (format) {
949 case MDP_RGB_565:
950 case MDP_BGR_565:
951 case MDP_RGB_888:
952 case MDP_ARGB_8888:
953 case MDP_RGBA_8888:
954 case MDP_XRGB_8888:
955 case MDP_BGRA_8888:
956 case MDP_RGBX_8888:
957 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
958 in_paddr, out_paddr,
959 use_imem,
960 msm_rotator_dev->last_session_idx
961 != s);
962 break;
963 case MDP_Y_CBCR_H2V2:
964 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700965 case MDP_Y_CB_CR_H2V2:
966 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530967 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968 case MDP_Y_CRCB_H2V2_TILE:
969 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700970 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
971 in_paddr, out_paddr, use_imem,
972 msm_rotator_dev->last_session_idx
973 != s,
974 in_chroma_paddr,
975 out_chroma_paddr,
976 in_chroma2_paddr);
977 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978 case MDP_Y_CBCR_H2V1:
979 case MDP_Y_CRCB_H2V1:
980 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
981 in_paddr, out_paddr, use_imem,
982 msm_rotator_dev->last_session_idx
983 != s,
984 in_chroma_paddr,
985 out_chroma_paddr);
986 break;
987 case MDP_YCRYCB_H2V1:
988 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
989 in_paddr, out_paddr, use_imem,
990 msm_rotator_dev->last_session_idx != s);
991 break;
992 default:
993 rc = -EINVAL;
994 goto do_rotate_exit;
995 }
996
997 if (rc != 0) {
998 msm_rotator_dev->last_session_idx = INVALID_SESSION;
999 goto do_rotate_exit;
1000 }
1001
1002 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1003
1004 msm_rotator_dev->processing = 1;
1005 iowrite32(0x1, MSM_ROTATOR_START);
1006
1007 wait_event(msm_rotator_dev->wq,
1008 (msm_rotator_dev->processing == 0));
1009 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
1010 if ((status & 0x03) != 0x01)
1011 rc = -EFAULT;
1012 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1013 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1014
1015do_rotate_exit:
1016 disable_irq(msm_rotator_dev->irq);
1017#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1018 msm_rotator_imem_free(ROTATOR_REQUEST);
1019#endif
1020 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001021do_rotate_unlock_mutex:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 if (dst_chroma_file)
1023 put_pmem_file(dst_chroma_file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 if (src_chroma_file)
1025 put_pmem_file(src_chroma_file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 if (dst_file)
1027 put_pmem_file(dst_file);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 if (src_file)
1029 put_pmem_file(src_file);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001030 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1032 __func__, rc);
1033 return rc;
1034}
1035
1036static int msm_rotator_start(unsigned long arg, int pid)
1037{
1038 struct msm_rotator_img_info info;
1039 int rc = 0;
1040 int s;
1041 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001042 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001043
1044 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1045 return -EFAULT;
1046
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001047 if (info.rotations & MDP_ROT_90) {
1048 dst_w = info.src_rect.h;
1049 dst_h = info.src_rect.w;
1050 } else {
1051 dst_w = info.src_rect.w;
1052 dst_h = info.src_rect.h;
1053 }
1054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1056 (info.src.height > MSM_ROTATOR_MAX_H) ||
1057 (info.src.width > MSM_ROTATOR_MAX_W) ||
1058 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1059 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001060 checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
1061 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1062 checkoffset(info.dst_x, dst_w, info.dst.width) ||
1063 checkoffset(info.dst_y, dst_h, info.dst.height))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064 return -EINVAL;
1065
1066 switch (info.src.format) {
1067 case MDP_RGB_565:
1068 case MDP_BGR_565:
1069 case MDP_RGB_888:
1070 case MDP_ARGB_8888:
1071 case MDP_RGBA_8888:
1072 case MDP_XRGB_8888:
1073 case MDP_RGBX_8888:
1074 case MDP_BGRA_8888:
1075 case MDP_Y_CBCR_H2V2:
1076 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001077 case MDP_Y_CB_CR_H2V2:
1078 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301079 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001080 case MDP_Y_CBCR_H2V1:
1081 case MDP_Y_CRCB_H2V1:
1082 case MDP_YCRYCB_H2V1:
1083 case MDP_Y_CRCB_H2V2_TILE:
1084 case MDP_Y_CBCR_H2V2_TILE:
1085 break;
1086 default:
1087 return -EINVAL;
1088 }
1089
1090 switch (info.dst.format) {
1091 case MDP_RGB_565:
1092 case MDP_BGR_565:
1093 case MDP_RGB_888:
1094 case MDP_ARGB_8888:
1095 case MDP_RGBA_8888:
1096 case MDP_XRGB_8888:
1097 case MDP_RGBX_8888:
1098 case MDP_BGRA_8888:
1099 case MDP_Y_CBCR_H2V2:
1100 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001101 case MDP_Y_CB_CR_H2V2:
1102 case MDP_Y_CR_CB_H2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 case MDP_Y_CBCR_H2V1:
1104 case MDP_Y_CRCB_H2V1:
1105 case MDP_YCRYCB_H2V1:
1106 break;
1107 default:
1108 return -EINVAL;
1109 }
1110
1111 mutex_lock(&msm_rotator_dev->rotator_lock);
1112 for (s = 0; s < MAX_SESSIONS; s++) {
1113 if ((msm_rotator_dev->img_info[s] != NULL) &&
1114 (info.session_id ==
1115 (unsigned int)msm_rotator_dev->img_info[s]
1116 )) {
1117 *(msm_rotator_dev->img_info[s]) = info;
1118 msm_rotator_dev->pid_list[s] = pid;
1119
1120 if (msm_rotator_dev->last_session_idx == s)
1121 msm_rotator_dev->last_session_idx =
1122 INVALID_SESSION;
1123 break;
1124 }
1125
1126 if ((msm_rotator_dev->img_info[s] == NULL) &&
1127 (first_free_index ==
1128 INVALID_SESSION))
1129 first_free_index = s;
1130 }
1131
1132 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1133 /* allocate a session id */
1134 msm_rotator_dev->img_info[first_free_index] =
1135 kzalloc(sizeof(struct msm_rotator_img_info),
1136 GFP_KERNEL);
1137 if (!msm_rotator_dev->img_info[first_free_index]) {
1138 printk(KERN_ERR "%s : unable to alloc mem\n",
1139 __func__);
1140 rc = -ENOMEM;
1141 goto rotator_start_exit;
1142 }
1143 info.session_id = (unsigned int)
1144 msm_rotator_dev->img_info[first_free_index];
1145 *(msm_rotator_dev->img_info[first_free_index]) = info;
1146 msm_rotator_dev->pid_list[first_free_index] = pid;
1147
1148 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
1149 rc = -EFAULT;
1150 } else if (s == MAX_SESSIONS) {
1151 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1152 __func__);
1153 rc = -EBUSY;
1154 }
1155
1156rotator_start_exit:
1157 mutex_unlock(&msm_rotator_dev->rotator_lock);
1158
1159 return rc;
1160}
1161
1162static int msm_rotator_finish(unsigned long arg)
1163{
1164 int rc = 0;
1165 int s;
1166 unsigned int session_id;
1167
1168 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1169 return -EFAULT;
1170
1171 mutex_lock(&msm_rotator_dev->rotator_lock);
1172 for (s = 0; s < MAX_SESSIONS; s++) {
1173 if ((msm_rotator_dev->img_info[s] != NULL) &&
1174 (session_id ==
1175 (unsigned int)msm_rotator_dev->img_info[s])) {
1176 if (msm_rotator_dev->last_session_idx == s)
1177 msm_rotator_dev->last_session_idx =
1178 INVALID_SESSION;
1179 kfree(msm_rotator_dev->img_info[s]);
1180 msm_rotator_dev->img_info[s] = NULL;
1181 msm_rotator_dev->pid_list[s] = 0;
1182 break;
1183 }
1184 }
1185
1186 if (s == MAX_SESSIONS)
1187 rc = -EINVAL;
1188 mutex_unlock(&msm_rotator_dev->rotator_lock);
1189 return rc;
1190}
1191
1192static int
1193msm_rotator_open(struct inode *inode, struct file *filp)
1194{
1195 int *id;
1196 int i;
1197
1198 if (filp->private_data)
1199 return -EBUSY;
1200
1201 mutex_lock(&msm_rotator_dev->rotator_lock);
1202 id = &msm_rotator_dev->pid_list[0];
1203 for (i = 0; i < MAX_SESSIONS; i++, id++) {
1204 if (*id == 0)
1205 break;
1206 }
1207 mutex_unlock(&msm_rotator_dev->rotator_lock);
1208
1209 if (i == MAX_SESSIONS)
1210 return -EBUSY;
1211
kuogee hsieh7a46d592011-09-09 10:27:23 -07001212 filp->private_data = (void *)current->pid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213
1214 return 0;
1215}
1216
1217static int
1218msm_rotator_close(struct inode *inode, struct file *filp)
1219{
1220 int s;
1221 int pid;
1222
1223 pid = (int)filp->private_data;
1224 mutex_lock(&msm_rotator_dev->rotator_lock);
1225 for (s = 0; s < MAX_SESSIONS; s++) {
1226 if (msm_rotator_dev->img_info[s] != NULL &&
1227 msm_rotator_dev->pid_list[s] == pid) {
1228 kfree(msm_rotator_dev->img_info[s]);
1229 msm_rotator_dev->img_info[s] = NULL;
1230 if (msm_rotator_dev->last_session_idx == s)
1231 msm_rotator_dev->last_session_idx =
1232 INVALID_SESSION;
1233 }
1234 }
1235 mutex_unlock(&msm_rotator_dev->rotator_lock);
1236
1237 return 0;
1238}
1239
1240static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1241 unsigned long arg)
1242{
1243 int pid;
1244
1245 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1246 return -ENOTTY;
1247
1248 pid = (int)file->private_data;
1249
1250 switch (cmd) {
1251 case MSM_ROTATOR_IOCTL_START:
1252 return msm_rotator_start(arg, pid);
1253 case MSM_ROTATOR_IOCTL_ROTATE:
1254 return msm_rotator_do_rotate(arg);
1255 case MSM_ROTATOR_IOCTL_FINISH:
1256 return msm_rotator_finish(arg);
1257
1258 default:
1259 dev_dbg(msm_rotator_dev->device,
1260 "unexpected IOCTL %d\n", cmd);
1261 return -ENOTTY;
1262 }
1263}
1264
1265static const struct file_operations msm_rotator_fops = {
1266 .owner = THIS_MODULE,
1267 .open = msm_rotator_open,
1268 .release = msm_rotator_close,
1269 .unlocked_ioctl = msm_rotator_ioctl,
1270};
1271
1272static int __devinit msm_rotator_probe(struct platform_device *pdev)
1273{
1274 int rc = 0;
1275 struct resource *res;
1276 struct msm_rotator_platform_data *pdata = NULL;
1277 int i, number_of_clks;
1278 uint32_t ver;
1279
1280 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1281 if (!msm_rotator_dev) {
1282 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1283 __func__);
1284 return -ENOMEM;
1285 }
1286 for (i = 0; i < MAX_SESSIONS; i++)
1287 msm_rotator_dev->img_info[i] = NULL;
1288 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1289
1290 pdata = pdev->dev.platform_data;
1291 number_of_clks = pdata->number_of_clocks;
1292
1293 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1294 mutex_init(&msm_rotator_dev->imem_lock);
1295 msm_rotator_dev->imem_clk_state = CLK_DIS;
1296 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1297 msm_rotator_imem_clk_work_f);
1298 msm_rotator_dev->imem_clk = NULL;
1299 msm_rotator_dev->pdev = pdev;
1300
1301 msm_rotator_dev->core_clk = NULL;
1302 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303
1304 for (i = 0; i < number_of_clks; i++) {
1305 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1306 msm_rotator_dev->imem_clk =
1307 clk_get(&msm_rotator_dev->pdev->dev,
1308 pdata->rotator_clks[i].clk_name);
1309 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1310 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1311 msm_rotator_dev->imem_clk = NULL;
1312 printk(KERN_ERR "%s: cannot get imem_clk "
1313 "rc=%d\n", DRIVER_NAME, rc);
1314 goto error_imem_clk;
1315 }
1316 if (pdata->rotator_clks[i].clk_rate)
1317 clk_set_min_rate(msm_rotator_dev->imem_clk,
1318 pdata->rotator_clks[i].clk_rate);
1319 }
1320 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1321 msm_rotator_dev->pclk =
1322 clk_get(&msm_rotator_dev->pdev->dev,
1323 pdata->rotator_clks[i].clk_name);
1324 if (IS_ERR(msm_rotator_dev->pclk)) {
1325 rc = PTR_ERR(msm_rotator_dev->pclk);
1326 msm_rotator_dev->pclk = NULL;
1327 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1328 DRIVER_NAME, rc);
1329 goto error_pclk;
1330 }
1331
1332 if (pdata->rotator_clks[i].clk_rate)
1333 clk_set_min_rate(msm_rotator_dev->pclk,
1334 pdata->rotator_clks[i].clk_rate);
1335 }
1336
1337 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1338 msm_rotator_dev->core_clk =
1339 clk_get(&msm_rotator_dev->pdev->dev,
1340 pdata->rotator_clks[i].clk_name);
1341 if (IS_ERR(msm_rotator_dev->core_clk)) {
1342 rc = PTR_ERR(msm_rotator_dev->core_clk);
1343 msm_rotator_dev->core_clk = NULL;
1344 printk(KERN_ERR "%s: cannot get core clk "
1345 "rc=%d\n", DRIVER_NAME, rc);
1346 goto error_core_clk;
1347 }
1348
1349 if (pdata->rotator_clks[i].clk_rate)
1350 clk_set_min_rate(msm_rotator_dev->core_clk,
1351 pdata->rotator_clks[i].clk_rate);
1352 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353 }
1354
1355 msm_rotator_dev->regulator = regulator_get(NULL, pdata->regulator_name);
1356 if (IS_ERR(msm_rotator_dev->regulator))
1357 msm_rotator_dev->regulator = NULL;
1358
1359 msm_rotator_dev->rot_clk_state = CLK_DIS;
1360 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1361 msm_rotator_rot_clk_work_f);
1362
1363 mutex_init(&msm_rotator_dev->rotator_lock);
1364
1365 platform_set_drvdata(pdev, msm_rotator_dev);
1366
1367
1368 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1369 if (!res) {
1370 printk(KERN_ALERT
1371 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1372 rc = -ENODEV;
1373 goto error_get_resource;
1374 }
1375 msm_rotator_dev->io_base = ioremap(res->start,
1376 resource_size(res));
1377
1378#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1379 if (msm_rotator_dev->imem_clk)
1380 clk_enable(msm_rotator_dev->imem_clk);
1381#endif
1382 enable_rot_clks();
1383 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1384 disable_rot_clks();
1385
1386#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1387 if (msm_rotator_dev->imem_clk)
1388 clk_disable(msm_rotator_dev->imem_clk);
1389#endif
1390 if (ver != pdata->hardware_version_number) {
Nagamalleswararao Ganjibcdea002011-09-13 15:43:47 -07001391 pr_info("%s: invalid HW version\n", DRIVER_NAME);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 }
1393 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1394 if (msm_rotator_dev->irq < 0) {
1395 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1396 DRIVER_NAME);
1397 rc = -ENODEV;
1398 goto error_get_irq;
1399 }
1400 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1401 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1402 if (rc) {
1403 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1404 goto error_get_irq;
1405 }
1406 /* we enable the IRQ when we need it in the ioctl */
1407 disable_irq(msm_rotator_dev->irq);
1408
1409 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1410 if (rc < 0) {
1411 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1412 __func__, rc);
1413 goto error_get_irq;
1414 }
1415
1416 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1417 if (IS_ERR(msm_rotator_dev->class)) {
1418 rc = PTR_ERR(msm_rotator_dev->class);
1419 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1420 DRIVER_NAME, rc);
1421 goto error_class_create;
1422 }
1423
1424 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1425 msm_rotator_dev->dev_num, NULL,
1426 DRIVER_NAME);
1427 if (IS_ERR(msm_rotator_dev->device)) {
1428 rc = PTR_ERR(msm_rotator_dev->device);
1429 printk(KERN_ERR "%s: device_create failed %d\n",
1430 DRIVER_NAME, rc);
1431 goto error_class_device_create;
1432 }
1433
1434 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1435 rc = cdev_add(&msm_rotator_dev->cdev,
1436 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1437 1);
1438 if (rc < 0) {
1439 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1440 goto error_cdev_add;
1441 }
1442
1443 init_waitqueue_head(&msm_rotator_dev->wq);
1444
1445 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1446 return rc;
1447
1448error_cdev_add:
1449 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1450error_class_device_create:
1451 class_destroy(msm_rotator_dev->class);
1452error_class_create:
1453 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1454error_get_irq:
1455 iounmap(msm_rotator_dev->io_base);
1456error_get_resource:
1457 mutex_destroy(&msm_rotator_dev->rotator_lock);
1458 if (msm_rotator_dev->regulator)
1459 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 clk_put(msm_rotator_dev->core_clk);
1461error_core_clk:
1462 clk_put(msm_rotator_dev->pclk);
1463error_pclk:
1464 if (msm_rotator_dev->imem_clk)
1465 clk_put(msm_rotator_dev->imem_clk);
1466error_imem_clk:
1467 mutex_destroy(&msm_rotator_dev->imem_lock);
1468 kfree(msm_rotator_dev);
1469 return rc;
1470}
1471
1472static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1473{
1474 int i;
1475
1476 free_irq(msm_rotator_dev->irq, NULL);
1477 mutex_destroy(&msm_rotator_dev->rotator_lock);
1478 cdev_del(&msm_rotator_dev->cdev);
1479 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1480 class_destroy(msm_rotator_dev->class);
1481 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1482 iounmap(msm_rotator_dev->io_base);
1483 if (msm_rotator_dev->imem_clk) {
1484 if (msm_rotator_dev->imem_clk_state == CLK_EN)
1485 clk_disable(msm_rotator_dev->imem_clk);
1486 clk_put(msm_rotator_dev->imem_clk);
1487 msm_rotator_dev->imem_clk = NULL;
1488 }
1489 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1490 disable_rot_clks();
1491 clk_put(msm_rotator_dev->core_clk);
1492 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 if (msm_rotator_dev->regulator)
1494 regulator_put(msm_rotator_dev->regulator);
1495 msm_rotator_dev->core_clk = NULL;
1496 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 mutex_destroy(&msm_rotator_dev->imem_lock);
1498 for (i = 0; i < MAX_SESSIONS; i++)
1499 if (msm_rotator_dev->img_info[i] != NULL)
1500 kfree(msm_rotator_dev->img_info[i]);
1501 kfree(msm_rotator_dev);
1502 return 0;
1503}
1504
1505#ifdef CONFIG_PM
1506static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1507{
1508 mutex_lock(&msm_rotator_dev->imem_lock);
1509 if (msm_rotator_dev->imem_clk_state == CLK_EN
1510 && msm_rotator_dev->imem_clk) {
1511 clk_disable(msm_rotator_dev->imem_clk);
1512 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1513 }
1514 mutex_unlock(&msm_rotator_dev->imem_lock);
1515 mutex_lock(&msm_rotator_dev->rotator_lock);
1516 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1517 disable_rot_clks();
1518 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1519 }
1520 mutex_unlock(&msm_rotator_dev->rotator_lock);
1521 return 0;
1522}
1523
1524static int msm_rotator_resume(struct platform_device *dev)
1525{
1526 mutex_lock(&msm_rotator_dev->imem_lock);
1527 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1528 && msm_rotator_dev->imem_clk) {
1529 clk_enable(msm_rotator_dev->imem_clk);
1530 msm_rotator_dev->imem_clk_state = CLK_EN;
1531 }
1532 mutex_unlock(&msm_rotator_dev->imem_lock);
1533 mutex_lock(&msm_rotator_dev->rotator_lock);
1534 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1535 enable_rot_clks();
1536 msm_rotator_dev->rot_clk_state = CLK_EN;
1537 }
1538 mutex_unlock(&msm_rotator_dev->rotator_lock);
1539 return 0;
1540}
1541#endif
1542
1543static struct platform_driver msm_rotator_platform_driver = {
1544 .probe = msm_rotator_probe,
1545 .remove = __devexit_p(msm_rotator_remove),
1546#ifdef CONFIG_PM
1547 .suspend = msm_rotator_suspend,
1548 .resume = msm_rotator_resume,
1549#endif
1550 .driver = {
1551 .owner = THIS_MODULE,
1552 .name = DRIVER_NAME
1553 }
1554};
1555
1556static int __init msm_rotator_init(void)
1557{
1558 return platform_driver_register(&msm_rotator_platform_driver);
1559}
1560
1561static void __exit msm_rotator_exit(void)
1562{
1563 return platform_driver_unregister(&msm_rotator_platform_driver);
1564}
1565
1566module_init(msm_rotator_init);
1567module_exit(msm_rotator_exit);
1568
1569MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1570MODULE_VERSION("1.0");
1571MODULE_LICENSE("GPL v2");