blob: 81a9fa728939b6a8a1cf826bd39e260e11f8ba9a [file] [log] [blame]
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -08001/* Copyright (c) 2009-2012, 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>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/android_pmem.h>
23#include <linux/msm_rotator.h>
24#include <linux/io.h>
25#include <mach/msm_rotator_imem.h>
26#include <linux/ktime.h>
27#include <linux/workqueue.h>
28#include <linux/file.h>
29#include <linux/major.h>
30#include <linux/regulator/consumer.h>
Naseer Ahmed18018602011-10-25 13:32:58 -070031#include <linux/ion.h>
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -080032#ifdef CONFIG_MSM_BUS_SCALING
33#include <mach/msm_bus.h>
34#include <mach/msm_bus_board.h>
35#endif
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -070036#include <mach/msm_subsystem_map.h>
37#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#define DRIVER_NAME "msm_rotator"
40
41#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
42#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
43#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
44#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
45#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
46#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
47#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
48#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
49#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
50#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070051#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
53#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
54#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
55#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
56#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
57#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
58#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
59#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070060#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
62#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
63#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
64#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
65
66#define MSM_ROTATOR_MAX_ROT 0x07
67#define MSM_ROTATOR_MAX_H 0x1fff
68#define MSM_ROTATOR_MAX_W 0x1fff
69
70/* from lsb to msb */
71#define GET_PACK_PATTERN(a, x, y, z, bit) \
72 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
73#define CLR_G 0x0
74#define CLR_B 0x1
75#define CLR_R 0x2
76#define CLR_ALPHA 0x3
77
78#define CLR_Y CLR_G
79#define CLR_CB CLR_B
80#define CLR_CR CLR_R
81
82#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
83 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
84 (((r) & MDP_FLIP_UD) ? 4 : 0))
85
86#define IMEM_NO_OWNER -1;
87
88#define MAX_SESSIONS 16
89#define INVALID_SESSION -1
90#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070091#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092
Mayank Chopra012a8e72012-04-11 10:41:13 +053093#define ROTATOR_REVISION_V0 0
94#define ROTATOR_REVISION_V1 1
95#define ROTATOR_REVISION_V2 2
96#define ROTATOR_REVISION_NONE 0xffffffff
97
98uint32_t rotator_hw_revision;
99
100/*
101 * rotator_hw_revision:
102 * 0 == 7x30
103 * 1 == 8x60
104 * 2 == 8960
105 *
106 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107struct tile_parm {
108 unsigned int width; /* tile's width */
109 unsigned int height; /* tile's height */
110 unsigned int row_tile_w; /* tiles per row's width */
111 unsigned int row_tile_h; /* tiles per row's height */
112};
113
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700114struct msm_rotator_mem_planes {
115 unsigned int num_planes;
116 unsigned int plane_size[4];
117 unsigned int total_size;
118};
119
120#define checkoffset(offset, size, max_size) \
121 ((size) > (max_size) || (offset) > ((max_size) - (size)))
122
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700123struct msm_rotator_fd_info {
124 int pid;
125 int ref_cnt;
126 struct list_head list;
127};
128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129struct msm_rotator_dev {
130 void __iomem *io_base;
131 int irq;
132 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
133 struct clk *core_clk;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700134 struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
135 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 int rot_clk_state;
138 struct regulator *regulator;
139 struct delayed_work rot_clk_work;
140 struct clk *imem_clk;
141 int imem_clk_state;
142 struct delayed_work imem_clk_work;
143 struct platform_device *pdev;
144 struct cdev cdev;
145 struct device *device;
146 struct class *class;
147 dev_t dev_num;
148 int processing;
149 int last_session_idx;
150 struct mutex rotator_lock;
151 struct mutex imem_lock;
152 int imem_owner;
153 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700154 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800155 #ifdef CONFIG_MSM_BUS_SCALING
156 uint32_t bus_client_handle;
157 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158};
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160#define COMPONENT_5BITS 1
161#define COMPONENT_6BITS 2
162#define COMPONENT_8BITS 3
163
164static struct msm_rotator_dev *msm_rotator_dev;
165
166enum {
167 CLK_EN,
168 CLK_DIS,
169 CLK_SUSPEND,
170};
171
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700172int msm_rotator_iommu_map_buf(int mem_id, unsigned char src,
173 unsigned long *start, unsigned long *len,
174 struct ion_handle **pihdl)
175{
176 if (!msm_rotator_dev->client)
177 return -EINVAL;
178
179 *pihdl = ion_import_fd(msm_rotator_dev->client, mem_id);
180 if (IS_ERR_OR_NULL(*pihdl)) {
181 pr_err("ion_import_fd() failed\n");
182 return PTR_ERR(*pihdl);
183 }
184 pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *pihdl,
185 ion_share(msm_rotator_dev->client, *pihdl));
186
187 if (ion_map_iommu(msm_rotator_dev->client,
188 *pihdl, ROTATOR_DOMAIN, GEN_POOL,
189 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
190 pr_err("ion_map_iommu() failed\n");
191 return -EINVAL;
192 }
193
194 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
195 __func__, mem_id, *start, *len);
196 return 0;
197}
198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199int msm_rotator_imem_allocate(int requestor)
200{
201 int rc = 0;
202
203#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
204 switch (requestor) {
205 case ROTATOR_REQUEST:
206 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
207 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
208 rc = 1;
209 } else
210 rc = 0;
211 break;
212 case JPEG_REQUEST:
213 mutex_lock(&msm_rotator_dev->imem_lock);
214 msm_rotator_dev->imem_owner = JPEG_REQUEST;
215 rc = 1;
216 break;
217 default:
218 rc = 0;
219 }
220#else
221 if (requestor == JPEG_REQUEST)
222 rc = 1;
223#endif
224 if (rc == 1) {
225 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
226 if (msm_rotator_dev->imem_clk_state != CLK_EN
227 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700228 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 msm_rotator_dev->imem_clk_state = CLK_EN;
230 }
231 }
232
233 return rc;
234}
235EXPORT_SYMBOL(msm_rotator_imem_allocate);
236
237void msm_rotator_imem_free(int requestor)
238{
239#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
240 if (msm_rotator_dev->imem_owner == requestor) {
241 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
242 mutex_unlock(&msm_rotator_dev->imem_lock);
243 }
244#else
245 if (requestor == JPEG_REQUEST)
246 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
247#endif
248}
249EXPORT_SYMBOL(msm_rotator_imem_free);
250
251static void msm_rotator_imem_clk_work_f(struct work_struct *work)
252{
253#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
254 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
255 if (msm_rotator_dev->imem_clk_state == CLK_EN
256 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700257 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 msm_rotator_dev->imem_clk_state = CLK_DIS;
259 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
260 msm_rotator_dev->imem_clk_state = CLK_DIS;
261 mutex_unlock(&msm_rotator_dev->imem_lock);
262 }
263#endif
264}
265
266/* enable clocks needed by rotator block */
267static void enable_rot_clks(void)
268{
269 if (msm_rotator_dev->regulator)
270 regulator_enable(msm_rotator_dev->regulator);
271 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700272 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700274 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275}
276
277/* disable clocks needed by rotator block */
278static void disable_rot_clks(void)
279{
280 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700281 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700283 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 if (msm_rotator_dev->regulator)
285 regulator_disable(msm_rotator_dev->regulator);
286}
287
288static void msm_rotator_rot_clk_work_f(struct work_struct *work)
289{
290 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
291 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
292 disable_rot_clks();
293 msm_rotator_dev->rot_clk_state = CLK_DIS;
294 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
295 msm_rotator_dev->rot_clk_state = CLK_DIS;
296 mutex_unlock(&msm_rotator_dev->rotator_lock);
297 }
298}
299
300static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
301{
302 if (msm_rotator_dev->processing) {
303 msm_rotator_dev->processing = 0;
304 wake_up(&msm_rotator_dev->wq);
305 } else
306 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
307
308 return IRQ_HANDLED;
309}
310
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700311static unsigned int tile_size(unsigned int src_width,
312 unsigned int src_height,
313 const struct tile_parm *tp)
314{
315 unsigned int tile_w, tile_h;
316 unsigned int row_num_w, row_num_h;
317 tile_w = tp->width * tp->row_tile_w;
318 tile_h = tp->height * tp->row_tile_h;
319 row_num_w = (src_width + tile_w - 1) / tile_w;
320 row_num_h = (src_height + tile_h - 1) / tile_h;
321 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
322}
323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324static int get_bpp(int format)
325{
326 switch (format) {
327 case MDP_RGB_565:
328 case MDP_BGR_565:
329 return 2;
330
331 case MDP_XRGB_8888:
332 case MDP_ARGB_8888:
333 case MDP_RGBA_8888:
334 case MDP_BGRA_8888:
335 case MDP_RGBX_8888:
336 return 4;
337
338 case MDP_Y_CBCR_H2V2:
339 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700340 case MDP_Y_CB_CR_H2V2:
341 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530342 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 case MDP_Y_CRCB_H2V2_TILE:
344 case MDP_Y_CBCR_H2V2_TILE:
345 return 1;
346
347 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700348 case MDP_YCBCR_H1V1:
349 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 return 3;
351
352 case MDP_YCRYCB_H2V1:
353 return 2;/* YCrYCb interleave */
354
355 case MDP_Y_CRCB_H2V1:
356 case MDP_Y_CBCR_H2V1:
357 return 1;
358
359 default:
360 return -1;
361 }
362
363}
364
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700365static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
366 struct msm_rotator_mem_planes *p)
367{
368 /*
369 * each row of samsung tile consists of two tiles in height
370 * and two tiles in width which means width should align to
371 * 64 x 2 bytes and height should align to 32 x 2 bytes.
372 * video decoder generate two tiles in width and one tile
373 * in height which ends up height align to 32 X 1 bytes.
374 */
375 const struct tile_parm tile = {64, 32, 2, 1};
376 int i;
377
378 if (p == NULL)
379 return -EINVAL;
380
381 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
382 return -ERANGE;
383
384 memset(p, 0, sizeof(*p));
385
386 switch (format) {
387 case MDP_XRGB_8888:
388 case MDP_ARGB_8888:
389 case MDP_RGBA_8888:
390 case MDP_BGRA_8888:
391 case MDP_RGBX_8888:
392 case MDP_RGB_888:
393 case MDP_RGB_565:
394 case MDP_BGR_565:
395 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700396 case MDP_YCBCR_H1V1:
397 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700398 p->num_planes = 1;
399 p->plane_size[0] = w * h * get_bpp(format);
400 break;
401 case MDP_Y_CRCB_H2V1:
402 case MDP_Y_CBCR_H2V1:
403 p->num_planes = 2;
404 p->plane_size[0] = w * h;
405 p->plane_size[1] = w * h;
406 break;
407 case MDP_Y_CBCR_H2V2:
408 case MDP_Y_CRCB_H2V2:
409 p->num_planes = 2;
410 p->plane_size[0] = w * h;
411 p->plane_size[1] = w * h / 2;
412 break;
413 case MDP_Y_CRCB_H2V2_TILE:
414 case MDP_Y_CBCR_H2V2_TILE:
415 p->num_planes = 2;
416 p->plane_size[0] = tile_size(w, h, &tile);
417 p->plane_size[1] = tile_size(w, h/2, &tile);
418 break;
419 case MDP_Y_CB_CR_H2V2:
420 case MDP_Y_CR_CB_H2V2:
421 p->num_planes = 3;
422 p->plane_size[0] = w * h;
423 p->plane_size[1] = (w / 2) * (h / 2);
424 p->plane_size[2] = (w / 2) * (h / 2);
425 break;
426 case MDP_Y_CR_CB_GH2V2:
427 p->num_planes = 3;
428 p->plane_size[0] = ALIGN(w, 16) * h;
429 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
430 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
431 break;
432 default:
433 return -EINVAL;
434 }
435
436 for (i = 0; i < p->num_planes; i++)
437 p->total_size += p->plane_size[i];
438
439 return 0;
440}
441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
443 unsigned int in_paddr,
444 unsigned int out_paddr,
445 unsigned int use_imem,
446 int new_session,
447 unsigned int in_chroma_paddr,
448 unsigned int out_chroma_paddr)
449{
450 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451
452 if (info->src.format != info->dst.format)
453 return -EINVAL;
454
455 bpp = get_bpp(info->src.format);
456 if (bpp < 0)
457 return -ENOTTY;
458
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700460 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461 iowrite32(out_paddr +
462 ((info->dst_y * info->dst.width) + info->dst_x),
463 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700464 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465 ((info->dst_y * info->dst.width) + info->dst_x),
466 MSM_ROTATOR_OUTP1_ADDR);
467
468 if (new_session) {
469 iowrite32(info->src.width |
470 info->src.width << 16,
471 MSM_ROTATOR_SRC_YSTRIDE1);
472 if (info->rotations & MDP_ROT_90)
473 iowrite32(info->dst.width |
474 info->dst.width*2 << 16,
475 MSM_ROTATOR_OUT_YSTRIDE1);
476 else
477 iowrite32(info->dst.width |
478 info->dst.width << 16,
479 MSM_ROTATOR_OUT_YSTRIDE1);
480 if (info->src.format == MDP_Y_CBCR_H2V1) {
481 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
482 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
483 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
484 MSM_ROTATOR_OUT_PACK_PATTERN1);
485 } else {
486 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
487 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
488 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
489 MSM_ROTATOR_OUT_PACK_PATTERN1);
490 }
491 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
492 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700493 1 << 8 | /* ROT_EN */
494 info->downscale_ratio << 2 | /* downscale v ratio */
495 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496 MSM_ROTATOR_SUB_BLOCK_CFG);
497 iowrite32(0 << 29 | /* frame format 0 = linear */
498 (use_imem ? 0 : 1) << 22 | /* tile size */
499 2 << 19 | /* fetch planes 2 = pseudo */
500 0 << 18 | /* unpack align */
501 1 << 17 | /* unpack tight */
502 1 << 13 | /* unpack count 0=1 component */
503 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
504 0 << 8 | /* has alpha */
505 0 << 6 | /* alpha bits 3=8bits */
506 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
507 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
508 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
509 MSM_ROTATOR_SRC_FORMAT);
510 }
511
512 return 0;
513}
514
515static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
516 unsigned int in_paddr,
517 unsigned int out_paddr,
518 unsigned int use_imem,
519 int new_session,
520 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700521 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700522 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700524 uint32_t dst_format;
525 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700527 switch (info->src.format) {
528 case MDP_Y_CRCB_H2V2_TILE:
529 is_tile = 1;
530 case MDP_Y_CR_CB_H2V2:
531 case MDP_Y_CR_CB_GH2V2:
532 case MDP_Y_CRCB_H2V2:
533 dst_format = MDP_Y_CRCB_H2V2;
534 break;
535 case MDP_Y_CBCR_H2V2_TILE:
536 is_tile = 1;
537 case MDP_Y_CB_CR_H2V2:
538 case MDP_Y_CBCR_H2V2:
539 dst_format = MDP_Y_CBCR_H2V2;
540 break;
541 default:
542 return -EINVAL;
543 }
544 if (info->dst.format != dst_format)
545 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800547 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530548 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
549 info->src.format == MDP_Y_CR_CB_GH2V2) &&
550 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800551 swap(in_chroma_paddr, in_chroma2_paddr);
552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700553 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700554 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
555 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
556
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557 iowrite32(out_paddr +
558 ((info->dst_y * info->dst.width) + info->dst_x),
559 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700560 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 ((info->dst_y * info->dst.width)/2 + info->dst_x),
562 MSM_ROTATOR_OUTP1_ADDR);
563
564 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700565 if (in_chroma2_paddr) {
566 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530567 iowrite32(ALIGN(info->src.width, 16) |
568 ALIGN((info->src.width / 2), 16) << 16,
569 MSM_ROTATOR_SRC_YSTRIDE1);
570 iowrite32(ALIGN((info->src.width / 2), 16),
571 MSM_ROTATOR_SRC_YSTRIDE2);
572 } else {
573 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700574 (info->src.width / 2) << 16,
575 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530576 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700577 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530578 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700579 } else {
580 iowrite32(info->src.width |
581 info->src.width << 16,
582 MSM_ROTATOR_SRC_YSTRIDE1);
583 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700585 info->dst.width << 16,
586 MSM_ROTATOR_OUT_YSTRIDE1);
587
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700588 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700589 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
590 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
591 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
592 MSM_ROTATOR_OUT_PACK_PATTERN1);
593 } else {
594 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
595 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
596 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
597 MSM_ROTATOR_OUT_PACK_PATTERN1);
598 }
599 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
600 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700601 1 << 8 | /* ROT_EN */
602 info->downscale_ratio << 2 | /* downscale v ratio */
603 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700605
606 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700608 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 0 << 18 | /* unpack align */
610 1 << 17 | /* unpack tight */
611 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700612 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613 0 << 8 | /* has alpha */
614 0 << 6 | /* alpha bits 3=8bits */
615 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
616 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
617 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
618 MSM_ROTATOR_SRC_FORMAT);
619 }
620 return 0;
621}
622
623static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
624 unsigned int in_paddr,
625 unsigned int out_paddr,
626 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530627 int new_session,
628 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629{
630 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530631 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632
Mayank Chopra732dcd62012-01-09 20:53:39 +0530633 if (info->src.format == MDP_YCRYCB_H2V1)
634 dst_format = MDP_Y_CRCB_H2V1;
635 else
636 return -EINVAL;
637
638 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 return -EINVAL;
640
641 bpp = get_bpp(info->src.format);
642 if (bpp < 0)
643 return -ENOTTY;
644
645 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
646 iowrite32(out_paddr +
647 ((info->dst_y * info->dst.width) + info->dst_x),
648 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530649 iowrite32(out_chroma_paddr +
650 ((info->dst_y * info->dst.width)/2 + info->dst_x),
651 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652
653 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530654 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530656 if (info->rotations & MDP_ROT_90)
657 iowrite32(info->dst.width |
658 (info->dst.width*2) << 16,
659 MSM_ROTATOR_OUT_YSTRIDE1);
660 else
661 iowrite32(info->dst.width |
662 (info->dst.width) << 16,
663 MSM_ROTATOR_OUT_YSTRIDE1);
664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
666 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530667 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700668 MSM_ROTATOR_OUT_PACK_PATTERN1);
669 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
670 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700671 1 << 8 | /* ROT_EN */
672 info->downscale_ratio << 2 | /* downscale v ratio */
673 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 MSM_ROTATOR_SUB_BLOCK_CFG);
675 iowrite32(0 << 29 | /* frame format 0 = linear */
676 (use_imem ? 0 : 1) << 22 | /* tile size */
677 0 << 19 | /* fetch planes 0=interleaved */
678 0 << 18 | /* unpack align */
679 1 << 17 | /* unpack tight */
680 3 << 13 | /* unpack count 0=1 component */
681 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
682 0 << 8 | /* has alpha */
683 0 << 6 | /* alpha bits 3=8bits */
684 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
685 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
686 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
687 MSM_ROTATOR_SRC_FORMAT);
688 }
689
690 return 0;
691}
692
693static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
694 unsigned int in_paddr,
695 unsigned int out_paddr,
696 unsigned int use_imem,
697 int new_session)
698{
699 int bpp, abits, rbits, gbits, bbits;
700
701 if (info->src.format != info->dst.format)
702 return -EINVAL;
703
704 bpp = get_bpp(info->src.format);
705 if (bpp < 0)
706 return -ENOTTY;
707
708 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
709 iowrite32(out_paddr +
710 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
711 MSM_ROTATOR_OUTP0_ADDR);
712
713 if (new_session) {
714 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
715 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
716 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
717 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700718 1 << 8 | /* ROT_EN */
719 info->downscale_ratio << 2 | /* downscale v ratio */
720 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721 MSM_ROTATOR_SUB_BLOCK_CFG);
722 switch (info->src.format) {
723 case MDP_RGB_565:
724 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
725 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
726 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
727 MSM_ROTATOR_OUT_PACK_PATTERN1);
728 abits = 0;
729 rbits = COMPONENT_5BITS;
730 gbits = COMPONENT_6BITS;
731 bbits = COMPONENT_5BITS;
732 break;
733
734 case MDP_BGR_565:
735 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
736 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
737 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
738 MSM_ROTATOR_OUT_PACK_PATTERN1);
739 abits = 0;
740 rbits = COMPONENT_5BITS;
741 gbits = COMPONENT_6BITS;
742 bbits = COMPONENT_5BITS;
743 break;
744
745 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700746 case MDP_YCBCR_H1V1:
747 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700748 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
749 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
750 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
751 MSM_ROTATOR_OUT_PACK_PATTERN1);
752 abits = 0;
753 rbits = COMPONENT_8BITS;
754 gbits = COMPONENT_8BITS;
755 bbits = COMPONENT_8BITS;
756 break;
757
758 case MDP_ARGB_8888:
759 case MDP_RGBA_8888:
760 case MDP_XRGB_8888:
761 case MDP_RGBX_8888:
762 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
763 CLR_B, 8),
764 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
765 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
766 CLR_B, 8),
767 MSM_ROTATOR_OUT_PACK_PATTERN1);
768 abits = COMPONENT_8BITS;
769 rbits = COMPONENT_8BITS;
770 gbits = COMPONENT_8BITS;
771 bbits = COMPONENT_8BITS;
772 break;
773
774 case MDP_BGRA_8888:
775 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
776 CLR_R, 8),
777 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
778 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
779 CLR_R, 8),
780 MSM_ROTATOR_OUT_PACK_PATTERN1);
781 abits = COMPONENT_8BITS;
782 rbits = COMPONENT_8BITS;
783 gbits = COMPONENT_8BITS;
784 bbits = COMPONENT_8BITS;
785 break;
786
787 default:
788 return -EINVAL;
789 }
790 iowrite32(0 << 29 | /* frame format 0 = linear */
791 (use_imem ? 0 : 1) << 22 | /* tile size */
792 0 << 19 | /* fetch planes 0=interleaved */
793 0 << 18 | /* unpack align */
794 1 << 17 | /* unpack tight */
795 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
796 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
797 (abits ? 1 : 0) << 8 | /* has alpha */
798 abits << 6 | /* alpha bits 3=8bits */
799 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
800 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
801 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
802 MSM_ROTATOR_SRC_FORMAT);
803 }
804
805 return 0;
806}
807
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700808static int get_img(struct msmfb_data *fbd, unsigned char src,
809 unsigned long *start, unsigned long *len, struct file **p_file,
810 int *p_need, struct ion_handle **p_ihdl)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700811{
812 int ret = 0;
813#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700814 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815 int put_needed, fb_num;
816#endif
817#ifdef CONFIG_ANDROID_PMEM
818 unsigned long vstart;
819#endif
820
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800821 *p_need = 0;
822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700824 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
825 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700826 if (file == NULL) {
827 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700828 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700829 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830
Naseer Ahmed18018602011-10-25 13:32:58 -0700831 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
832 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700833 if (get_fb_phys_info(start, len, fb_num,
834 ROTATOR_SUBSYSTEM_ID)) {
835 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700836 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700837 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700838 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800839 *p_need = put_needed;
840 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700841 } else {
842 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700844 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700845 if (ret)
846 fput_light(file, put_needed);
847 return ret;
848 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700849#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700850
851#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700852 return msm_rotator_iommu_map_buf(fbd->memory_id, src, start,
853 len, p_ihdl);
Naseer Ahmed18018602011-10-25 13:32:58 -0700854#endif
855#ifdef CONFIG_ANDROID_PMEM
856 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
857 return 0;
858 else
859 return -ENOMEM;
860#endif
861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862}
863
Naseer Ahmed18018602011-10-25 13:32:58 -0700864static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
865{
866#ifdef CONFIG_ANDROID_PMEM
867 if (p_file != NULL)
868 put_pmem_file(p_file);
869#endif
870#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700871 if (!IS_ERR_OR_NULL(p_ihdl)) {
872 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
873 ion_unmap_iommu(msm_rotator_dev->client,
874 p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
875
Naseer Ahmed18018602011-10-25 13:32:58 -0700876 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700877 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700878#endif
879}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700880static int msm_rotator_do_rotate(unsigned long arg)
881{
Naseer Ahmed18018602011-10-25 13:32:58 -0700882 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883 struct msm_rotator_data_info info;
884 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700885 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700886 int use_imem = 0, rc = 0, s;
887 struct file *srcp0_file = NULL, *dstp0_file = NULL;
888 struct file *srcp1_file = NULL, *dstp1_file = NULL;
889 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
890 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800891 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700893 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700894 struct msm_rotator_img_info *img_info;
895 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896
897 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
898 return -EFAULT;
899
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 mutex_lock(&msm_rotator_dev->rotator_lock);
901 for (s = 0; s < MAX_SESSIONS; s++)
902 if ((msm_rotator_dev->img_info[s] != NULL) &&
903 (info.session_id ==
904 (unsigned int)msm_rotator_dev->img_info[s]
905 ))
906 break;
907
908 if (s == MAX_SESSIONS) {
909 dev_dbg(msm_rotator_dev->device,
910 "%s() : Attempt to use invalid session_id %d\n",
911 __func__, s);
912 rc = -EINVAL;
913 goto do_rotate_unlock_mutex;
914 }
915
916 if (msm_rotator_dev->img_info[s]->enable == 0) {
917 dev_dbg(msm_rotator_dev->device,
918 "%s() : Session_id %d not enabled \n",
919 __func__, s);
920 rc = -EINVAL;
921 goto do_rotate_unlock_mutex;
922 }
923
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700924 img_info = msm_rotator_dev->img_info[s];
925 if (msm_rotator_get_plane_sizes(img_info->src.format,
926 img_info->src.width,
927 img_info->src.height,
928 &src_planes)) {
929 pr_err("%s: invalid src format\n", __func__);
930 rc = -EINVAL;
931 goto do_rotate_unlock_mutex;
932 }
933 if (msm_rotator_get_plane_sizes(img_info->dst.format,
934 img_info->dst.width,
935 img_info->dst.height,
936 &dst_planes)) {
937 pr_err("%s: invalid dst format\n", __func__);
938 rc = -EINVAL;
939 goto do_rotate_unlock_mutex;
940 }
941
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700942 rc = get_img(&info.src, 1, (unsigned long *)&in_paddr,
943 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
944 &srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700945 if (rc) {
946 pr_err("%s: in get_img() failed id=0x%08x\n",
947 DRIVER_NAME, info.src.memory_id);
948 goto do_rotate_unlock_mutex;
949 }
950
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700951 rc = get_img(&info.dst, 0, (unsigned long *)&out_paddr,
952 (unsigned long *)&dst_len, &dstp0_file, &p_need,
953 &dstp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700954 if (rc) {
955 pr_err("%s: out get_img() failed id=0x%08x\n",
956 DRIVER_NAME, info.dst.memory_id);
957 goto do_rotate_unlock_mutex;
958 }
959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960 format = msm_rotator_dev->img_info[s]->src.format;
961 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700962 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
963 (src_planes.num_planes == 2)) {
964 if (checkoffset(info.src.offset,
965 src_planes.plane_size[0],
966 src_len)) {
967 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
968 __func__, src_len, info.src.offset);
969 rc = -ERANGE;
970 goto do_rotate_unlock_mutex;
971 }
972 if (checkoffset(info.dst.offset,
973 dst_planes.plane_size[0],
974 dst_len)) {
975 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
976 __func__, dst_len, info.dst.offset);
977 rc = -ERANGE;
978 goto do_rotate_unlock_mutex;
979 }
980
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700981 rc = get_img(&info.src_chroma, 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800983 (unsigned long *)&src_len, &srcp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700984 &srcp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700986 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 DRIVER_NAME, info.src_chroma.memory_id);
988 goto do_rotate_unlock_mutex;
989 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700991 rc = get_img(&info.dst_chroma, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800993 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700994 &dstp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700996 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700998 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001000
1001 if (checkoffset(info.src_chroma.offset,
1002 src_planes.plane_size[1],
1003 src_len)) {
1004 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1005 __func__, src_len, info.src_chroma.offset);
1006 rc = -ERANGE;
1007 goto do_rotate_unlock_mutex;
1008 }
1009
1010 if (checkoffset(info.dst_chroma.offset,
1011 src_planes.plane_size[1],
1012 dst_len)) {
1013 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1014 __func__, dst_len, info.dst_chroma.offset);
1015 rc = -ERANGE;
1016 goto do_rotate_unlock_mutex;
1017 }
1018
1019 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001021 } else {
1022 if (checkoffset(info.src.offset,
1023 src_planes.total_size,
1024 src_len)) {
1025 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1026 __func__, src_len, info.src.offset);
1027 rc = -ERANGE;
1028 goto do_rotate_unlock_mutex;
1029 }
1030 if (checkoffset(info.dst.offset,
1031 dst_planes.total_size,
1032 dst_len)) {
1033 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1034 __func__, dst_len, info.dst.offset);
1035 rc = -ERANGE;
1036 goto do_rotate_unlock_mutex;
1037 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 }
1039
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001040 in_paddr += info.src.offset;
1041 out_paddr += info.dst.offset;
1042
1043 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1044 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1045 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1046 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1047 if (src_planes.num_planes >= 3)
1048 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1051 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1052 enable_rot_clks();
1053 msm_rotator_dev->rot_clk_state = CLK_EN;
1054 }
1055 enable_irq(msm_rotator_dev->irq);
1056
1057#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1058 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1059#else
1060 use_imem = 0;
1061#endif
1062 /*
1063 * workaround for a hardware bug. rotator hardware hangs when we
1064 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1065 * temporary fix use 0x42 for BURST_SIZE when imem used.
1066 */
1067 if (use_imem)
1068 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1069
1070 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1071 << 16) |
1072 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1073 MSM_ROTATOR_SRC_SIZE);
1074 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1075 << 16) |
1076 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1077 MSM_ROTATOR_SRC_XY);
1078 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1079 << 16) |
1080 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1081 MSM_ROTATOR_SRC_IMAGE_SIZE);
1082
1083 switch (format) {
1084 case MDP_RGB_565:
1085 case MDP_BGR_565:
1086 case MDP_RGB_888:
1087 case MDP_ARGB_8888:
1088 case MDP_RGBA_8888:
1089 case MDP_XRGB_8888:
1090 case MDP_BGRA_8888:
1091 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001092 case MDP_YCBCR_H1V1:
1093 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1095 in_paddr, out_paddr,
1096 use_imem,
1097 msm_rotator_dev->last_session_idx
1098 != s);
1099 break;
1100 case MDP_Y_CBCR_H2V2:
1101 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001102 case MDP_Y_CB_CR_H2V2:
1103 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301104 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 case MDP_Y_CRCB_H2V2_TILE:
1106 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001107 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1108 in_paddr, out_paddr, use_imem,
1109 msm_rotator_dev->last_session_idx
1110 != s,
1111 in_chroma_paddr,
1112 out_chroma_paddr,
1113 in_chroma2_paddr);
1114 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 case MDP_Y_CBCR_H2V1:
1116 case MDP_Y_CRCB_H2V1:
1117 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1118 in_paddr, out_paddr, use_imem,
1119 msm_rotator_dev->last_session_idx
1120 != s,
1121 in_chroma_paddr,
1122 out_chroma_paddr);
1123 break;
1124 case MDP_YCRYCB_H2V1:
1125 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1126 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301127 msm_rotator_dev->last_session_idx != s,
1128 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 break;
1130 default:
1131 rc = -EINVAL;
1132 goto do_rotate_exit;
1133 }
1134
1135 if (rc != 0) {
1136 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1137 goto do_rotate_exit;
1138 }
1139
1140 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1141
1142 msm_rotator_dev->processing = 1;
1143 iowrite32(0x1, MSM_ROTATOR_START);
1144
1145 wait_event(msm_rotator_dev->wq,
1146 (msm_rotator_dev->processing == 0));
1147 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
1148 if ((status & 0x03) != 0x01)
1149 rc = -EFAULT;
1150 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1151 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1152
1153do_rotate_exit:
1154 disable_irq(msm_rotator_dev->irq);
1155#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1156 msm_rotator_imem_free(ROTATOR_REQUEST);
1157#endif
1158 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001159do_rotate_unlock_mutex:
Naseer Ahmed18018602011-10-25 13:32:58 -07001160 put_img(dstp1_file, dstp1_ihdl);
1161 put_img(srcp1_file, srcp1_ihdl);
1162 put_img(dstp0_file, dstp0_ihdl);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001163
1164 /* only source may use frame buffer */
1165 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1166 fput_light(srcp0_file, ps0_need);
1167 else
1168 put_img(srcp0_file, srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001169 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1171 __func__, rc);
1172 return rc;
1173}
1174
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001175static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1176{
1177 u32 perf_level;
1178
1179 if (is_rgb)
1180 perf_level = 1;
1181 else if (wh <= (640 * 480))
1182 perf_level = 2;
1183 else if (wh <= (736 * 1280))
1184 perf_level = 3;
1185 else
1186 perf_level = 4;
1187
1188#ifdef CONFIG_MSM_BUS_SCALING
1189 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1190 perf_level);
1191#endif
1192
1193}
1194
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001195static int msm_rotator_start(unsigned long arg,
1196 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197{
1198 struct msm_rotator_img_info info;
1199 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001200 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001202 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203
1204 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1205 return -EFAULT;
1206
1207 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1208 (info.src.height > MSM_ROTATOR_MAX_H) ||
1209 (info.src.width > MSM_ROTATOR_MAX_W) ||
1210 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1211 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001212 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1213 pr_err("%s: Invalid parameters\n", __func__);
1214 return -EINVAL;
1215 }
1216
1217 if (info.rotations & MDP_ROT_90) {
1218 dst_w = info.src_rect.h >> info.downscale_ratio;
1219 dst_h = info.src_rect.w >> info.downscale_ratio;
1220 } else {
1221 dst_w = info.src_rect.w >> info.downscale_ratio;
1222 dst_h = info.src_rect.h >> info.downscale_ratio;
1223 }
1224
1225 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001226 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1227 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001228 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1229 pr_err("%s: Invalid src or dst rect\n", __func__);
1230 return -ERANGE;
1231 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001232
1233 switch (info.src.format) {
1234 case MDP_RGB_565:
1235 case MDP_BGR_565:
1236 case MDP_RGB_888:
1237 case MDP_ARGB_8888:
1238 case MDP_RGBA_8888:
1239 case MDP_XRGB_8888:
1240 case MDP_RGBX_8888:
1241 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001242 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301243 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001244 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245 case MDP_Y_CBCR_H2V2:
1246 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301247 case MDP_Y_CBCR_H2V1:
1248 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001249 case MDP_YCBCR_H1V1:
1250 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301251 info.dst.format = info.src.format;
1252 break;
1253 case MDP_YCRYCB_H2V1:
1254 info.dst.format = MDP_Y_CRCB_H2V1;
1255 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001256 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301257 case MDP_Y_CBCR_H2V2_TILE:
1258 info.dst.format = MDP_Y_CBCR_H2V2;
1259 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001260 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301261 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301263 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 break;
1265 default:
1266 return -EINVAL;
1267 }
1268
1269 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001270
1271 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 for (s = 0; s < MAX_SESSIONS; s++) {
1274 if ((msm_rotator_dev->img_info[s] != NULL) &&
1275 (info.session_id ==
1276 (unsigned int)msm_rotator_dev->img_info[s]
1277 )) {
1278 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001279 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280
1281 if (msm_rotator_dev->last_session_idx == s)
1282 msm_rotator_dev->last_session_idx =
1283 INVALID_SESSION;
1284 break;
1285 }
1286
1287 if ((msm_rotator_dev->img_info[s] == NULL) &&
1288 (first_free_index ==
1289 INVALID_SESSION))
1290 first_free_index = s;
1291 }
1292
1293 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1294 /* allocate a session id */
1295 msm_rotator_dev->img_info[first_free_index] =
1296 kzalloc(sizeof(struct msm_rotator_img_info),
1297 GFP_KERNEL);
1298 if (!msm_rotator_dev->img_info[first_free_index]) {
1299 printk(KERN_ERR "%s : unable to alloc mem\n",
1300 __func__);
1301 rc = -ENOMEM;
1302 goto rotator_start_exit;
1303 }
1304 info.session_id = (unsigned int)
1305 msm_rotator_dev->img_info[first_free_index];
1306 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001307 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 } else if (s == MAX_SESSIONS) {
1309 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1310 __func__);
1311 rc = -EBUSY;
1312 }
1313
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001314 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1315 rc = -EFAULT;
1316
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001317rotator_start_exit:
1318 mutex_unlock(&msm_rotator_dev->rotator_lock);
1319
1320 return rc;
1321}
1322
1323static int msm_rotator_finish(unsigned long arg)
1324{
1325 int rc = 0;
1326 int s;
1327 unsigned int session_id;
1328
1329 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1330 return -EFAULT;
1331
1332 mutex_lock(&msm_rotator_dev->rotator_lock);
1333 for (s = 0; s < MAX_SESSIONS; s++) {
1334 if ((msm_rotator_dev->img_info[s] != NULL) &&
1335 (session_id ==
1336 (unsigned int)msm_rotator_dev->img_info[s])) {
1337 if (msm_rotator_dev->last_session_idx == s)
1338 msm_rotator_dev->last_session_idx =
1339 INVALID_SESSION;
1340 kfree(msm_rotator_dev->img_info[s]);
1341 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001342 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343 break;
1344 }
1345 }
1346
1347 if (s == MAX_SESSIONS)
1348 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001349#ifdef CONFIG_MSM_BUS_SCALING
1350 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1351 0);
1352#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353 mutex_unlock(&msm_rotator_dev->rotator_lock);
1354 return rc;
1355}
1356
1357static int
1358msm_rotator_open(struct inode *inode, struct file *filp)
1359{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001360 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001361 int i;
1362
1363 if (filp->private_data)
1364 return -EBUSY;
1365
1366 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001367 for (i = 0; i < MAX_SESSIONS; i++) {
1368 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369 break;
1370 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001371
1372 if (i == MAX_SESSIONS) {
1373 mutex_unlock(&msm_rotator_dev->rotator_lock);
1374 return -EBUSY;
1375 }
1376
1377 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1378 if (tmp->pid == current->pid) {
1379 fd_info = tmp;
1380 break;
1381 }
1382 }
1383
1384 if (!fd_info) {
1385 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1386 if (!fd_info) {
1387 mutex_unlock(&msm_rotator_dev->rotator_lock);
1388 pr_err("%s: insufficient memory to alloc resources\n",
1389 __func__);
1390 return -ENOMEM;
1391 }
1392 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1393 fd_info->pid = current->pid;
1394 }
1395 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 mutex_unlock(&msm_rotator_dev->rotator_lock);
1397
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001398 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399
1400 return 0;
1401}
1402
1403static int
1404msm_rotator_close(struct inode *inode, struct file *filp)
1405{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001406 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001409 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1410
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001412 if (--fd_info->ref_cnt > 0) {
1413 mutex_unlock(&msm_rotator_dev->rotator_lock);
1414 return 0;
1415 }
1416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417 for (s = 0; s < MAX_SESSIONS; s++) {
1418 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001419 msm_rotator_dev->fd_info[s] == fd_info) {
1420 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1421 __func__, msm_rotator_dev->img_info[s],
1422 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001423 kfree(msm_rotator_dev->img_info[s]);
1424 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001425 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426 if (msm_rotator_dev->last_session_idx == s)
1427 msm_rotator_dev->last_session_idx =
1428 INVALID_SESSION;
1429 }
1430 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001431 list_del(&fd_info->list);
1432 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433 mutex_unlock(&msm_rotator_dev->rotator_lock);
1434
1435 return 0;
1436}
1437
1438static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1439 unsigned long arg)
1440{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001441 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442
1443 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1444 return -ENOTTY;
1445
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001446 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447
1448 switch (cmd) {
1449 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001450 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 case MSM_ROTATOR_IOCTL_ROTATE:
1452 return msm_rotator_do_rotate(arg);
1453 case MSM_ROTATOR_IOCTL_FINISH:
1454 return msm_rotator_finish(arg);
1455
1456 default:
1457 dev_dbg(msm_rotator_dev->device,
1458 "unexpected IOCTL %d\n", cmd);
1459 return -ENOTTY;
1460 }
1461}
1462
1463static const struct file_operations msm_rotator_fops = {
1464 .owner = THIS_MODULE,
1465 .open = msm_rotator_open,
1466 .release = msm_rotator_close,
1467 .unlocked_ioctl = msm_rotator_ioctl,
1468};
1469
1470static int __devinit msm_rotator_probe(struct platform_device *pdev)
1471{
1472 int rc = 0;
1473 struct resource *res;
1474 struct msm_rotator_platform_data *pdata = NULL;
1475 int i, number_of_clks;
1476 uint32_t ver;
1477
1478 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1479 if (!msm_rotator_dev) {
1480 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1481 __func__);
1482 return -ENOMEM;
1483 }
1484 for (i = 0; i < MAX_SESSIONS; i++)
1485 msm_rotator_dev->img_info[i] = NULL;
1486 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1487
1488 pdata = pdev->dev.platform_data;
1489 number_of_clks = pdata->number_of_clocks;
1490
1491 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1492 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001493 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494 msm_rotator_dev->imem_clk_state = CLK_DIS;
1495 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1496 msm_rotator_imem_clk_work_f);
1497 msm_rotator_dev->imem_clk = NULL;
1498 msm_rotator_dev->pdev = pdev;
1499
1500 msm_rotator_dev->core_clk = NULL;
1501 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001503#ifdef CONFIG_MSM_BUS_SCALING
1504 if (!msm_rotator_dev->bus_client_handle && pdata &&
1505 pdata->bus_scale_table) {
1506 msm_rotator_dev->bus_client_handle =
1507 msm_bus_scale_register_client(
1508 pdata->bus_scale_table);
1509 if (!msm_rotator_dev->bus_client_handle) {
1510 pr_err("%s not able to get bus scale handle\n",
1511 __func__);
1512 }
1513 }
1514#endif
1515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 for (i = 0; i < number_of_clks; i++) {
1517 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1518 msm_rotator_dev->imem_clk =
1519 clk_get(&msm_rotator_dev->pdev->dev,
1520 pdata->rotator_clks[i].clk_name);
1521 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1522 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1523 msm_rotator_dev->imem_clk = NULL;
1524 printk(KERN_ERR "%s: cannot get imem_clk "
1525 "rc=%d\n", DRIVER_NAME, rc);
1526 goto error_imem_clk;
1527 }
1528 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001529 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 pdata->rotator_clks[i].clk_rate);
1531 }
1532 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1533 msm_rotator_dev->pclk =
1534 clk_get(&msm_rotator_dev->pdev->dev,
1535 pdata->rotator_clks[i].clk_name);
1536 if (IS_ERR(msm_rotator_dev->pclk)) {
1537 rc = PTR_ERR(msm_rotator_dev->pclk);
1538 msm_rotator_dev->pclk = NULL;
1539 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1540 DRIVER_NAME, rc);
1541 goto error_pclk;
1542 }
1543
1544 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001545 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 pdata->rotator_clks[i].clk_rate);
1547 }
1548
1549 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1550 msm_rotator_dev->core_clk =
1551 clk_get(&msm_rotator_dev->pdev->dev,
1552 pdata->rotator_clks[i].clk_name);
1553 if (IS_ERR(msm_rotator_dev->core_clk)) {
1554 rc = PTR_ERR(msm_rotator_dev->core_clk);
1555 msm_rotator_dev->core_clk = NULL;
1556 printk(KERN_ERR "%s: cannot get core clk "
1557 "rc=%d\n", DRIVER_NAME, rc);
1558 goto error_core_clk;
1559 }
1560
1561 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001562 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563 pdata->rotator_clks[i].clk_rate);
1564 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 }
1566
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001567 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1568 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 if (IS_ERR(msm_rotator_dev->regulator))
1570 msm_rotator_dev->regulator = NULL;
1571
1572 msm_rotator_dev->rot_clk_state = CLK_DIS;
1573 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1574 msm_rotator_rot_clk_work_f);
1575
1576 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001577#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1578 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1579#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 platform_set_drvdata(pdev, msm_rotator_dev);
1581
1582
1583 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1584 if (!res) {
1585 printk(KERN_ALERT
1586 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1587 rc = -ENODEV;
1588 goto error_get_resource;
1589 }
1590 msm_rotator_dev->io_base = ioremap(res->start,
1591 resource_size(res));
1592
1593#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1594 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001595 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596#endif
1597 enable_rot_clks();
1598 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1599 disable_rot_clks();
1600
1601#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1602 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001603 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001605 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301606 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001607 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001608
Mayank Chopra012a8e72012-04-11 10:41:13 +05301609 rotator_hw_revision = ver;
1610 rotator_hw_revision >>= 16; /* bit 31:16 */
1611 rotator_hw_revision &= 0xff;
1612
1613 pr_info("%s: rotator_hw_revision=%x\n",
1614 __func__, rotator_hw_revision);
1615
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1617 if (msm_rotator_dev->irq < 0) {
1618 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1619 DRIVER_NAME);
1620 rc = -ENODEV;
1621 goto error_get_irq;
1622 }
1623 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1624 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1625 if (rc) {
1626 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1627 goto error_get_irq;
1628 }
1629 /* we enable the IRQ when we need it in the ioctl */
1630 disable_irq(msm_rotator_dev->irq);
1631
1632 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1633 if (rc < 0) {
1634 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1635 __func__, rc);
1636 goto error_get_irq;
1637 }
1638
1639 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1640 if (IS_ERR(msm_rotator_dev->class)) {
1641 rc = PTR_ERR(msm_rotator_dev->class);
1642 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1643 DRIVER_NAME, rc);
1644 goto error_class_create;
1645 }
1646
1647 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1648 msm_rotator_dev->dev_num, NULL,
1649 DRIVER_NAME);
1650 if (IS_ERR(msm_rotator_dev->device)) {
1651 rc = PTR_ERR(msm_rotator_dev->device);
1652 printk(KERN_ERR "%s: device_create failed %d\n",
1653 DRIVER_NAME, rc);
1654 goto error_class_device_create;
1655 }
1656
1657 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1658 rc = cdev_add(&msm_rotator_dev->cdev,
1659 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1660 1);
1661 if (rc < 0) {
1662 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1663 goto error_cdev_add;
1664 }
1665
1666 init_waitqueue_head(&msm_rotator_dev->wq);
1667
1668 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1669 return rc;
1670
1671error_cdev_add:
1672 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1673error_class_device_create:
1674 class_destroy(msm_rotator_dev->class);
1675error_class_create:
1676 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1677error_get_irq:
1678 iounmap(msm_rotator_dev->io_base);
1679error_get_resource:
1680 mutex_destroy(&msm_rotator_dev->rotator_lock);
1681 if (msm_rotator_dev->regulator)
1682 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683 clk_put(msm_rotator_dev->core_clk);
1684error_core_clk:
1685 clk_put(msm_rotator_dev->pclk);
1686error_pclk:
1687 if (msm_rotator_dev->imem_clk)
1688 clk_put(msm_rotator_dev->imem_clk);
1689error_imem_clk:
1690 mutex_destroy(&msm_rotator_dev->imem_lock);
1691 kfree(msm_rotator_dev);
1692 return rc;
1693}
1694
1695static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1696{
1697 int i;
1698
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001699#ifdef CONFIG_MSM_BUS_SCALING
1700 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1701#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 free_irq(msm_rotator_dev->irq, NULL);
1703 mutex_destroy(&msm_rotator_dev->rotator_lock);
1704 cdev_del(&msm_rotator_dev->cdev);
1705 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1706 class_destroy(msm_rotator_dev->class);
1707 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1708 iounmap(msm_rotator_dev->io_base);
1709 if (msm_rotator_dev->imem_clk) {
1710 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001711 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 clk_put(msm_rotator_dev->imem_clk);
1713 msm_rotator_dev->imem_clk = NULL;
1714 }
1715 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1716 disable_rot_clks();
1717 clk_put(msm_rotator_dev->core_clk);
1718 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 if (msm_rotator_dev->regulator)
1720 regulator_put(msm_rotator_dev->regulator);
1721 msm_rotator_dev->core_clk = NULL;
1722 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 mutex_destroy(&msm_rotator_dev->imem_lock);
1724 for (i = 0; i < MAX_SESSIONS; i++)
1725 if (msm_rotator_dev->img_info[i] != NULL)
1726 kfree(msm_rotator_dev->img_info[i]);
1727 kfree(msm_rotator_dev);
1728 return 0;
1729}
1730
1731#ifdef CONFIG_PM
1732static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1733{
1734 mutex_lock(&msm_rotator_dev->imem_lock);
1735 if (msm_rotator_dev->imem_clk_state == CLK_EN
1736 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001737 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1739 }
1740 mutex_unlock(&msm_rotator_dev->imem_lock);
1741 mutex_lock(&msm_rotator_dev->rotator_lock);
1742 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1743 disable_rot_clks();
1744 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1745 }
1746 mutex_unlock(&msm_rotator_dev->rotator_lock);
1747 return 0;
1748}
1749
1750static int msm_rotator_resume(struct platform_device *dev)
1751{
1752 mutex_lock(&msm_rotator_dev->imem_lock);
1753 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1754 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001755 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001756 msm_rotator_dev->imem_clk_state = CLK_EN;
1757 }
1758 mutex_unlock(&msm_rotator_dev->imem_lock);
1759 mutex_lock(&msm_rotator_dev->rotator_lock);
1760 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1761 enable_rot_clks();
1762 msm_rotator_dev->rot_clk_state = CLK_EN;
1763 }
1764 mutex_unlock(&msm_rotator_dev->rotator_lock);
1765 return 0;
1766}
1767#endif
1768
1769static struct platform_driver msm_rotator_platform_driver = {
1770 .probe = msm_rotator_probe,
1771 .remove = __devexit_p(msm_rotator_remove),
1772#ifdef CONFIG_PM
1773 .suspend = msm_rotator_suspend,
1774 .resume = msm_rotator_resume,
1775#endif
1776 .driver = {
1777 .owner = THIS_MODULE,
1778 .name = DRIVER_NAME
1779 }
1780};
1781
1782static int __init msm_rotator_init(void)
1783{
1784 return platform_driver_register(&msm_rotator_platform_driver);
1785}
1786
1787static void __exit msm_rotator_exit(void)
1788{
1789 return platform_driver_unregister(&msm_rotator_platform_driver);
1790}
1791
1792module_init(msm_rotator_init);
1793module_exit(msm_rotator_exit);
1794
1795MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1796MODULE_VERSION("1.0");
1797MODULE_LICENSE("GPL v2");