gsc-core.c (32257B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd. 4 * http://www.samsung.com 5 * 6 * Samsung EXYNOS5 SoC series G-Scaler driver 7 */ 8 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/types.h> 12#include <linux/errno.h> 13#include <linux/bug.h> 14#include <linux/interrupt.h> 15#include <linux/workqueue.h> 16#include <linux/device.h> 17#include <linux/platform_device.h> 18#include <linux/list.h> 19#include <linux/io.h> 20#include <linux/slab.h> 21#include <linux/clk.h> 22#include <linux/of.h> 23#include <linux/of_device.h> 24#include <media/v4l2-ioctl.h> 25 26#include "gsc-core.h" 27 28static const struct gsc_fmt gsc_formats[] = { 29 { 30 .pixelformat = V4L2_PIX_FMT_RGB565X, 31 .depth = { 16 }, 32 .color = GSC_RGB, 33 .num_planes = 1, 34 .num_comp = 1, 35 }, { 36 .pixelformat = V4L2_PIX_FMT_BGR32, 37 .depth = { 32 }, 38 .color = GSC_RGB, 39 .num_planes = 1, 40 .num_comp = 1, 41 }, { 42 .pixelformat = V4L2_PIX_FMT_YUYV, 43 .depth = { 16 }, 44 .color = GSC_YUV422, 45 .yorder = GSC_LSB_Y, 46 .corder = GSC_CBCR, 47 .num_planes = 1, 48 .num_comp = 1, 49 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, 50 }, { 51 .pixelformat = V4L2_PIX_FMT_UYVY, 52 .depth = { 16 }, 53 .color = GSC_YUV422, 54 .yorder = GSC_LSB_C, 55 .corder = GSC_CBCR, 56 .num_planes = 1, 57 .num_comp = 1, 58 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, 59 }, { 60 .pixelformat = V4L2_PIX_FMT_VYUY, 61 .depth = { 16 }, 62 .color = GSC_YUV422, 63 .yorder = GSC_LSB_C, 64 .corder = GSC_CRCB, 65 .num_planes = 1, 66 .num_comp = 1, 67 .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, 68 }, { 69 .pixelformat = V4L2_PIX_FMT_YVYU, 70 .depth = { 16 }, 71 .color = GSC_YUV422, 72 .yorder = GSC_LSB_Y, 73 .corder = GSC_CRCB, 74 .num_planes = 1, 75 .num_comp = 1, 76 .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, 77 }, { 78 .pixelformat = V4L2_PIX_FMT_YUV32, 79 .depth = { 32 }, 80 .color = GSC_YUV444, 81 .yorder = GSC_LSB_Y, 82 .corder = GSC_CBCR, 83 .num_planes = 1, 84 .num_comp = 1, 85 }, { 86 .pixelformat = V4L2_PIX_FMT_YUV422P, 87 .depth = { 16 }, 88 .color = GSC_YUV422, 89 .yorder = GSC_LSB_Y, 90 .corder = GSC_CBCR, 91 .num_planes = 1, 92 .num_comp = 3, 93 }, { 94 .pixelformat = V4L2_PIX_FMT_NV16, 95 .depth = { 16 }, 96 .color = GSC_YUV422, 97 .yorder = GSC_LSB_Y, 98 .corder = GSC_CBCR, 99 .num_planes = 1, 100 .num_comp = 2, 101 }, { 102 .pixelformat = V4L2_PIX_FMT_NV16M, 103 .depth = { 8, 8 }, 104 .color = GSC_YUV422, 105 .yorder = GSC_LSB_Y, 106 .corder = GSC_CBCR, 107 .num_planes = 2, 108 .num_comp = 2, 109 }, { 110 .pixelformat = V4L2_PIX_FMT_NV61, 111 .depth = { 16 }, 112 .color = GSC_YUV422, 113 .yorder = GSC_LSB_Y, 114 .corder = GSC_CRCB, 115 .num_planes = 1, 116 .num_comp = 2, 117 }, { 118 .pixelformat = V4L2_PIX_FMT_NV61M, 119 .depth = { 8, 8 }, 120 .color = GSC_YUV422, 121 .yorder = GSC_LSB_Y, 122 .corder = GSC_CRCB, 123 .num_planes = 2, 124 .num_comp = 2, 125 }, { 126 .pixelformat = V4L2_PIX_FMT_YUV420, 127 .depth = { 12 }, 128 .color = GSC_YUV420, 129 .yorder = GSC_LSB_Y, 130 .corder = GSC_CBCR, 131 .num_planes = 1, 132 .num_comp = 3, 133 }, { 134 .pixelformat = V4L2_PIX_FMT_YVU420, 135 .depth = { 12 }, 136 .color = GSC_YUV420, 137 .yorder = GSC_LSB_Y, 138 .corder = GSC_CRCB, 139 .num_planes = 1, 140 .num_comp = 3, 141 142 }, { 143 .pixelformat = V4L2_PIX_FMT_NV12, 144 .depth = { 12 }, 145 .color = GSC_YUV420, 146 .yorder = GSC_LSB_Y, 147 .corder = GSC_CBCR, 148 .num_planes = 1, 149 .num_comp = 2, 150 }, { 151 .pixelformat = V4L2_PIX_FMT_NV21, 152 .depth = { 12 }, 153 .color = GSC_YUV420, 154 .yorder = GSC_LSB_Y, 155 .corder = GSC_CRCB, 156 .num_planes = 1, 157 .num_comp = 2, 158 }, { 159 .pixelformat = V4L2_PIX_FMT_NV21M, 160 .depth = { 8, 4 }, 161 .color = GSC_YUV420, 162 .yorder = GSC_LSB_Y, 163 .corder = GSC_CRCB, 164 .num_planes = 2, 165 .num_comp = 2, 166 }, { 167 .pixelformat = V4L2_PIX_FMT_NV12M, 168 .depth = { 8, 4 }, 169 .color = GSC_YUV420, 170 .yorder = GSC_LSB_Y, 171 .corder = GSC_CBCR, 172 .num_planes = 2, 173 .num_comp = 2, 174 }, { 175 .pixelformat = V4L2_PIX_FMT_YUV420M, 176 .depth = { 8, 2, 2 }, 177 .color = GSC_YUV420, 178 .yorder = GSC_LSB_Y, 179 .corder = GSC_CBCR, 180 .num_planes = 3, 181 .num_comp = 3, 182 }, { 183 .pixelformat = V4L2_PIX_FMT_YVU420M, 184 .depth = { 8, 2, 2 }, 185 .color = GSC_YUV420, 186 .yorder = GSC_LSB_Y, 187 .corder = GSC_CRCB, 188 .num_planes = 3, 189 .num_comp = 3, 190 }, { 191 .pixelformat = V4L2_PIX_FMT_NV12MT_16X16, 192 .depth = { 8, 4 }, 193 .color = GSC_YUV420, 194 .yorder = GSC_LSB_Y, 195 .corder = GSC_CBCR, 196 .num_planes = 2, 197 .num_comp = 2, 198 } 199}; 200 201const struct gsc_fmt *get_format(int index) 202{ 203 if (index >= ARRAY_SIZE(gsc_formats)) 204 return NULL; 205 206 return (struct gsc_fmt *)&gsc_formats[index]; 207} 208 209const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index) 210{ 211 const struct gsc_fmt *fmt, *def_fmt = NULL; 212 unsigned int i; 213 214 if (index >= ARRAY_SIZE(gsc_formats)) 215 return NULL; 216 217 for (i = 0; i < ARRAY_SIZE(gsc_formats); ++i) { 218 fmt = get_format(i); 219 if (pixelformat && fmt->pixelformat == *pixelformat) 220 return fmt; 221 if (mbus_code && fmt->mbus_code == *mbus_code) 222 return fmt; 223 if (index == i) 224 def_fmt = fmt; 225 } 226 return def_fmt; 227 228} 229 230void gsc_set_frame_size(struct gsc_frame *frame, int width, int height) 231{ 232 frame->f_width = width; 233 frame->f_height = height; 234 frame->crop.width = width; 235 frame->crop.height = height; 236 frame->crop.left = 0; 237 frame->crop.top = 0; 238} 239 240int gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst, 241 u32 *ratio) 242{ 243 if ((dst > src) || (dst >= src / var->poly_sc_down_max)) { 244 *ratio = 1; 245 return 0; 246 } 247 248 if ((src / var->poly_sc_down_max / var->pre_sc_down_max) > dst) { 249 pr_err("Exceeded maximum downscaling ratio (1/16))"); 250 return -EINVAL; 251 } 252 253 *ratio = (dst > (src / 8)) ? 2 : 4; 254 255 return 0; 256} 257 258void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh) 259{ 260 if (hratio == 4 && vratio == 4) 261 *sh = 4; 262 else if ((hratio == 4 && vratio == 2) || 263 (hratio == 2 && vratio == 4)) 264 *sh = 3; 265 else if ((hratio == 4 && vratio == 1) || 266 (hratio == 1 && vratio == 4) || 267 (hratio == 2 && vratio == 2)) 268 *sh = 2; 269 else if (hratio == 1 && vratio == 1) 270 *sh = 0; 271 else 272 *sh = 1; 273} 274 275void gsc_check_src_scale_info(struct gsc_variant *var, 276 struct gsc_frame *s_frame, u32 *wratio, 277 u32 tx, u32 ty, u32 *hratio) 278{ 279 int remainder = 0, walign, halign; 280 281 if (is_yuv420(s_frame->fmt->color)) { 282 walign = GSC_SC_ALIGN_4; 283 halign = GSC_SC_ALIGN_4; 284 } else if (is_yuv422(s_frame->fmt->color)) { 285 walign = GSC_SC_ALIGN_4; 286 halign = GSC_SC_ALIGN_2; 287 } else { 288 walign = GSC_SC_ALIGN_2; 289 halign = GSC_SC_ALIGN_2; 290 } 291 292 remainder = s_frame->crop.width % (*wratio * walign); 293 if (remainder) { 294 s_frame->crop.width -= remainder; 295 gsc_cal_prescaler_ratio(var, s_frame->crop.width, tx, wratio); 296 pr_info("cropped src width size is recalculated from %d to %d", 297 s_frame->crop.width + remainder, s_frame->crop.width); 298 } 299 300 remainder = s_frame->crop.height % (*hratio * halign); 301 if (remainder) { 302 s_frame->crop.height -= remainder; 303 gsc_cal_prescaler_ratio(var, s_frame->crop.height, ty, hratio); 304 pr_info("cropped src height size is recalculated from %d to %d", 305 s_frame->crop.height + remainder, s_frame->crop.height); 306 } 307} 308 309int gsc_enum_fmt(struct v4l2_fmtdesc *f) 310{ 311 const struct gsc_fmt *fmt; 312 313 fmt = find_fmt(NULL, NULL, f->index); 314 if (!fmt) 315 return -EINVAL; 316 317 f->pixelformat = fmt->pixelformat; 318 319 return 0; 320} 321 322static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_addr) 323{ 324 if (frm->addr.y == addr) { 325 *index = 0; 326 *ret_addr = frm->addr.y; 327 } else if (frm->addr.cb == addr) { 328 *index = 1; 329 *ret_addr = frm->addr.cb; 330 } else if (frm->addr.cr == addr) { 331 *index = 2; 332 *ret_addr = frm->addr.cr; 333 } else { 334 pr_err("Plane address is wrong"); 335 return -EINVAL; 336 } 337 return 0; 338} 339 340void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm) 341{ 342 u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len; 343 f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0; 344 345 f_chk_addr = frm->addr.y; 346 f_chk_len = frm->payload[0]; 347 if (frm->fmt->num_planes == 2) { 348 s_chk_addr = frm->addr.cb; 349 s_chk_len = frm->payload[1]; 350 } else if (frm->fmt->num_planes == 3) { 351 u32 low_addr, low_plane, mid_addr, mid_plane; 352 u32 high_addr, high_plane; 353 u32 t_min, t_max; 354 355 t_min = min3(frm->addr.y, frm->addr.cb, frm->addr.cr); 356 if (get_plane_info(frm, t_min, &low_plane, &low_addr)) 357 return; 358 t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr); 359 if (get_plane_info(frm, t_max, &high_plane, &high_addr)) 360 return; 361 362 mid_plane = 3 - (low_plane + high_plane); 363 if (mid_plane == 0) 364 mid_addr = frm->addr.y; 365 else if (mid_plane == 1) 366 mid_addr = frm->addr.cb; 367 else if (mid_plane == 2) 368 mid_addr = frm->addr.cr; 369 else 370 return; 371 372 f_chk_addr = low_addr; 373 if (mid_addr + frm->payload[mid_plane] - low_addr > 374 high_addr + frm->payload[high_plane] - mid_addr) { 375 f_chk_len = frm->payload[low_plane]; 376 s_chk_addr = mid_addr; 377 s_chk_len = high_addr + 378 frm->payload[high_plane] - mid_addr; 379 } else { 380 f_chk_len = mid_addr + 381 frm->payload[mid_plane] - low_addr; 382 s_chk_addr = high_addr; 383 s_chk_len = frm->payload[high_plane]; 384 } 385 } 386 pr_debug("f_addr = 0x%08x, f_len = %d, s_addr = 0x%08x, s_len = %d\n", 387 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len); 388} 389 390int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f) 391{ 392 struct gsc_dev *gsc = ctx->gsc_dev; 393 struct gsc_variant *variant = gsc->variant; 394 struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 395 const struct gsc_fmt *fmt; 396 u32 max_w, max_h, mod_x, mod_y; 397 u32 min_w, min_h, tmp_w, tmp_h; 398 int i; 399 400 pr_debug("user put w: %d, h: %d", pix_mp->width, pix_mp->height); 401 402 fmt = find_fmt(&pix_mp->pixelformat, NULL, 0); 403 if (!fmt) { 404 pr_err("pixelformat format (0x%X) invalid\n", 405 pix_mp->pixelformat); 406 return -EINVAL; 407 } 408 409 if (pix_mp->field == V4L2_FIELD_ANY) 410 pix_mp->field = V4L2_FIELD_NONE; 411 else if (pix_mp->field != V4L2_FIELD_NONE) { 412 pr_debug("Not supported field order(%d)\n", pix_mp->field); 413 return -EINVAL; 414 } 415 416 max_w = variant->pix_max->target_rot_dis_w; 417 max_h = variant->pix_max->target_rot_dis_h; 418 419 mod_x = ffs(variant->pix_align->org_w) - 1; 420 if (is_yuv420(fmt->color)) 421 mod_y = ffs(variant->pix_align->org_h) - 1; 422 else 423 mod_y = ffs(variant->pix_align->org_h) - 2; 424 425 if (V4L2_TYPE_IS_OUTPUT(f->type)) { 426 min_w = variant->pix_min->org_w; 427 min_h = variant->pix_min->org_h; 428 } else { 429 min_w = variant->pix_min->target_rot_dis_w; 430 min_h = variant->pix_min->target_rot_dis_h; 431 pix_mp->colorspace = ctx->out_colorspace; 432 } 433 434 pr_debug("mod_x: %d, mod_y: %d, max_w: %d, max_h = %d", 435 mod_x, mod_y, max_w, max_h); 436 437 /* To check if image size is modified to adjust parameter against 438 hardware abilities */ 439 tmp_w = pix_mp->width; 440 tmp_h = pix_mp->height; 441 442 v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_x, 443 &pix_mp->height, min_h, max_h, mod_y, 0); 444 if (tmp_w != pix_mp->width || tmp_h != pix_mp->height) 445 pr_debug("Image size has been modified from %dx%d to %dx%d\n", 446 tmp_w, tmp_h, pix_mp->width, pix_mp->height); 447 448 pix_mp->num_planes = fmt->num_planes; 449 450 if (V4L2_TYPE_IS_OUTPUT(f->type)) 451 ctx->out_colorspace = pix_mp->colorspace; 452 453 for (i = 0; i < pix_mp->num_planes; ++i) { 454 struct v4l2_plane_pix_format *plane_fmt = &pix_mp->plane_fmt[i]; 455 u32 bpl = plane_fmt->bytesperline; 456 457 if (fmt->num_comp == 1 && /* Packed */ 458 (bpl == 0 || (bpl * 8 / fmt->depth[i]) < pix_mp->width)) 459 bpl = pix_mp->width * fmt->depth[i] / 8; 460 461 if (fmt->num_comp > 1 && /* Planar */ 462 (bpl == 0 || bpl < pix_mp->width)) 463 bpl = pix_mp->width; 464 465 if (i != 0 && fmt->num_comp == 3) 466 bpl /= 2; 467 468 plane_fmt->bytesperline = bpl; 469 plane_fmt->sizeimage = max(pix_mp->width * pix_mp->height * 470 fmt->depth[i] / 8, 471 plane_fmt->sizeimage); 472 pr_debug("[%d]: bpl: %d, sizeimage: %d", 473 i, bpl, pix_mp->plane_fmt[i].sizeimage); 474 } 475 476 return 0; 477} 478 479int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f) 480{ 481 struct gsc_frame *frame; 482 struct v4l2_pix_format_mplane *pix_mp; 483 int i; 484 485 frame = ctx_get_frame(ctx, f->type); 486 if (IS_ERR(frame)) 487 return PTR_ERR(frame); 488 489 pix_mp = &f->fmt.pix_mp; 490 491 pix_mp->width = frame->f_width; 492 pix_mp->height = frame->f_height; 493 pix_mp->field = V4L2_FIELD_NONE; 494 pix_mp->pixelformat = frame->fmt->pixelformat; 495 pix_mp->num_planes = frame->fmt->num_planes; 496 pix_mp->colorspace = ctx->out_colorspace; 497 498 for (i = 0; i < pix_mp->num_planes; ++i) { 499 pix_mp->plane_fmt[i].bytesperline = (frame->f_width * 500 frame->fmt->depth[i]) / 8; 501 pix_mp->plane_fmt[i].sizeimage = 502 pix_mp->plane_fmt[i].bytesperline * frame->f_height; 503 } 504 505 return 0; 506} 507 508void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h) 509{ 510 if (tmp_w != *w || tmp_h != *h) { 511 pr_info("Cropped size has been modified from %dx%d to %dx%d", 512 *w, *h, tmp_w, tmp_h); 513 *w = tmp_w; 514 *h = tmp_h; 515 } 516} 517 518int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s) 519{ 520 struct gsc_frame *f; 521 struct gsc_dev *gsc = ctx->gsc_dev; 522 struct gsc_variant *variant = gsc->variant; 523 u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h; 524 u32 min_w, min_h, max_w, max_h; 525 526 if (s->r.top < 0 || s->r.left < 0) { 527 pr_err("doesn't support negative values for top & left\n"); 528 return -EINVAL; 529 } 530 pr_debug("user put w: %d, h: %d", s->r.width, s->r.height); 531 532 if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 533 f = &ctx->d_frame; 534 else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 535 f = &ctx->s_frame; 536 else 537 return -EINVAL; 538 539 max_w = f->f_width; 540 max_h = f->f_height; 541 tmp_w = s->r.width; 542 tmp_h = s->r.height; 543 544 if (V4L2_TYPE_IS_OUTPUT(s->type)) { 545 if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 1) || 546 is_rgb(f->fmt->color)) 547 min_w = 32; 548 else 549 min_w = 64; 550 if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 3) || 551 is_yuv420(f->fmt->color)) 552 min_h = 32; 553 else 554 min_h = 16; 555 } else { 556 if (is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) 557 mod_x = ffs(variant->pix_align->target_w) - 1; 558 if (is_yuv420(f->fmt->color)) 559 mod_y = ffs(variant->pix_align->target_h) - 1; 560 if (ctx->gsc_ctrls.rotate->val == 90 || 561 ctx->gsc_ctrls.rotate->val == 270) { 562 max_w = f->f_height; 563 max_h = f->f_width; 564 min_w = variant->pix_min->target_rot_en_w; 565 min_h = variant->pix_min->target_rot_en_h; 566 tmp_w = s->r.height; 567 tmp_h = s->r.width; 568 } else { 569 min_w = variant->pix_min->target_rot_dis_w; 570 min_h = variant->pix_min->target_rot_dis_h; 571 } 572 } 573 pr_debug("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d", 574 mod_x, mod_y, min_w, min_h); 575 pr_debug("tmp_w : %d, tmp_h : %d", tmp_w, tmp_h); 576 577 v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x, 578 &tmp_h, min_h, max_h, mod_y, 0); 579 580 if (V4L2_TYPE_IS_CAPTURE(s->type) && 581 (ctx->gsc_ctrls.rotate->val == 90 || 582 ctx->gsc_ctrls.rotate->val == 270)) 583 gsc_check_crop_change(tmp_h, tmp_w, 584 &s->r.width, &s->r.height); 585 else 586 gsc_check_crop_change(tmp_w, tmp_h, 587 &s->r.width, &s->r.height); 588 589 590 /* adjust left/top if cropping rectangle is out of bounds */ 591 /* Need to add code to algin left value with 2's multiple */ 592 if (s->r.left + tmp_w > max_w) 593 s->r.left = max_w - tmp_w; 594 if (s->r.top + tmp_h > max_h) 595 s->r.top = max_h - tmp_h; 596 597 if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) && 598 s->r.left & 1) 599 s->r.left -= 1; 600 601 pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", 602 s->r.left, s->r.top, s->r.width, s->r.height, max_w, max_h); 603 604 return 0; 605} 606 607int gsc_check_scaler_ratio(struct gsc_variant *var, int sw, int sh, int dw, 608 int dh, int rot, int out_path) 609{ 610 int tmp_w, tmp_h, sc_down_max; 611 612 if (out_path == GSC_DMA) 613 sc_down_max = var->sc_down_max; 614 else 615 sc_down_max = var->local_sc_down; 616 617 if (rot == 90 || rot == 270) { 618 tmp_w = dh; 619 tmp_h = dw; 620 } else { 621 tmp_w = dw; 622 tmp_h = dh; 623 } 624 625 if ((sw / tmp_w) > sc_down_max || 626 (sh / tmp_h) > sc_down_max || 627 (tmp_w / sw) > var->sc_up_max || 628 (tmp_h / sh) > var->sc_up_max) 629 return -EINVAL; 630 631 return 0; 632} 633 634int gsc_set_scaler_info(struct gsc_ctx *ctx) 635{ 636 struct gsc_scaler *sc = &ctx->scaler; 637 struct gsc_frame *s_frame = &ctx->s_frame; 638 struct gsc_frame *d_frame = &ctx->d_frame; 639 struct gsc_variant *variant = ctx->gsc_dev->variant; 640 struct device *dev = &ctx->gsc_dev->pdev->dev; 641 int tx, ty; 642 int ret; 643 644 ret = gsc_check_scaler_ratio(variant, s_frame->crop.width, 645 s_frame->crop.height, d_frame->crop.width, d_frame->crop.height, 646 ctx->gsc_ctrls.rotate->val, ctx->out_path); 647 if (ret) { 648 pr_err("out of scaler range"); 649 return ret; 650 } 651 652 if (ctx->gsc_ctrls.rotate->val == 90 || 653 ctx->gsc_ctrls.rotate->val == 270) { 654 ty = d_frame->crop.width; 655 tx = d_frame->crop.height; 656 } else { 657 tx = d_frame->crop.width; 658 ty = d_frame->crop.height; 659 } 660 661 if (tx <= 0 || ty <= 0) { 662 dev_err(dev, "Invalid target size: %dx%d", tx, ty); 663 return -EINVAL; 664 } 665 666 ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.width, 667 tx, &sc->pre_hratio); 668 if (ret) { 669 pr_err("Horizontal scale ratio is out of range"); 670 return ret; 671 } 672 673 ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.height, 674 ty, &sc->pre_vratio); 675 if (ret) { 676 pr_err("Vertical scale ratio is out of range"); 677 return ret; 678 } 679 680 gsc_check_src_scale_info(variant, s_frame, &sc->pre_hratio, 681 tx, ty, &sc->pre_vratio); 682 683 gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio, 684 &sc->pre_shfactor); 685 686 sc->main_hratio = (s_frame->crop.width << 16) / tx; 687 sc->main_vratio = (s_frame->crop.height << 16) / ty; 688 689 pr_debug("scaler input/output size : sx = %d, sy = %d, tx = %d, ty = %d", 690 s_frame->crop.width, s_frame->crop.height, tx, ty); 691 pr_debug("scaler ratio info : pre_shfactor : %d, pre_h : %d", 692 sc->pre_shfactor, sc->pre_hratio); 693 pr_debug("pre_v :%d, main_h : %d, main_v : %d", 694 sc->pre_vratio, sc->main_hratio, sc->main_vratio); 695 696 return 0; 697} 698 699static int __gsc_s_ctrl(struct gsc_ctx *ctx, struct v4l2_ctrl *ctrl) 700{ 701 struct gsc_dev *gsc = ctx->gsc_dev; 702 struct gsc_variant *variant = gsc->variant; 703 unsigned int flags = GSC_DST_FMT | GSC_SRC_FMT; 704 int ret = 0; 705 706 if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) 707 return 0; 708 709 switch (ctrl->id) { 710 case V4L2_CID_HFLIP: 711 ctx->hflip = ctrl->val; 712 break; 713 714 case V4L2_CID_VFLIP: 715 ctx->vflip = ctrl->val; 716 break; 717 718 case V4L2_CID_ROTATE: 719 if ((ctx->state & flags) == flags) { 720 ret = gsc_check_scaler_ratio(variant, 721 ctx->s_frame.crop.width, 722 ctx->s_frame.crop.height, 723 ctx->d_frame.crop.width, 724 ctx->d_frame.crop.height, 725 ctx->gsc_ctrls.rotate->val, 726 ctx->out_path); 727 728 if (ret) 729 return -EINVAL; 730 } 731 732 ctx->rotation = ctrl->val; 733 break; 734 735 case V4L2_CID_ALPHA_COMPONENT: 736 ctx->d_frame.alpha = ctrl->val; 737 break; 738 } 739 740 ctx->state |= GSC_PARAMS; 741 return 0; 742} 743 744static int gsc_s_ctrl(struct v4l2_ctrl *ctrl) 745{ 746 struct gsc_ctx *ctx = ctrl_to_ctx(ctrl); 747 unsigned long flags; 748 int ret; 749 750 spin_lock_irqsave(&ctx->gsc_dev->slock, flags); 751 ret = __gsc_s_ctrl(ctx, ctrl); 752 spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags); 753 754 return ret; 755} 756 757static const struct v4l2_ctrl_ops gsc_ctrl_ops = { 758 .s_ctrl = gsc_s_ctrl, 759}; 760 761int gsc_ctrls_create(struct gsc_ctx *ctx) 762{ 763 if (ctx->ctrls_rdy) { 764 pr_err("Control handler of this context was created already"); 765 return 0; 766 } 767 768 v4l2_ctrl_handler_init(&ctx->ctrl_handler, GSC_MAX_CTRL_NUM); 769 770 ctx->gsc_ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, 771 &gsc_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0); 772 ctx->gsc_ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, 773 &gsc_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); 774 ctx->gsc_ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, 775 &gsc_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); 776 ctx->gsc_ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler, 777 &gsc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0); 778 779 ctx->ctrls_rdy = ctx->ctrl_handler.error == 0; 780 781 if (ctx->ctrl_handler.error) { 782 int err = ctx->ctrl_handler.error; 783 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 784 pr_err("Failed to create G-Scaler control handlers"); 785 return err; 786 } 787 788 return 0; 789} 790 791void gsc_ctrls_delete(struct gsc_ctx *ctx) 792{ 793 if (ctx->ctrls_rdy) { 794 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 795 ctx->ctrls_rdy = false; 796 } 797} 798 799/* The color format (num_comp, num_planes) must be already configured. */ 800int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb, 801 struct gsc_frame *frame, struct gsc_addr *addr) 802{ 803 int ret = 0; 804 u32 pix_size; 805 806 if ((vb == NULL) || (frame == NULL)) 807 return -EINVAL; 808 809 pix_size = frame->f_width * frame->f_height; 810 811 pr_debug("num_planes= %d, num_comp= %d, pix_size= %d", 812 frame->fmt->num_planes, frame->fmt->num_comp, pix_size); 813 814 addr->y = vb2_dma_contig_plane_dma_addr(vb, 0); 815 816 if (frame->fmt->num_planes == 1) { 817 switch (frame->fmt->num_comp) { 818 case 1: 819 addr->cb = 0; 820 addr->cr = 0; 821 break; 822 case 2: 823 /* decompose Y into Y/Cb */ 824 addr->cb = (dma_addr_t)(addr->y + pix_size); 825 addr->cr = 0; 826 break; 827 case 3: 828 /* decompose Y into Y/Cb/Cr */ 829 addr->cb = (dma_addr_t)(addr->y + pix_size); 830 if (GSC_YUV420 == frame->fmt->color) 831 addr->cr = (dma_addr_t)(addr->cb 832 + (pix_size >> 2)); 833 else /* 422 */ 834 addr->cr = (dma_addr_t)(addr->cb 835 + (pix_size >> 1)); 836 break; 837 default: 838 pr_err("Invalid the number of color planes"); 839 return -EINVAL; 840 } 841 } else { 842 if (frame->fmt->num_planes >= 2) 843 addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); 844 845 if (frame->fmt->num_planes == 3) 846 addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2); 847 } 848 849 if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) || 850 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) || 851 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) || 852 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M)) 853 swap(addr->cb, addr->cr); 854 855 pr_debug("ADDR: y= %pad cb= %pad cr= %pad ret= %d", 856 &addr->y, &addr->cb, &addr->cr, ret); 857 858 return ret; 859} 860 861static irqreturn_t gsc_irq_handler(int irq, void *priv) 862{ 863 struct gsc_dev *gsc = priv; 864 struct gsc_ctx *ctx; 865 int gsc_irq; 866 867 gsc_irq = gsc_hw_get_irq_status(gsc); 868 gsc_hw_clear_irq(gsc, gsc_irq); 869 870 if (gsc_irq == GSC_IRQ_OVERRUN) { 871 pr_err("Local path input over-run interrupt has occurred!\n"); 872 return IRQ_HANDLED; 873 } 874 875 spin_lock(&gsc->slock); 876 877 if (test_and_clear_bit(ST_M2M_PEND, &gsc->state)) { 878 879 gsc_hw_enable_control(gsc, false); 880 881 if (test_and_clear_bit(ST_M2M_SUSPENDING, &gsc->state)) { 882 set_bit(ST_M2M_SUSPENDED, &gsc->state); 883 wake_up(&gsc->irq_queue); 884 goto isr_unlock; 885 } 886 ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev); 887 888 if (!ctx || !ctx->m2m_ctx) 889 goto isr_unlock; 890 891 spin_unlock(&gsc->slock); 892 gsc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); 893 894 /* wake_up job_abort, stop_streaming */ 895 if (ctx->state & GSC_CTX_STOP_REQ) { 896 ctx->state &= ~GSC_CTX_STOP_REQ; 897 wake_up(&gsc->irq_queue); 898 } 899 return IRQ_HANDLED; 900 } 901 902isr_unlock: 903 spin_unlock(&gsc->slock); 904 return IRQ_HANDLED; 905} 906 907static struct gsc_pix_max gsc_v_100_max = { 908 .org_scaler_bypass_w = 8192, 909 .org_scaler_bypass_h = 8192, 910 .org_scaler_input_w = 4800, 911 .org_scaler_input_h = 3344, 912 .real_rot_dis_w = 4800, 913 .real_rot_dis_h = 3344, 914 .real_rot_en_w = 2047, 915 .real_rot_en_h = 2047, 916 .target_rot_dis_w = 4800, 917 .target_rot_dis_h = 3344, 918 .target_rot_en_w = 2016, 919 .target_rot_en_h = 2016, 920}; 921 922static struct gsc_pix_max gsc_v_5250_max = { 923 .org_scaler_bypass_w = 8192, 924 .org_scaler_bypass_h = 8192, 925 .org_scaler_input_w = 4800, 926 .org_scaler_input_h = 3344, 927 .real_rot_dis_w = 4800, 928 .real_rot_dis_h = 3344, 929 .real_rot_en_w = 2016, 930 .real_rot_en_h = 2016, 931 .target_rot_dis_w = 4800, 932 .target_rot_dis_h = 3344, 933 .target_rot_en_w = 2016, 934 .target_rot_en_h = 2016, 935}; 936 937static struct gsc_pix_max gsc_v_5420_max = { 938 .org_scaler_bypass_w = 8192, 939 .org_scaler_bypass_h = 8192, 940 .org_scaler_input_w = 4800, 941 .org_scaler_input_h = 3344, 942 .real_rot_dis_w = 4800, 943 .real_rot_dis_h = 3344, 944 .real_rot_en_w = 2048, 945 .real_rot_en_h = 2048, 946 .target_rot_dis_w = 4800, 947 .target_rot_dis_h = 3344, 948 .target_rot_en_w = 2016, 949 .target_rot_en_h = 2016, 950}; 951 952static struct gsc_pix_max gsc_v_5433_max = { 953 .org_scaler_bypass_w = 8192, 954 .org_scaler_bypass_h = 8192, 955 .org_scaler_input_w = 4800, 956 .org_scaler_input_h = 3344, 957 .real_rot_dis_w = 4800, 958 .real_rot_dis_h = 3344, 959 .real_rot_en_w = 2047, 960 .real_rot_en_h = 2047, 961 .target_rot_dis_w = 4800, 962 .target_rot_dis_h = 3344, 963 .target_rot_en_w = 2016, 964 .target_rot_en_h = 2016, 965}; 966 967static struct gsc_pix_min gsc_v_100_min = { 968 .org_w = 64, 969 .org_h = 32, 970 .real_w = 64, 971 .real_h = 32, 972 .target_rot_dis_w = 64, 973 .target_rot_dis_h = 32, 974 .target_rot_en_w = 32, 975 .target_rot_en_h = 16, 976}; 977 978static struct gsc_pix_align gsc_v_100_align = { 979 .org_h = 16, 980 .org_w = 16, /* yuv420 : 16, others : 8 */ 981 .offset_h = 2, /* yuv420/422 : 2, others : 1 */ 982 .real_w = 16, /* yuv420/422 : 4~16, others : 2~8 */ 983 .real_h = 16, /* yuv420 : 4~16, others : 1 */ 984 .target_w = 2, /* yuv420/422 : 2, others : 1 */ 985 .target_h = 2, /* yuv420 : 2, others : 1 */ 986}; 987 988static struct gsc_variant gsc_v_100_variant = { 989 .pix_max = &gsc_v_100_max, 990 .pix_min = &gsc_v_100_min, 991 .pix_align = &gsc_v_100_align, 992 .in_buf_cnt = 32, 993 .out_buf_cnt = 32, 994 .sc_up_max = 8, 995 .sc_down_max = 16, 996 .poly_sc_down_max = 4, 997 .pre_sc_down_max = 4, 998 .local_sc_down = 2, 999}; 1000 1001static struct gsc_variant gsc_v_5250_variant = { 1002 .pix_max = &gsc_v_5250_max, 1003 .pix_min = &gsc_v_100_min, 1004 .pix_align = &gsc_v_100_align, 1005 .in_buf_cnt = 32, 1006 .out_buf_cnt = 32, 1007 .sc_up_max = 8, 1008 .sc_down_max = 16, 1009 .poly_sc_down_max = 4, 1010 .pre_sc_down_max = 4, 1011 .local_sc_down = 2, 1012}; 1013 1014static struct gsc_variant gsc_v_5420_variant = { 1015 .pix_max = &gsc_v_5420_max, 1016 .pix_min = &gsc_v_100_min, 1017 .pix_align = &gsc_v_100_align, 1018 .in_buf_cnt = 32, 1019 .out_buf_cnt = 32, 1020 .sc_up_max = 8, 1021 .sc_down_max = 16, 1022 .poly_sc_down_max = 4, 1023 .pre_sc_down_max = 4, 1024 .local_sc_down = 2, 1025}; 1026 1027static struct gsc_variant gsc_v_5433_variant = { 1028 .pix_max = &gsc_v_5433_max, 1029 .pix_min = &gsc_v_100_min, 1030 .pix_align = &gsc_v_100_align, 1031 .in_buf_cnt = 32, 1032 .out_buf_cnt = 32, 1033 .sc_up_max = 8, 1034 .sc_down_max = 16, 1035 .poly_sc_down_max = 4, 1036 .pre_sc_down_max = 4, 1037 .local_sc_down = 2, 1038}; 1039 1040static struct gsc_driverdata gsc_v_100_drvdata = { 1041 .variant = { 1042 [0] = &gsc_v_100_variant, 1043 [1] = &gsc_v_100_variant, 1044 [2] = &gsc_v_100_variant, 1045 [3] = &gsc_v_100_variant, 1046 }, 1047 .num_entities = 4, 1048 .clk_names = { "gscl" }, 1049 .num_clocks = 1, 1050}; 1051 1052static struct gsc_driverdata gsc_v_5250_drvdata = { 1053 .variant = { 1054 [0] = &gsc_v_5250_variant, 1055 [1] = &gsc_v_5250_variant, 1056 [2] = &gsc_v_5250_variant, 1057 [3] = &gsc_v_5250_variant, 1058 }, 1059 .num_entities = 4, 1060 .clk_names = { "gscl" }, 1061 .num_clocks = 1, 1062}; 1063 1064static struct gsc_driverdata gsc_v_5420_drvdata = { 1065 .variant = { 1066 [0] = &gsc_v_5420_variant, 1067 [1] = &gsc_v_5420_variant, 1068 }, 1069 .num_entities = 2, 1070 .clk_names = { "gscl" }, 1071 .num_clocks = 1, 1072}; 1073 1074static struct gsc_driverdata gsc_5433_drvdata = { 1075 .variant = { 1076 [0] = &gsc_v_5433_variant, 1077 [1] = &gsc_v_5433_variant, 1078 [2] = &gsc_v_5433_variant, 1079 }, 1080 .num_entities = 3, 1081 .clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" }, 1082 .num_clocks = 4, 1083}; 1084 1085static const struct of_device_id exynos_gsc_match[] = { 1086 { 1087 .compatible = "samsung,exynos5250-gsc", 1088 .data = &gsc_v_5250_drvdata, 1089 }, 1090 { 1091 .compatible = "samsung,exynos5420-gsc", 1092 .data = &gsc_v_5420_drvdata, 1093 }, 1094 { 1095 .compatible = "samsung,exynos5433-gsc", 1096 .data = &gsc_5433_drvdata, 1097 }, 1098 { 1099 .compatible = "samsung,exynos5-gsc", 1100 .data = &gsc_v_100_drvdata, 1101 }, 1102 {}, 1103}; 1104MODULE_DEVICE_TABLE(of, exynos_gsc_match); 1105 1106static int gsc_probe(struct platform_device *pdev) 1107{ 1108 struct gsc_dev *gsc; 1109 struct device *dev = &pdev->dev; 1110 const struct gsc_driverdata *drv_data = of_device_get_match_data(dev); 1111 int irq; 1112 int ret; 1113 int i; 1114 1115 gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL); 1116 if (!gsc) 1117 return -ENOMEM; 1118 1119 ret = of_alias_get_id(pdev->dev.of_node, "gsc"); 1120 if (ret < 0) 1121 return ret; 1122 1123 if (drv_data == &gsc_v_100_drvdata) 1124 dev_info(dev, "compatible 'exynos5-gsc' is deprecated\n"); 1125 1126 gsc->id = ret; 1127 if (gsc->id >= drv_data->num_entities) { 1128 dev_err(dev, "Invalid platform device id: %d\n", gsc->id); 1129 return -EINVAL; 1130 } 1131 1132 gsc->num_clocks = drv_data->num_clocks; 1133 gsc->variant = drv_data->variant[gsc->id]; 1134 gsc->pdev = pdev; 1135 1136 init_waitqueue_head(&gsc->irq_queue); 1137 spin_lock_init(&gsc->slock); 1138 mutex_init(&gsc->lock); 1139 1140 gsc->regs = devm_platform_ioremap_resource(pdev, 0); 1141 if (IS_ERR(gsc->regs)) 1142 return PTR_ERR(gsc->regs); 1143 1144 irq = platform_get_irq(pdev, 0); 1145 if (irq < 0) 1146 return irq; 1147 1148 for (i = 0; i < gsc->num_clocks; i++) { 1149 gsc->clock[i] = devm_clk_get(dev, drv_data->clk_names[i]); 1150 if (IS_ERR(gsc->clock[i])) { 1151 dev_err(dev, "failed to get clock: %s\n", 1152 drv_data->clk_names[i]); 1153 return PTR_ERR(gsc->clock[i]); 1154 } 1155 } 1156 1157 for (i = 0; i < gsc->num_clocks; i++) { 1158 ret = clk_prepare_enable(gsc->clock[i]); 1159 if (ret) { 1160 dev_err(dev, "clock prepare failed for clock: %s\n", 1161 drv_data->clk_names[i]); 1162 while (--i >= 0) 1163 clk_disable_unprepare(gsc->clock[i]); 1164 return ret; 1165 } 1166 } 1167 1168 ret = devm_request_irq(dev, irq, gsc_irq_handler, 1169 0, pdev->name, gsc); 1170 if (ret) { 1171 dev_err(dev, "failed to install irq (%d)\n", ret); 1172 goto err_clk; 1173 } 1174 1175 ret = v4l2_device_register(dev, &gsc->v4l2_dev); 1176 if (ret) 1177 goto err_clk; 1178 1179 ret = gsc_register_m2m_device(gsc); 1180 if (ret) 1181 goto err_v4l2; 1182 1183 platform_set_drvdata(pdev, gsc); 1184 1185 gsc_hw_set_sw_reset(gsc); 1186 gsc_wait_reset(gsc); 1187 1188 vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); 1189 1190 dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id); 1191 1192 pm_runtime_set_active(dev); 1193 pm_runtime_enable(dev); 1194 1195 return 0; 1196 1197err_v4l2: 1198 v4l2_device_unregister(&gsc->v4l2_dev); 1199err_clk: 1200 for (i = gsc->num_clocks - 1; i >= 0; i--) 1201 clk_disable_unprepare(gsc->clock[i]); 1202 return ret; 1203} 1204 1205static int gsc_remove(struct platform_device *pdev) 1206{ 1207 struct gsc_dev *gsc = platform_get_drvdata(pdev); 1208 int i; 1209 1210 gsc_unregister_m2m_device(gsc); 1211 v4l2_device_unregister(&gsc->v4l2_dev); 1212 1213 vb2_dma_contig_clear_max_seg_size(&pdev->dev); 1214 1215 pm_runtime_disable(&pdev->dev); 1216 1217 if (!pm_runtime_status_suspended(&pdev->dev)) 1218 for (i = 0; i < gsc->num_clocks; i++) 1219 clk_disable_unprepare(gsc->clock[i]); 1220 1221 pm_runtime_set_suspended(&pdev->dev); 1222 1223 dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); 1224 return 0; 1225} 1226 1227#ifdef CONFIG_PM 1228static int gsc_m2m_suspend(struct gsc_dev *gsc) 1229{ 1230 unsigned long flags; 1231 int timeout; 1232 1233 spin_lock_irqsave(&gsc->slock, flags); 1234 if (!gsc_m2m_pending(gsc)) { 1235 spin_unlock_irqrestore(&gsc->slock, flags); 1236 return 0; 1237 } 1238 clear_bit(ST_M2M_SUSPENDED, &gsc->state); 1239 set_bit(ST_M2M_SUSPENDING, &gsc->state); 1240 spin_unlock_irqrestore(&gsc->slock, flags); 1241 1242 timeout = wait_event_timeout(gsc->irq_queue, 1243 test_bit(ST_M2M_SUSPENDED, &gsc->state), 1244 GSC_SHUTDOWN_TIMEOUT); 1245 1246 clear_bit(ST_M2M_SUSPENDING, &gsc->state); 1247 return timeout == 0 ? -EAGAIN : 0; 1248} 1249 1250static void gsc_m2m_resume(struct gsc_dev *gsc) 1251{ 1252 struct gsc_ctx *ctx; 1253 unsigned long flags; 1254 1255 spin_lock_irqsave(&gsc->slock, flags); 1256 /* Clear for full H/W setup in first run after resume */ 1257 ctx = gsc->m2m.ctx; 1258 gsc->m2m.ctx = NULL; 1259 spin_unlock_irqrestore(&gsc->slock, flags); 1260 1261 if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state)) 1262 gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); 1263} 1264 1265static int gsc_runtime_resume(struct device *dev) 1266{ 1267 struct gsc_dev *gsc = dev_get_drvdata(dev); 1268 int ret = 0; 1269 int i; 1270 1271 pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state); 1272 1273 for (i = 0; i < gsc->num_clocks; i++) { 1274 ret = clk_prepare_enable(gsc->clock[i]); 1275 if (ret) { 1276 while (--i >= 0) 1277 clk_disable_unprepare(gsc->clock[i]); 1278 return ret; 1279 } 1280 } 1281 1282 gsc_hw_set_sw_reset(gsc); 1283 gsc_wait_reset(gsc); 1284 gsc_m2m_resume(gsc); 1285 1286 return 0; 1287} 1288 1289static int gsc_runtime_suspend(struct device *dev) 1290{ 1291 struct gsc_dev *gsc = dev_get_drvdata(dev); 1292 int ret = 0; 1293 int i; 1294 1295 ret = gsc_m2m_suspend(gsc); 1296 if (ret) 1297 return ret; 1298 1299 for (i = gsc->num_clocks - 1; i >= 0; i--) 1300 clk_disable_unprepare(gsc->clock[i]); 1301 1302 pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state); 1303 return ret; 1304} 1305#endif 1306 1307static const struct dev_pm_ops gsc_pm_ops = { 1308 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 1309 pm_runtime_force_resume) 1310 SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL) 1311}; 1312 1313static struct platform_driver gsc_driver = { 1314 .probe = gsc_probe, 1315 .remove = gsc_remove, 1316 .driver = { 1317 .name = GSC_MODULE_NAME, 1318 .pm = &gsc_pm_ops, 1319 .of_match_table = exynos_gsc_match, 1320 } 1321}; 1322 1323module_platform_driver(gsc_driver); 1324 1325MODULE_AUTHOR("Hyunwong Kim <khw0178.kim@samsung.com>"); 1326MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series G-Scaler driver"); 1327MODULE_LICENSE("GPL");