fimc-core.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. /*
  2. * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver
  3. *
  4. * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
  5. * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published
  9. * by the Free Software Foundation, either version 2 of the License,
  10. * or (at your option) any later version.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/kernel.h>
  14. #include <linux/types.h>
  15. #include <linux/errno.h>
  16. #include <linux/bug.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/device.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/pm_runtime.h>
  21. #include <linux/list.h>
  22. #include <linux/io.h>
  23. #include <linux/slab.h>
  24. #include <linux/clk.h>
  25. #include <media/v4l2-ioctl.h>
  26. #include <media/videobuf2-core.h>
  27. #include <media/videobuf2-dma-contig.h>
  28. #include "fimc-core.h"
  29. #include "fimc-reg.h"
  30. #include "fimc-mdevice.h"
  31. static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
  32. "sclk_fimc", "fimc"
  33. };
  34. static struct fimc_fmt fimc_formats[] = {
  35. {
  36. .name = "RGB565",
  37. .fourcc = V4L2_PIX_FMT_RGB565,
  38. .depth = { 16 },
  39. .color = FIMC_FMT_RGB565,
  40. .memplanes = 1,
  41. .colplanes = 1,
  42. .flags = FMT_FLAGS_M2M,
  43. }, {
  44. .name = "BGR666",
  45. .fourcc = V4L2_PIX_FMT_BGR666,
  46. .depth = { 32 },
  47. .color = FIMC_FMT_RGB666,
  48. .memplanes = 1,
  49. .colplanes = 1,
  50. .flags = FMT_FLAGS_M2M,
  51. }, {
  52. .name = "ARGB8888, 32 bpp",
  53. .fourcc = V4L2_PIX_FMT_RGB32,
  54. .depth = { 32 },
  55. .color = FIMC_FMT_RGB888,
  56. .memplanes = 1,
  57. .colplanes = 1,
  58. .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA,
  59. }, {
  60. .name = "ARGB1555",
  61. .fourcc = V4L2_PIX_FMT_RGB555,
  62. .depth = { 16 },
  63. .color = FIMC_FMT_RGB555,
  64. .memplanes = 1,
  65. .colplanes = 1,
  66. .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
  67. }, {
  68. .name = "ARGB4444",
  69. .fourcc = V4L2_PIX_FMT_RGB444,
  70. .depth = { 16 },
  71. .color = FIMC_FMT_RGB444,
  72. .memplanes = 1,
  73. .colplanes = 1,
  74. .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
  75. }, {
  76. .name = "YUV 4:2:2 packed, YCbYCr",
  77. .fourcc = V4L2_PIX_FMT_YUYV,
  78. .depth = { 16 },
  79. .color = FIMC_FMT_YCBYCR422,
  80. .memplanes = 1,
  81. .colplanes = 1,
  82. .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
  83. .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  84. }, {
  85. .name = "YUV 4:2:2 packed, CbYCrY",
  86. .fourcc = V4L2_PIX_FMT_UYVY,
  87. .depth = { 16 },
  88. .color = FIMC_FMT_CBYCRY422,
  89. .memplanes = 1,
  90. .colplanes = 1,
  91. .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
  92. .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  93. }, {
  94. .name = "YUV 4:2:2 packed, CrYCbY",
  95. .fourcc = V4L2_PIX_FMT_VYUY,
  96. .depth = { 16 },
  97. .color = FIMC_FMT_CRYCBY422,
  98. .memplanes = 1,
  99. .colplanes = 1,
  100. .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
  101. .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  102. }, {
  103. .name = "YUV 4:2:2 packed, YCrYCb",
  104. .fourcc = V4L2_PIX_FMT_YVYU,
  105. .depth = { 16 },
  106. .color = FIMC_FMT_YCRYCB422,
  107. .memplanes = 1,
  108. .colplanes = 1,
  109. .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
  110. .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
  111. }, {
  112. .name = "YUV 4:2:2 planar, Y/Cb/Cr",
  113. .fourcc = V4L2_PIX_FMT_YUV422P,
  114. .depth = { 12 },
  115. .color = FIMC_FMT_YCBYCR422,
  116. .memplanes = 1,
  117. .colplanes = 3,
  118. .flags = FMT_FLAGS_M2M,
  119. }, {
  120. .name = "YUV 4:2:2 planar, Y/CbCr",
  121. .fourcc = V4L2_PIX_FMT_NV16,
  122. .depth = { 16 },
  123. .color = FIMC_FMT_YCBYCR422,
  124. .memplanes = 1,
  125. .colplanes = 2,
  126. .flags = FMT_FLAGS_M2M,
  127. }, {
  128. .name = "YUV 4:2:2 planar, Y/CrCb",
  129. .fourcc = V4L2_PIX_FMT_NV61,
  130. .depth = { 16 },
  131. .color = FIMC_FMT_YCRYCB422,
  132. .memplanes = 1,
  133. .colplanes = 2,
  134. .flags = FMT_FLAGS_M2M,
  135. }, {
  136. .name = "YUV 4:2:0 planar, YCbCr",
  137. .fourcc = V4L2_PIX_FMT_YUV420,
  138. .depth = { 12 },
  139. .color = FIMC_FMT_YCBCR420,
  140. .memplanes = 1,
  141. .colplanes = 3,
  142. .flags = FMT_FLAGS_M2M,
  143. }, {
  144. .name = "YUV 4:2:0 planar, Y/CbCr",
  145. .fourcc = V4L2_PIX_FMT_NV12,
  146. .depth = { 12 },
  147. .color = FIMC_FMT_YCBCR420,
  148. .memplanes = 1,
  149. .colplanes = 2,
  150. .flags = FMT_FLAGS_M2M,
  151. }, {
  152. .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
  153. .fourcc = V4L2_PIX_FMT_NV12M,
  154. .color = FIMC_FMT_YCBCR420,
  155. .depth = { 8, 4 },
  156. .memplanes = 2,
  157. .colplanes = 2,
  158. .flags = FMT_FLAGS_M2M,
  159. }, {
  160. .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
  161. .fourcc = V4L2_PIX_FMT_YUV420M,
  162. .color = FIMC_FMT_YCBCR420,
  163. .depth = { 8, 2, 2 },
  164. .memplanes = 3,
  165. .colplanes = 3,
  166. .flags = FMT_FLAGS_M2M,
  167. }, {
  168. .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
  169. .fourcc = V4L2_PIX_FMT_NV12MT,
  170. .color = FIMC_FMT_YCBCR420,
  171. .depth = { 8, 4 },
  172. .memplanes = 2,
  173. .colplanes = 2,
  174. .flags = FMT_FLAGS_M2M,
  175. }, {
  176. .name = "JPEG encoded data",
  177. .fourcc = V4L2_PIX_FMT_JPEG,
  178. .color = FIMC_FMT_JPEG,
  179. .depth = { 8 },
  180. .memplanes = 1,
  181. .colplanes = 1,
  182. .mbus_code = V4L2_MBUS_FMT_JPEG_1X8,
  183. .flags = FMT_FLAGS_CAM,
  184. },
  185. };
  186. struct fimc_fmt * fimc_get_format(unsigned int index)
  187. {
  188. if (index >= ARRAY_SIZE(fimc_formats))
  189. return NULL;
  190. return &fimc_formats[index];
  191. }
  192. int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
  193. int dw, int dh, int rotation)
  194. {
  195. if (rotation == 90 || rotation == 270)
  196. swap(dw, dh);
  197. if (!ctx->scaler.enabled)
  198. return (sw == dw && sh == dh) ? 0 : -EINVAL;
  199. if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh))
  200. return -EINVAL;
  201. return 0;
  202. }
  203. static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
  204. {
  205. u32 sh = 6;
  206. if (src >= 64 * tar)
  207. return -EINVAL;
  208. while (sh--) {
  209. u32 tmp = 1 << sh;
  210. if (src >= tar * tmp) {
  211. *shift = sh, *ratio = tmp;
  212. return 0;
  213. }
  214. }
  215. *shift = 0, *ratio = 1;
  216. return 0;
  217. }
  218. int fimc_set_scaler_info(struct fimc_ctx *ctx)
  219. {
  220. struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
  221. struct device *dev = &ctx->fimc_dev->pdev->dev;
  222. struct fimc_scaler *sc = &ctx->scaler;
  223. struct fimc_frame *s_frame = &ctx->s_frame;
  224. struct fimc_frame *d_frame = &ctx->d_frame;
  225. int tx, ty, sx, sy;
  226. int ret;
  227. if (ctx->rotation == 90 || ctx->rotation == 270) {
  228. ty = d_frame->width;
  229. tx = d_frame->height;
  230. } else {
  231. tx = d_frame->width;
  232. ty = d_frame->height;
  233. }
  234. if (tx <= 0 || ty <= 0) {
  235. dev_err(dev, "Invalid target size: %dx%d", tx, ty);
  236. return -EINVAL;
  237. }
  238. sx = s_frame->width;
  239. sy = s_frame->height;
  240. if (sx <= 0 || sy <= 0) {
  241. dev_err(dev, "Invalid source size: %dx%d", sx, sy);
  242. return -EINVAL;
  243. }
  244. sc->real_width = sx;
  245. sc->real_height = sy;
  246. ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
  247. if (ret)
  248. return ret;
  249. ret = fimc_get_scaler_factor(sy, ty, &sc->pre_vratio, &sc->vfactor);
  250. if (ret)
  251. return ret;
  252. sc->pre_dst_width = sx / sc->pre_hratio;
  253. sc->pre_dst_height = sy / sc->pre_vratio;
  254. if (variant->has_mainscaler_ext) {
  255. sc->main_hratio = (sx << 14) / (tx << sc->hfactor);
  256. sc->main_vratio = (sy << 14) / (ty << sc->vfactor);
  257. } else {
  258. sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
  259. sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
  260. }
  261. sc->scaleup_h = (tx >= sx) ? 1 : 0;
  262. sc->scaleup_v = (ty >= sy) ? 1 : 0;
  263. /* check to see if input and output size/format differ */
  264. if (s_frame->fmt->color == d_frame->fmt->color
  265. && s_frame->width == d_frame->width
  266. && s_frame->height == d_frame->height)
  267. sc->copy_mode = 1;
  268. else
  269. sc->copy_mode = 0;
  270. return 0;
  271. }
  272. static irqreturn_t fimc_irq_handler(int irq, void *priv)
  273. {
  274. struct fimc_dev *fimc = priv;
  275. struct fimc_ctx *ctx;
  276. fimc_hw_clear_irq(fimc);
  277. spin_lock(&fimc->slock);
  278. if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
  279. if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) {
  280. set_bit(ST_M2M_SUSPENDED, &fimc->state);
  281. wake_up(&fimc->irq_queue);
  282. goto out;
  283. }
  284. ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
  285. if (ctx != NULL) {
  286. spin_unlock(&fimc->slock);
  287. fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
  288. if (ctx->state & FIMC_CTX_SHUT) {
  289. ctx->state &= ~FIMC_CTX_SHUT;
  290. wake_up(&fimc->irq_queue);
  291. }
  292. return IRQ_HANDLED;
  293. }
  294. } else if (test_bit(ST_CAPT_PEND, &fimc->state)) {
  295. int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) &&
  296. fimc->vid_cap.reqbufs_count == 1;
  297. fimc_capture_irq_handler(fimc, !last_buf);
  298. }
  299. out:
  300. spin_unlock(&fimc->slock);
  301. return IRQ_HANDLED;
  302. }
  303. /* The color format (colplanes, memplanes) must be already configured. */
  304. int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
  305. struct fimc_frame *frame, struct fimc_addr *paddr)
  306. {
  307. int ret = 0;
  308. u32 pix_size;
  309. if (vb == NULL || frame == NULL)
  310. return -EINVAL;
  311. pix_size = frame->width * frame->height;
  312. dbg("memplanes= %d, colplanes= %d, pix_size= %d",
  313. frame->fmt->memplanes, frame->fmt->colplanes, pix_size);
  314. paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
  315. if (frame->fmt->memplanes == 1) {
  316. switch (frame->fmt->colplanes) {
  317. case 1:
  318. paddr->cb = 0;
  319. paddr->cr = 0;
  320. break;
  321. case 2:
  322. /* decompose Y into Y/Cb */
  323. paddr->cb = (u32)(paddr->y + pix_size);
  324. paddr->cr = 0;
  325. break;
  326. case 3:
  327. paddr->cb = (u32)(paddr->y + pix_size);
  328. /* decompose Y into Y/Cb/Cr */
  329. if (FIMC_FMT_YCBCR420 == frame->fmt->color)
  330. paddr->cr = (u32)(paddr->cb
  331. + (pix_size >> 2));
  332. else /* 422 */
  333. paddr->cr = (u32)(paddr->cb
  334. + (pix_size >> 1));
  335. break;
  336. default:
  337. return -EINVAL;
  338. }
  339. } else {
  340. if (frame->fmt->memplanes >= 2)
  341. paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
  342. if (frame->fmt->memplanes == 3)
  343. paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
  344. }
  345. dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d",
  346. paddr->y, paddr->cb, paddr->cr, ret);
  347. return ret;
  348. }
  349. /* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */
  350. void fimc_set_yuv_order(struct fimc_ctx *ctx)
  351. {
  352. /* The one only mode supported in SoC. */
  353. ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
  354. ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
  355. /* Set order for 1 plane input formats. */
  356. switch (ctx->s_frame.fmt->color) {
  357. case FIMC_FMT_YCRYCB422:
  358. ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
  359. break;
  360. case FIMC_FMT_CBYCRY422:
  361. ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
  362. break;
  363. case FIMC_FMT_CRYCBY422:
  364. ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
  365. break;
  366. case FIMC_FMT_YCBYCR422:
  367. default:
  368. ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
  369. break;
  370. }
  371. dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
  372. switch (ctx->d_frame.fmt->color) {
  373. case FIMC_FMT_YCRYCB422:
  374. ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
  375. break;
  376. case FIMC_FMT_CBYCRY422:
  377. ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
  378. break;
  379. case FIMC_FMT_CRYCBY422:
  380. ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
  381. break;
  382. case FIMC_FMT_YCBYCR422:
  383. default:
  384. ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
  385. break;
  386. }
  387. dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
  388. }
  389. void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
  390. {
  391. struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
  392. u32 i, depth = 0;
  393. for (i = 0; i < f->fmt->colplanes; i++)
  394. depth += f->fmt->depth[i];
  395. f->dma_offset.y_h = f->offs_h;
  396. if (!variant->pix_hoff)
  397. f->dma_offset.y_h *= (depth >> 3);
  398. f->dma_offset.y_v = f->offs_v;
  399. f->dma_offset.cb_h = f->offs_h;
  400. f->dma_offset.cb_v = f->offs_v;
  401. f->dma_offset.cr_h = f->offs_h;
  402. f->dma_offset.cr_v = f->offs_v;
  403. if (!variant->pix_hoff) {
  404. if (f->fmt->colplanes == 3) {
  405. f->dma_offset.cb_h >>= 1;
  406. f->dma_offset.cr_h >>= 1;
  407. }
  408. if (f->fmt->color == FIMC_FMT_YCBCR420) {
  409. f->dma_offset.cb_v >>= 1;
  410. f->dma_offset.cr_v >>= 1;
  411. }
  412. }
  413. dbg("in_offset: color= %d, y_h= %d, y_v= %d",
  414. f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
  415. }
  416. /*
  417. * V4L2 controls handling
  418. */
  419. #define ctrl_to_ctx(__ctrl) \
  420. container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler)
  421. static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
  422. {
  423. struct fimc_dev *fimc = ctx->fimc_dev;
  424. struct samsung_fimc_variant *variant = fimc->variant;
  425. unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
  426. int ret = 0;
  427. if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
  428. return 0;
  429. switch (ctrl->id) {
  430. case V4L2_CID_HFLIP:
  431. ctx->hflip = ctrl->val;
  432. break;
  433. case V4L2_CID_VFLIP:
  434. ctx->vflip = ctrl->val;
  435. break;
  436. case V4L2_CID_ROTATE:
  437. if (fimc_capture_pending(fimc) ||
  438. (ctx->state & flags) == flags) {
  439. ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
  440. ctx->s_frame.height, ctx->d_frame.width,
  441. ctx->d_frame.height, ctrl->val);
  442. if (ret)
  443. return -EINVAL;
  444. }
  445. if ((ctrl->val == 90 || ctrl->val == 270) &&
  446. !variant->has_out_rot)
  447. return -EINVAL;
  448. ctx->rotation = ctrl->val;
  449. break;
  450. case V4L2_CID_ALPHA_COMPONENT:
  451. ctx->d_frame.alpha = ctrl->val;
  452. break;
  453. }
  454. ctx->state |= FIMC_PARAMS;
  455. set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
  456. return 0;
  457. }
  458. static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
  459. {
  460. struct fimc_ctx *ctx = ctrl_to_ctx(ctrl);
  461. unsigned long flags;
  462. int ret;
  463. spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
  464. ret = __fimc_s_ctrl(ctx, ctrl);
  465. spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
  466. return ret;
  467. }
  468. static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
  469. .s_ctrl = fimc_s_ctrl,
  470. };
  471. int fimc_ctrls_create(struct fimc_ctx *ctx)
  472. {
  473. struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
  474. unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
  475. if (ctx->ctrls_rdy)
  476. return 0;
  477. v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
  478. ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
  479. V4L2_CID_ROTATE, 0, 270, 90, 0);
  480. ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
  481. V4L2_CID_HFLIP, 0, 1, 1, 0);
  482. ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
  483. V4L2_CID_VFLIP, 0, 1, 1, 0);
  484. if (variant->has_alpha)
  485. ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
  486. &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
  487. 0, max_alpha, 1, 0);
  488. else
  489. ctx->ctrl_alpha = NULL;
  490. ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
  491. return ctx->ctrl_handler.error;
  492. }
  493. void fimc_ctrls_delete(struct fimc_ctx *ctx)
  494. {
  495. if (ctx->ctrls_rdy) {
  496. v4l2_ctrl_handler_free(&ctx->ctrl_handler);
  497. ctx->ctrls_rdy = false;
  498. ctx->ctrl_alpha = NULL;
  499. }
  500. }
  501. void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
  502. {
  503. unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
  504. if (!ctx->ctrls_rdy)
  505. return;
  506. mutex_lock(&ctx->ctrl_handler.lock);
  507. v4l2_ctrl_activate(ctx->ctrl_rotate, active);
  508. v4l2_ctrl_activate(ctx->ctrl_hflip, active);
  509. v4l2_ctrl_activate(ctx->ctrl_vflip, active);
  510. if (ctx->ctrl_alpha)
  511. v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha);
  512. if (active) {
  513. ctx->rotation = ctx->ctrl_rotate->val;
  514. ctx->hflip = ctx->ctrl_hflip->val;
  515. ctx->vflip = ctx->ctrl_vflip->val;
  516. } else {
  517. ctx->rotation = 0;
  518. ctx->hflip = 0;
  519. ctx->vflip = 0;
  520. }
  521. mutex_unlock(&ctx->ctrl_handler.lock);
  522. }
  523. /* Update maximum value of the alpha color control */
  524. void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
  525. {
  526. struct fimc_dev *fimc = ctx->fimc_dev;
  527. struct v4l2_ctrl *ctrl = ctx->ctrl_alpha;
  528. if (ctrl == NULL || !fimc->variant->has_alpha)
  529. return;
  530. v4l2_ctrl_lock(ctrl);
  531. ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt);
  532. if (ctrl->cur.val > ctrl->maximum)
  533. ctrl->cur.val = ctrl->maximum;
  534. v4l2_ctrl_unlock(ctrl);
  535. }
  536. int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
  537. {
  538. struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
  539. int i;
  540. pixm->width = frame->o_width;
  541. pixm->height = frame->o_height;
  542. pixm->field = V4L2_FIELD_NONE;
  543. pixm->pixelformat = frame->fmt->fourcc;
  544. pixm->colorspace = V4L2_COLORSPACE_JPEG;
  545. pixm->num_planes = frame->fmt->memplanes;
  546. for (i = 0; i < pixm->num_planes; ++i) {
  547. int bpl = frame->f_width;
  548. if (frame->fmt->colplanes == 1) /* packed formats */
  549. bpl = (bpl * frame->fmt->depth[0]) / 8;
  550. pixm->plane_fmt[i].bytesperline = bpl;
  551. pixm->plane_fmt[i].sizeimage = (frame->o_width *
  552. frame->o_height * frame->fmt->depth[i]) / 8;
  553. }
  554. return 0;
  555. }
  556. void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f)
  557. {
  558. struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
  559. frame->f_width = pixm->plane_fmt[0].bytesperline;
  560. if (frame->fmt->colplanes == 1)
  561. frame->f_width = (frame->f_width * 8) / frame->fmt->depth[0];
  562. frame->f_height = pixm->height;
  563. frame->width = pixm->width;
  564. frame->height = pixm->height;
  565. frame->o_width = pixm->width;
  566. frame->o_height = pixm->height;
  567. frame->offs_h = 0;
  568. frame->offs_v = 0;
  569. }
  570. /**
  571. * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane
  572. * @fmt: fimc pixel format description (input)
  573. * @width: requested pixel width
  574. * @height: requested pixel height
  575. * @pix: multi-plane format to adjust
  576. */
  577. void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
  578. struct v4l2_pix_format_mplane *pix)
  579. {
  580. u32 bytesperline = 0;
  581. int i;
  582. pix->colorspace = V4L2_COLORSPACE_JPEG;
  583. pix->field = V4L2_FIELD_NONE;
  584. pix->num_planes = fmt->memplanes;
  585. pix->pixelformat = fmt->fourcc;
  586. pix->height = height;
  587. pix->width = width;
  588. for (i = 0; i < pix->num_planes; ++i) {
  589. u32 bpl = pix->plane_fmt[i].bytesperline;
  590. u32 *sizeimage = &pix->plane_fmt[i].sizeimage;
  591. if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
  592. bpl = pix->width; /* Planar */
  593. if (fmt->colplanes == 1 && /* Packed */
  594. (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
  595. bpl = (pix->width * fmt->depth[0]) / 8;
  596. if (i == 0) /* Same bytesperline for each plane. */
  597. bytesperline = bpl;
  598. pix->plane_fmt[i].bytesperline = bytesperline;
  599. *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8;
  600. }
  601. }
  602. /**
  603. * fimc_find_format - lookup fimc color format by fourcc or media bus format
  604. * @pixelformat: fourcc to match, ignored if null
  605. * @mbus_code: media bus code to match, ignored if null
  606. * @mask: the color flags to match
  607. * @index: offset in the fimc_formats array, ignored if negative
  608. */
  609. struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
  610. unsigned int mask, int index)
  611. {
  612. struct fimc_fmt *fmt, *def_fmt = NULL;
  613. unsigned int i;
  614. int id = 0;
  615. if (index >= (int)ARRAY_SIZE(fimc_formats))
  616. return NULL;
  617. for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
  618. fmt = &fimc_formats[i];
  619. if (!(fmt->flags & mask))
  620. continue;
  621. if (pixelformat && fmt->fourcc == *pixelformat)
  622. return fmt;
  623. if (mbus_code && fmt->mbus_code == *mbus_code)
  624. return fmt;
  625. if (index == id)
  626. def_fmt = fmt;
  627. id++;
  628. }
  629. return def_fmt;
  630. }
  631. static void fimc_clk_put(struct fimc_dev *fimc)
  632. {
  633. int i;
  634. for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
  635. if (IS_ERR_OR_NULL(fimc->clock[i]))
  636. continue;
  637. clk_unprepare(fimc->clock[i]);
  638. clk_put(fimc->clock[i]);
  639. fimc->clock[i] = NULL;
  640. }
  641. }
  642. static int fimc_clk_get(struct fimc_dev *fimc)
  643. {
  644. int i, ret;
  645. for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
  646. fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
  647. if (IS_ERR(fimc->clock[i]))
  648. goto err;
  649. ret = clk_prepare(fimc->clock[i]);
  650. if (ret < 0) {
  651. clk_put(fimc->clock[i]);
  652. fimc->clock[i] = NULL;
  653. goto err;
  654. }
  655. }
  656. return 0;
  657. err:
  658. fimc_clk_put(fimc);
  659. dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
  660. fimc_clocks[i]);
  661. return -ENXIO;
  662. }
  663. static int fimc_m2m_suspend(struct fimc_dev *fimc)
  664. {
  665. unsigned long flags;
  666. int timeout;
  667. spin_lock_irqsave(&fimc->slock, flags);
  668. if (!fimc_m2m_pending(fimc)) {
  669. spin_unlock_irqrestore(&fimc->slock, flags);
  670. return 0;
  671. }
  672. clear_bit(ST_M2M_SUSPENDED, &fimc->state);
  673. set_bit(ST_M2M_SUSPENDING, &fimc->state);
  674. spin_unlock_irqrestore(&fimc->slock, flags);
  675. timeout = wait_event_timeout(fimc->irq_queue,
  676. test_bit(ST_M2M_SUSPENDED, &fimc->state),
  677. FIMC_SHUTDOWN_TIMEOUT);
  678. clear_bit(ST_M2M_SUSPENDING, &fimc->state);
  679. return timeout == 0 ? -EAGAIN : 0;
  680. }
  681. static int fimc_m2m_resume(struct fimc_dev *fimc)
  682. {
  683. unsigned long flags;
  684. spin_lock_irqsave(&fimc->slock, flags);
  685. /* Clear for full H/W setup in first run after resume */
  686. fimc->m2m.ctx = NULL;
  687. spin_unlock_irqrestore(&fimc->slock, flags);
  688. if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state))
  689. fimc_m2m_job_finish(fimc->m2m.ctx,
  690. VB2_BUF_STATE_ERROR);
  691. return 0;
  692. }
  693. static int fimc_probe(struct platform_device *pdev)
  694. {
  695. struct fimc_dev *fimc;
  696. struct resource *res;
  697. struct samsung_fimc_driverdata *drv_data;
  698. struct s5p_platform_fimc *pdata;
  699. int ret = 0;
  700. drv_data = (struct samsung_fimc_driverdata *)
  701. platform_get_device_id(pdev)->driver_data;
  702. if (pdev->id >= drv_data->num_entities) {
  703. dev_err(&pdev->dev, "Invalid platform device id: %d\n",
  704. pdev->id);
  705. return -EINVAL;
  706. }
  707. fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
  708. if (!fimc)
  709. return -ENOMEM;
  710. fimc->id = pdev->id;
  711. fimc->variant = drv_data->variant[fimc->id];
  712. fimc->pdev = pdev;
  713. pdata = pdev->dev.platform_data;
  714. fimc->pdata = pdata;
  715. init_waitqueue_head(&fimc->irq_queue);
  716. spin_lock_init(&fimc->slock);
  717. mutex_init(&fimc->lock);
  718. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  719. fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
  720. if (fimc->regs == NULL) {
  721. dev_err(&pdev->dev, "Failed to obtain io memory\n");
  722. return -ENOENT;
  723. }
  724. res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  725. if (res == NULL) {
  726. dev_err(&pdev->dev, "Failed to get IRQ resource\n");
  727. return -ENXIO;
  728. }
  729. ret = fimc_clk_get(fimc);
  730. if (ret)
  731. return ret;
  732. clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
  733. clk_enable(fimc->clock[CLK_BUS]);
  734. ret = devm_request_irq(&pdev->dev, res->start, fimc_irq_handler,
  735. 0, pdev->name, fimc);
  736. if (ret) {
  737. dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
  738. goto err_clk;
  739. }
  740. ret = fimc_initialize_capture_subdev(fimc);
  741. if (ret)
  742. goto err_clk;
  743. platform_set_drvdata(pdev, fimc);
  744. pm_runtime_enable(&pdev->dev);
  745. ret = pm_runtime_get_sync(&pdev->dev);
  746. if (ret < 0)
  747. goto err_sd;
  748. /* Initialize contiguous memory allocator */
  749. fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
  750. if (IS_ERR(fimc->alloc_ctx)) {
  751. ret = PTR_ERR(fimc->alloc_ctx);
  752. goto err_pm;
  753. }
  754. dev_dbg(&pdev->dev, "FIMC.%d registered successfully\n", fimc->id);
  755. pm_runtime_put(&pdev->dev);
  756. return 0;
  757. err_pm:
  758. pm_runtime_put(&pdev->dev);
  759. err_sd:
  760. fimc_unregister_capture_subdev(fimc);
  761. err_clk:
  762. fimc_clk_put(fimc);
  763. return ret;
  764. }
  765. static int fimc_runtime_resume(struct device *dev)
  766. {
  767. struct fimc_dev *fimc = dev_get_drvdata(dev);
  768. dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
  769. /* Enable clocks and perform basic initalization */
  770. clk_enable(fimc->clock[CLK_GATE]);
  771. fimc_hw_reset(fimc);
  772. /* Resume the capture or mem-to-mem device */
  773. if (fimc_capture_busy(fimc))
  774. return fimc_capture_resume(fimc);
  775. return fimc_m2m_resume(fimc);
  776. }
  777. static int fimc_runtime_suspend(struct device *dev)
  778. {
  779. struct fimc_dev *fimc = dev_get_drvdata(dev);
  780. int ret = 0;
  781. if (fimc_capture_busy(fimc))
  782. ret = fimc_capture_suspend(fimc);
  783. else
  784. ret = fimc_m2m_suspend(fimc);
  785. if (!ret)
  786. clk_disable(fimc->clock[CLK_GATE]);
  787. dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
  788. return ret;
  789. }
  790. #ifdef CONFIG_PM_SLEEP
  791. static int fimc_resume(struct device *dev)
  792. {
  793. struct fimc_dev *fimc = dev_get_drvdata(dev);
  794. unsigned long flags;
  795. dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
  796. /* Do not resume if the device was idle before system suspend */
  797. spin_lock_irqsave(&fimc->slock, flags);
  798. if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
  799. (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) {
  800. spin_unlock_irqrestore(&fimc->slock, flags);
  801. return 0;
  802. }
  803. fimc_hw_reset(fimc);
  804. spin_unlock_irqrestore(&fimc->slock, flags);
  805. if (fimc_capture_busy(fimc))
  806. return fimc_capture_resume(fimc);
  807. return fimc_m2m_resume(fimc);
  808. }
  809. static int fimc_suspend(struct device *dev)
  810. {
  811. struct fimc_dev *fimc = dev_get_drvdata(dev);
  812. dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state);
  813. if (test_and_set_bit(ST_LPM, &fimc->state))
  814. return 0;
  815. if (fimc_capture_busy(fimc))
  816. return fimc_capture_suspend(fimc);
  817. return fimc_m2m_suspend(fimc);
  818. }
  819. #endif /* CONFIG_PM_SLEEP */
  820. static int __devexit fimc_remove(struct platform_device *pdev)
  821. {
  822. struct fimc_dev *fimc = platform_get_drvdata(pdev);
  823. pm_runtime_disable(&pdev->dev);
  824. pm_runtime_set_suspended(&pdev->dev);
  825. fimc_unregister_capture_subdev(fimc);
  826. vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
  827. clk_disable(fimc->clock[CLK_BUS]);
  828. fimc_clk_put(fimc);
  829. dev_info(&pdev->dev, "driver unloaded\n");
  830. return 0;
  831. }
  832. /* Image pixel limits, similar across several FIMC HW revisions. */
  833. static struct fimc_pix_limit s5p_pix_limit[4] = {
  834. [0] = {
  835. .scaler_en_w = 3264,
  836. .scaler_dis_w = 8192,
  837. .in_rot_en_h = 1920,
  838. .in_rot_dis_w = 8192,
  839. .out_rot_en_w = 1920,
  840. .out_rot_dis_w = 4224,
  841. },
  842. [1] = {
  843. .scaler_en_w = 4224,
  844. .scaler_dis_w = 8192,
  845. .in_rot_en_h = 1920,
  846. .in_rot_dis_w = 8192,
  847. .out_rot_en_w = 1920,
  848. .out_rot_dis_w = 4224,
  849. },
  850. [2] = {
  851. .scaler_en_w = 1920,
  852. .scaler_dis_w = 8192,
  853. .in_rot_en_h = 1280,
  854. .in_rot_dis_w = 8192,
  855. .out_rot_en_w = 1280,
  856. .out_rot_dis_w = 1920,
  857. },
  858. [3] = {
  859. .scaler_en_w = 1920,
  860. .scaler_dis_w = 8192,
  861. .in_rot_en_h = 1366,
  862. .in_rot_dis_w = 8192,
  863. .out_rot_en_w = 1366,
  864. .out_rot_dis_w = 1920,
  865. },
  866. };
  867. static struct samsung_fimc_variant fimc0_variant_s5p = {
  868. .has_inp_rot = 1,
  869. .has_out_rot = 1,
  870. .has_cam_if = 1,
  871. .min_inp_pixsize = 16,
  872. .min_out_pixsize = 16,
  873. .hor_offs_align = 8,
  874. .min_vsize_align = 16,
  875. .out_buf_count = 4,
  876. .pix_limit = &s5p_pix_limit[0],
  877. };
  878. static struct samsung_fimc_variant fimc2_variant_s5p = {
  879. .has_cam_if = 1,
  880. .min_inp_pixsize = 16,
  881. .min_out_pixsize = 16,
  882. .hor_offs_align = 8,
  883. .min_vsize_align = 16,
  884. .out_buf_count = 4,
  885. .pix_limit = &s5p_pix_limit[1],
  886. };
  887. static struct samsung_fimc_variant fimc0_variant_s5pv210 = {
  888. .pix_hoff = 1,
  889. .has_inp_rot = 1,
  890. .has_out_rot = 1,
  891. .has_cam_if = 1,
  892. .min_inp_pixsize = 16,
  893. .min_out_pixsize = 16,
  894. .hor_offs_align = 8,
  895. .min_vsize_align = 16,
  896. .out_buf_count = 4,
  897. .pix_limit = &s5p_pix_limit[1],
  898. };
  899. static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
  900. .pix_hoff = 1,
  901. .has_inp_rot = 1,
  902. .has_out_rot = 1,
  903. .has_cam_if = 1,
  904. .has_mainscaler_ext = 1,
  905. .min_inp_pixsize = 16,
  906. .min_out_pixsize = 16,
  907. .hor_offs_align = 1,
  908. .min_vsize_align = 1,
  909. .out_buf_count = 4,
  910. .pix_limit = &s5p_pix_limit[2],
  911. };
  912. static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
  913. .has_cam_if = 1,
  914. .pix_hoff = 1,
  915. .min_inp_pixsize = 16,
  916. .min_out_pixsize = 16,
  917. .hor_offs_align = 8,
  918. .min_vsize_align = 16,
  919. .out_buf_count = 4,
  920. .pix_limit = &s5p_pix_limit[2],
  921. };
  922. static struct samsung_fimc_variant fimc0_variant_exynos4 = {
  923. .pix_hoff = 1,
  924. .has_inp_rot = 1,
  925. .has_out_rot = 1,
  926. .has_cam_if = 1,
  927. .has_cistatus2 = 1,
  928. .has_mainscaler_ext = 1,
  929. .has_alpha = 1,
  930. .min_inp_pixsize = 16,
  931. .min_out_pixsize = 16,
  932. .hor_offs_align = 2,
  933. .min_vsize_align = 1,
  934. .out_buf_count = 32,
  935. .pix_limit = &s5p_pix_limit[1],
  936. };
  937. static struct samsung_fimc_variant fimc3_variant_exynos4 = {
  938. .pix_hoff = 1,
  939. .has_cam_if = 1,
  940. .has_cistatus2 = 1,
  941. .has_mainscaler_ext = 1,
  942. .has_alpha = 1,
  943. .min_inp_pixsize = 16,
  944. .min_out_pixsize = 16,
  945. .hor_offs_align = 2,
  946. .min_vsize_align = 1,
  947. .out_buf_count = 32,
  948. .pix_limit = &s5p_pix_limit[3],
  949. };
  950. /* S5PC100 */
  951. static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
  952. .variant = {
  953. [0] = &fimc0_variant_s5p,
  954. [1] = &fimc0_variant_s5p,
  955. [2] = &fimc2_variant_s5p,
  956. },
  957. .num_entities = 3,
  958. .lclk_frequency = 133000000UL,
  959. };
  960. /* S5PV210, S5PC110 */
  961. static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
  962. .variant = {
  963. [0] = &fimc0_variant_s5pv210,
  964. [1] = &fimc1_variant_s5pv210,
  965. [2] = &fimc2_variant_s5pv210,
  966. },
  967. .num_entities = 3,
  968. .lclk_frequency = 166000000UL,
  969. };
  970. /* S5PV310, S5PC210 */
  971. static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = {
  972. .variant = {
  973. [0] = &fimc0_variant_exynos4,
  974. [1] = &fimc0_variant_exynos4,
  975. [2] = &fimc0_variant_exynos4,
  976. [3] = &fimc3_variant_exynos4,
  977. },
  978. .num_entities = 4,
  979. .lclk_frequency = 166000000UL,
  980. };
  981. static struct platform_device_id fimc_driver_ids[] = {
  982. {
  983. .name = "s5p-fimc",
  984. .driver_data = (unsigned long)&fimc_drvdata_s5p,
  985. }, {
  986. .name = "s5pv210-fimc",
  987. .driver_data = (unsigned long)&fimc_drvdata_s5pv210,
  988. }, {
  989. .name = "exynos4-fimc",
  990. .driver_data = (unsigned long)&fimc_drvdata_exynos4,
  991. },
  992. {},
  993. };
  994. MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
  995. static const struct dev_pm_ops fimc_pm_ops = {
  996. SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
  997. SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL)
  998. };
  999. static struct platform_driver fimc_driver = {
  1000. .probe = fimc_probe,
  1001. .remove = __devexit_p(fimc_remove),
  1002. .id_table = fimc_driver_ids,
  1003. .driver = {
  1004. .name = FIMC_MODULE_NAME,
  1005. .owner = THIS_MODULE,
  1006. .pm = &fimc_pm_ops,
  1007. }
  1008. };
  1009. int __init fimc_register_driver(void)
  1010. {
  1011. return platform_driver_register(&fimc_driver);
  1012. }
  1013. void __exit fimc_unregister_driver(void)
  1014. {
  1015. platform_driver_unregister(&fimc_driver);
  1016. }