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 28 static 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 201 const 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 209 const 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 230 void 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 240 int 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 258 void 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 275 void 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 309 int 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 322 static 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 340 void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm) 341 { 342 u32 f_chk_addr, f_chk_len, s_chk_addr = 0, s_chk_len = 0; 343 344 f_chk_addr = frm->addr.y; 345 f_chk_len = frm->payload[0]; 346 if (frm->fmt->num_planes == 2) { 347 s_chk_addr = frm->addr.cb; 348 s_chk_len = frm->payload[1]; 349 } else if (frm->fmt->num_planes == 3) { 350 u32 low_addr, low_plane, mid_addr, mid_plane; 351 u32 high_addr, high_plane; 352 u32 t_min, t_max; 353 354 t_min = min3(frm->addr.y, frm->addr.cb, frm->addr.cr); 355 if (get_plane_info(frm, t_min, &low_plane, &low_addr)) 356 return; 357 t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr); 358 if (get_plane_info(frm, t_max, &high_plane, &high_addr)) 359 return; 360 361 mid_plane = 3 - (low_plane + high_plane); 362 if (mid_plane == 0) 363 mid_addr = frm->addr.y; 364 else if (mid_plane == 1) 365 mid_addr = frm->addr.cb; 366 else if (mid_plane == 2) 367 mid_addr = frm->addr.cr; 368 else 369 return; 370 371 f_chk_addr = low_addr; 372 if (mid_addr + frm->payload[mid_plane] - low_addr > 373 high_addr + frm->payload[high_plane] - mid_addr) { 374 f_chk_len = frm->payload[low_plane]; 375 s_chk_addr = mid_addr; 376 s_chk_len = high_addr + 377 frm->payload[high_plane] - mid_addr; 378 } else { 379 f_chk_len = mid_addr + 380 frm->payload[mid_plane] - low_addr; 381 s_chk_addr = high_addr; 382 s_chk_len = frm->payload[high_plane]; 383 } 384 } 385 pr_debug("f_addr = 0x%08x, f_len = %d, s_addr = 0x%08x, s_len = %d\n", 386 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len); 387 } 388 389 int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f) 390 { 391 struct gsc_dev *gsc = ctx->gsc_dev; 392 struct gsc_variant *variant = gsc->variant; 393 struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 394 const struct gsc_fmt *fmt; 395 u32 max_w, max_h, mod_x, mod_y; 396 u32 min_w, min_h, tmp_w, tmp_h; 397 int i; 398 399 pr_debug("user put w: %d, h: %d", pix_mp->width, pix_mp->height); 400 401 fmt = find_fmt(&pix_mp->pixelformat, NULL, 0); 402 if (!fmt) { 403 pr_err("pixelformat format (0x%X) invalid\n", 404 pix_mp->pixelformat); 405 return -EINVAL; 406 } 407 408 if (pix_mp->field == V4L2_FIELD_ANY) 409 pix_mp->field = V4L2_FIELD_NONE; 410 else if (pix_mp->field != V4L2_FIELD_NONE) { 411 pr_debug("Not supported field order(%d)\n", pix_mp->field); 412 return -EINVAL; 413 } 414 415 max_w = variant->pix_max->target_rot_dis_w; 416 max_h = variant->pix_max->target_rot_dis_h; 417 418 mod_x = ffs(variant->pix_align->org_w) - 1; 419 if (is_yuv420(fmt->color)) 420 mod_y = ffs(variant->pix_align->org_h) - 1; 421 else 422 mod_y = ffs(variant->pix_align->org_h) - 2; 423 424 if (V4L2_TYPE_IS_OUTPUT(f->type)) { 425 min_w = variant->pix_min->org_w; 426 min_h = variant->pix_min->org_h; 427 } else { 428 min_w = variant->pix_min->target_rot_dis_w; 429 min_h = variant->pix_min->target_rot_dis_h; 430 pix_mp->colorspace = ctx->out_colorspace; 431 } 432 433 pr_debug("mod_x: %d, mod_y: %d, max_w: %d, max_h = %d", 434 mod_x, mod_y, max_w, max_h); 435 436 /* To check if image size is modified to adjust parameter against 437 hardware abilities */ 438 tmp_w = pix_mp->width; 439 tmp_h = pix_mp->height; 440 441 v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_x, 442 &pix_mp->height, min_h, max_h, mod_y, 0); 443 if (tmp_w != pix_mp->width || tmp_h != pix_mp->height) 444 pr_debug("Image size has been modified from %dx%d to %dx%d\n", 445 tmp_w, tmp_h, pix_mp->width, pix_mp->height); 446 447 pix_mp->num_planes = fmt->num_planes; 448 449 if (V4L2_TYPE_IS_OUTPUT(f->type)) 450 ctx->out_colorspace = pix_mp->colorspace; 451 452 for (i = 0; i < pix_mp->num_planes; ++i) { 453 struct v4l2_plane_pix_format *plane_fmt = &pix_mp->plane_fmt[i]; 454 u32 bpl = plane_fmt->bytesperline; 455 456 if (fmt->num_comp == 1 && /* Packed */ 457 (bpl == 0 || (bpl * 8 / fmt->depth[i]) < pix_mp->width)) 458 bpl = pix_mp->width * fmt->depth[i] / 8; 459 460 if (fmt->num_comp > 1 && /* Planar */ 461 (bpl == 0 || bpl < pix_mp->width)) 462 bpl = pix_mp->width; 463 464 if (i != 0 && fmt->num_comp == 3) 465 bpl /= 2; 466 467 plane_fmt->bytesperline = bpl; 468 plane_fmt->sizeimage = max(pix_mp->width * pix_mp->height * 469 fmt->depth[i] / 8, 470 plane_fmt->sizeimage); 471 pr_debug("[%d]: bpl: %d, sizeimage: %d", 472 i, bpl, pix_mp->plane_fmt[i].sizeimage); 473 } 474 475 return 0; 476 } 477 478 int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f) 479 { 480 struct gsc_frame *frame; 481 struct v4l2_pix_format_mplane *pix_mp; 482 int i; 483 484 frame = ctx_get_frame(ctx, f->type); 485 if (IS_ERR(frame)) 486 return PTR_ERR(frame); 487 488 pix_mp = &f->fmt.pix_mp; 489 490 pix_mp->width = frame->f_width; 491 pix_mp->height = frame->f_height; 492 pix_mp->field = V4L2_FIELD_NONE; 493 pix_mp->pixelformat = frame->fmt->pixelformat; 494 pix_mp->num_planes = frame->fmt->num_planes; 495 pix_mp->colorspace = ctx->out_colorspace; 496 497 for (i = 0; i < pix_mp->num_planes; ++i) { 498 pix_mp->plane_fmt[i].bytesperline = (frame->f_width * 499 frame->fmt->depth[i]) / 8; 500 pix_mp->plane_fmt[i].sizeimage = 501 pix_mp->plane_fmt[i].bytesperline * frame->f_height; 502 } 503 504 return 0; 505 } 506 507 void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h) 508 { 509 if (tmp_w != *w || tmp_h != *h) { 510 pr_info("Cropped size has been modified from %dx%d to %dx%d", 511 *w, *h, tmp_w, tmp_h); 512 *w = tmp_w; 513 *h = tmp_h; 514 } 515 } 516 517 int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s) 518 { 519 struct gsc_frame *f; 520 struct gsc_dev *gsc = ctx->gsc_dev; 521 struct gsc_variant *variant = gsc->variant; 522 u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h; 523 u32 min_w, min_h, max_w, max_h; 524 525 if (s->r.top < 0 || s->r.left < 0) { 526 pr_err("doesn't support negative values for top & left\n"); 527 return -EINVAL; 528 } 529 pr_debug("user put w: %d, h: %d", s->r.width, s->r.height); 530 531 if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) 532 f = &ctx->d_frame; 533 else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) 534 f = &ctx->s_frame; 535 else 536 return -EINVAL; 537 538 max_w = f->f_width; 539 max_h = f->f_height; 540 tmp_w = s->r.width; 541 tmp_h = s->r.height; 542 543 if (V4L2_TYPE_IS_OUTPUT(s->type)) { 544 if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 1) || 545 is_rgb(f->fmt->color)) 546 min_w = 32; 547 else 548 min_w = 64; 549 if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 3) || 550 is_yuv420(f->fmt->color)) 551 min_h = 32; 552 else 553 min_h = 16; 554 } else { 555 if (is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) 556 mod_x = ffs(variant->pix_align->target_w) - 1; 557 if (is_yuv420(f->fmt->color)) 558 mod_y = ffs(variant->pix_align->target_h) - 1; 559 if (ctx->gsc_ctrls.rotate->val == 90 || 560 ctx->gsc_ctrls.rotate->val == 270) { 561 max_w = f->f_height; 562 max_h = f->f_width; 563 min_w = variant->pix_min->target_rot_en_w; 564 min_h = variant->pix_min->target_rot_en_h; 565 tmp_w = s->r.height; 566 tmp_h = s->r.width; 567 } else { 568 min_w = variant->pix_min->target_rot_dis_w; 569 min_h = variant->pix_min->target_rot_dis_h; 570 } 571 } 572 pr_debug("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d", 573 mod_x, mod_y, min_w, min_h); 574 pr_debug("tmp_w : %d, tmp_h : %d", tmp_w, tmp_h); 575 576 v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x, 577 &tmp_h, min_h, max_h, mod_y, 0); 578 579 if (V4L2_TYPE_IS_CAPTURE(s->type) && 580 (ctx->gsc_ctrls.rotate->val == 90 || 581 ctx->gsc_ctrls.rotate->val == 270)) 582 gsc_check_crop_change(tmp_h, tmp_w, 583 &s->r.width, &s->r.height); 584 else 585 gsc_check_crop_change(tmp_w, tmp_h, 586 &s->r.width, &s->r.height); 587 588 589 /* adjust left/top if cropping rectangle is out of bounds */ 590 /* Need to add code to algin left value with 2's multiple */ 591 if (s->r.left + tmp_w > max_w) 592 s->r.left = max_w - tmp_w; 593 if (s->r.top + tmp_h > max_h) 594 s->r.top = max_h - tmp_h; 595 596 if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) && 597 s->r.left & 1) 598 s->r.left -= 1; 599 600 pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", 601 s->r.left, s->r.top, s->r.width, s->r.height, max_w, max_h); 602 603 return 0; 604 } 605 606 int gsc_check_scaler_ratio(struct gsc_variant *var, int sw, int sh, int dw, 607 int dh, int rot, int out_path) 608 { 609 int tmp_w, tmp_h, sc_down_max; 610 611 if (out_path == GSC_DMA) 612 sc_down_max = var->sc_down_max; 613 else 614 sc_down_max = var->local_sc_down; 615 616 if (rot == 90 || rot == 270) { 617 tmp_w = dh; 618 tmp_h = dw; 619 } else { 620 tmp_w = dw; 621 tmp_h = dh; 622 } 623 624 if ((sw / tmp_w) > sc_down_max || 625 (sh / tmp_h) > sc_down_max || 626 (tmp_w / sw) > var->sc_up_max || 627 (tmp_h / sh) > var->sc_up_max) 628 return -EINVAL; 629 630 return 0; 631 } 632 633 int gsc_set_scaler_info(struct gsc_ctx *ctx) 634 { 635 struct gsc_scaler *sc = &ctx->scaler; 636 struct gsc_frame *s_frame = &ctx->s_frame; 637 struct gsc_frame *d_frame = &ctx->d_frame; 638 struct gsc_variant *variant = ctx->gsc_dev->variant; 639 struct device *dev = &ctx->gsc_dev->pdev->dev; 640 int tx, ty; 641 int ret; 642 643 ret = gsc_check_scaler_ratio(variant, s_frame->crop.width, 644 s_frame->crop.height, d_frame->crop.width, d_frame->crop.height, 645 ctx->gsc_ctrls.rotate->val, ctx->out_path); 646 if (ret) { 647 pr_err("out of scaler range"); 648 return ret; 649 } 650 651 if (ctx->gsc_ctrls.rotate->val == 90 || 652 ctx->gsc_ctrls.rotate->val == 270) { 653 ty = d_frame->crop.width; 654 tx = d_frame->crop.height; 655 } else { 656 tx = d_frame->crop.width; 657 ty = d_frame->crop.height; 658 } 659 660 if (tx <= 0 || ty <= 0) { 661 dev_err(dev, "Invalid target size: %dx%d", tx, ty); 662 return -EINVAL; 663 } 664 665 ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.width, 666 tx, &sc->pre_hratio); 667 if (ret) { 668 pr_err("Horizontal scale ratio is out of range"); 669 return ret; 670 } 671 672 ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.height, 673 ty, &sc->pre_vratio); 674 if (ret) { 675 pr_err("Vertical scale ratio is out of range"); 676 return ret; 677 } 678 679 gsc_check_src_scale_info(variant, s_frame, &sc->pre_hratio, 680 tx, ty, &sc->pre_vratio); 681 682 gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio, 683 &sc->pre_shfactor); 684 685 sc->main_hratio = (s_frame->crop.width << 16) / tx; 686 sc->main_vratio = (s_frame->crop.height << 16) / ty; 687 688 pr_debug("scaler input/output size : sx = %d, sy = %d, tx = %d, ty = %d", 689 s_frame->crop.width, s_frame->crop.height, tx, ty); 690 pr_debug("scaler ratio info : pre_shfactor : %d, pre_h : %d", 691 sc->pre_shfactor, sc->pre_hratio); 692 pr_debug("pre_v :%d, main_h : %d, main_v : %d", 693 sc->pre_vratio, sc->main_hratio, sc->main_vratio); 694 695 return 0; 696 } 697 698 static int __gsc_s_ctrl(struct gsc_ctx *ctx, struct v4l2_ctrl *ctrl) 699 { 700 struct gsc_dev *gsc = ctx->gsc_dev; 701 struct gsc_variant *variant = gsc->variant; 702 unsigned int flags = GSC_DST_FMT | GSC_SRC_FMT; 703 int ret = 0; 704 705 if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) 706 return 0; 707 708 switch (ctrl->id) { 709 case V4L2_CID_HFLIP: 710 ctx->hflip = ctrl->val; 711 break; 712 713 case V4L2_CID_VFLIP: 714 ctx->vflip = ctrl->val; 715 break; 716 717 case V4L2_CID_ROTATE: 718 if ((ctx->state & flags) == flags) { 719 ret = gsc_check_scaler_ratio(variant, 720 ctx->s_frame.crop.width, 721 ctx->s_frame.crop.height, 722 ctx->d_frame.crop.width, 723 ctx->d_frame.crop.height, 724 ctx->gsc_ctrls.rotate->val, 725 ctx->out_path); 726 727 if (ret) 728 return -EINVAL; 729 } 730 731 ctx->rotation = ctrl->val; 732 break; 733 734 case V4L2_CID_ALPHA_COMPONENT: 735 ctx->d_frame.alpha = ctrl->val; 736 break; 737 } 738 739 ctx->state |= GSC_PARAMS; 740 return 0; 741 } 742 743 static int gsc_s_ctrl(struct v4l2_ctrl *ctrl) 744 { 745 struct gsc_ctx *ctx = ctrl_to_ctx(ctrl); 746 unsigned long flags; 747 int ret; 748 749 spin_lock_irqsave(&ctx->gsc_dev->slock, flags); 750 ret = __gsc_s_ctrl(ctx, ctrl); 751 spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags); 752 753 return ret; 754 } 755 756 static const struct v4l2_ctrl_ops gsc_ctrl_ops = { 757 .s_ctrl = gsc_s_ctrl, 758 }; 759 760 int gsc_ctrls_create(struct gsc_ctx *ctx) 761 { 762 if (ctx->ctrls_rdy) { 763 pr_err("Control handler of this context was created already"); 764 return 0; 765 } 766 767 v4l2_ctrl_handler_init(&ctx->ctrl_handler, GSC_MAX_CTRL_NUM); 768 769 ctx->gsc_ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, 770 &gsc_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0); 771 ctx->gsc_ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, 772 &gsc_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); 773 ctx->gsc_ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, 774 &gsc_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); 775 ctx->gsc_ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler, 776 &gsc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0); 777 778 ctx->ctrls_rdy = ctx->ctrl_handler.error == 0; 779 780 if (ctx->ctrl_handler.error) { 781 int err = ctx->ctrl_handler.error; 782 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 783 pr_err("Failed to create G-Scaler control handlers"); 784 return err; 785 } 786 787 return 0; 788 } 789 790 void gsc_ctrls_delete(struct gsc_ctx *ctx) 791 { 792 if (ctx->ctrls_rdy) { 793 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 794 ctx->ctrls_rdy = false; 795 } 796 } 797 798 /* The color format (num_comp, num_planes) must be already configured. */ 799 int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb, 800 struct gsc_frame *frame, struct gsc_addr *addr) 801 { 802 int ret = 0; 803 u32 pix_size; 804 805 if ((vb == NULL) || (frame == NULL)) 806 return -EINVAL; 807 808 pix_size = frame->f_width * frame->f_height; 809 810 pr_debug("num_planes= %d, num_comp= %d, pix_size= %d", 811 frame->fmt->num_planes, frame->fmt->num_comp, pix_size); 812 813 addr->y = vb2_dma_contig_plane_dma_addr(vb, 0); 814 815 if (frame->fmt->num_planes == 1) { 816 switch (frame->fmt->num_comp) { 817 case 1: 818 addr->cb = 0; 819 addr->cr = 0; 820 break; 821 case 2: 822 /* decompose Y into Y/Cb */ 823 addr->cb = (dma_addr_t)(addr->y + pix_size); 824 addr->cr = 0; 825 break; 826 case 3: 827 /* decompose Y into Y/Cb/Cr */ 828 addr->cb = (dma_addr_t)(addr->y + pix_size); 829 if (GSC_YUV420 == frame->fmt->color) 830 addr->cr = (dma_addr_t)(addr->cb 831 + (pix_size >> 2)); 832 else /* 422 */ 833 addr->cr = (dma_addr_t)(addr->cb 834 + (pix_size >> 1)); 835 break; 836 default: 837 pr_err("Invalid the number of color planes"); 838 return -EINVAL; 839 } 840 } else { 841 if (frame->fmt->num_planes >= 2) 842 addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); 843 844 if (frame->fmt->num_planes == 3) 845 addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2); 846 } 847 848 if ((frame->fmt->pixelformat == V4L2_PIX_FMT_VYUY) || 849 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) || 850 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) || 851 (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M)) 852 swap(addr->cb, addr->cr); 853 854 pr_debug("ADDR: y= %pad cb= %pad cr= %pad ret= %d", 855 &addr->y, &addr->cb, &addr->cr, ret); 856 857 return ret; 858 } 859 860 static irqreturn_t gsc_irq_handler(int irq, void *priv) 861 { 862 struct gsc_dev *gsc = priv; 863 struct gsc_ctx *ctx; 864 int gsc_irq; 865 866 gsc_irq = gsc_hw_get_irq_status(gsc); 867 gsc_hw_clear_irq(gsc, gsc_irq); 868 869 if (gsc_irq == GSC_IRQ_OVERRUN) { 870 pr_err("Local path input over-run interrupt has occurred!\n"); 871 return IRQ_HANDLED; 872 } 873 874 spin_lock(&gsc->slock); 875 876 if (test_and_clear_bit(ST_M2M_PEND, &gsc->state)) { 877 878 gsc_hw_enable_control(gsc, false); 879 880 if (test_and_clear_bit(ST_M2M_SUSPENDING, &gsc->state)) { 881 set_bit(ST_M2M_SUSPENDED, &gsc->state); 882 wake_up(&gsc->irq_queue); 883 goto isr_unlock; 884 } 885 ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev); 886 887 if (!ctx || !ctx->m2m_ctx) 888 goto isr_unlock; 889 890 spin_unlock(&gsc->slock); 891 gsc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); 892 893 /* wake_up job_abort, stop_streaming */ 894 if (ctx->state & GSC_CTX_STOP_REQ) { 895 ctx->state &= ~GSC_CTX_STOP_REQ; 896 wake_up(&gsc->irq_queue); 897 } 898 return IRQ_HANDLED; 899 } 900 901 isr_unlock: 902 spin_unlock(&gsc->slock); 903 return IRQ_HANDLED; 904 } 905 906 static struct gsc_pix_max gsc_v_100_max = { 907 .org_scaler_bypass_w = 8192, 908 .org_scaler_bypass_h = 8192, 909 .org_scaler_input_w = 4800, 910 .org_scaler_input_h = 3344, 911 .real_rot_dis_w = 4800, 912 .real_rot_dis_h = 3344, 913 .real_rot_en_w = 2047, 914 .real_rot_en_h = 2047, 915 .target_rot_dis_w = 4800, 916 .target_rot_dis_h = 3344, 917 .target_rot_en_w = 2016, 918 .target_rot_en_h = 2016, 919 }; 920 921 static struct gsc_pix_max gsc_v_5250_max = { 922 .org_scaler_bypass_w = 8192, 923 .org_scaler_bypass_h = 8192, 924 .org_scaler_input_w = 4800, 925 .org_scaler_input_h = 3344, 926 .real_rot_dis_w = 4800, 927 .real_rot_dis_h = 3344, 928 .real_rot_en_w = 2016, 929 .real_rot_en_h = 2016, 930 .target_rot_dis_w = 4800, 931 .target_rot_dis_h = 3344, 932 .target_rot_en_w = 2016, 933 .target_rot_en_h = 2016, 934 }; 935 936 static struct gsc_pix_max gsc_v_5420_max = { 937 .org_scaler_bypass_w = 8192, 938 .org_scaler_bypass_h = 8192, 939 .org_scaler_input_w = 4800, 940 .org_scaler_input_h = 3344, 941 .real_rot_dis_w = 4800, 942 .real_rot_dis_h = 3344, 943 .real_rot_en_w = 2048, 944 .real_rot_en_h = 2048, 945 .target_rot_dis_w = 4800, 946 .target_rot_dis_h = 3344, 947 .target_rot_en_w = 2016, 948 .target_rot_en_h = 2016, 949 }; 950 951 static struct gsc_pix_max gsc_v_5433_max = { 952 .org_scaler_bypass_w = 8192, 953 .org_scaler_bypass_h = 8192, 954 .org_scaler_input_w = 4800, 955 .org_scaler_input_h = 3344, 956 .real_rot_dis_w = 4800, 957 .real_rot_dis_h = 3344, 958 .real_rot_en_w = 2047, 959 .real_rot_en_h = 2047, 960 .target_rot_dis_w = 4800, 961 .target_rot_dis_h = 3344, 962 .target_rot_en_w = 2016, 963 .target_rot_en_h = 2016, 964 }; 965 966 static struct gsc_pix_min gsc_v_100_min = { 967 .org_w = 64, 968 .org_h = 32, 969 .real_w = 64, 970 .real_h = 32, 971 .target_rot_dis_w = 64, 972 .target_rot_dis_h = 32, 973 .target_rot_en_w = 32, 974 .target_rot_en_h = 16, 975 }; 976 977 static struct gsc_pix_align gsc_v_100_align = { 978 .org_h = 16, 979 .org_w = 16, /* yuv420 : 16, others : 8 */ 980 .offset_h = 2, /* yuv420/422 : 2, others : 1 */ 981 .real_w = 16, /* yuv420/422 : 4~16, others : 2~8 */ 982 .real_h = 16, /* yuv420 : 4~16, others : 1 */ 983 .target_w = 2, /* yuv420/422 : 2, others : 1 */ 984 .target_h = 2, /* yuv420 : 2, others : 1 */ 985 }; 986 987 static struct gsc_variant gsc_v_100_variant = { 988 .pix_max = &gsc_v_100_max, 989 .pix_min = &gsc_v_100_min, 990 .pix_align = &gsc_v_100_align, 991 .in_buf_cnt = 32, 992 .out_buf_cnt = 32, 993 .sc_up_max = 8, 994 .sc_down_max = 16, 995 .poly_sc_down_max = 4, 996 .pre_sc_down_max = 4, 997 .local_sc_down = 2, 998 }; 999 1000 static struct gsc_variant gsc_v_5250_variant = { 1001 .pix_max = &gsc_v_5250_max, 1002 .pix_min = &gsc_v_100_min, 1003 .pix_align = &gsc_v_100_align, 1004 .in_buf_cnt = 32, 1005 .out_buf_cnt = 32, 1006 .sc_up_max = 8, 1007 .sc_down_max = 16, 1008 .poly_sc_down_max = 4, 1009 .pre_sc_down_max = 4, 1010 .local_sc_down = 2, 1011 }; 1012 1013 static struct gsc_variant gsc_v_5420_variant = { 1014 .pix_max = &gsc_v_5420_max, 1015 .pix_min = &gsc_v_100_min, 1016 .pix_align = &gsc_v_100_align, 1017 .in_buf_cnt = 32, 1018 .out_buf_cnt = 32, 1019 .sc_up_max = 8, 1020 .sc_down_max = 16, 1021 .poly_sc_down_max = 4, 1022 .pre_sc_down_max = 4, 1023 .local_sc_down = 2, 1024 }; 1025 1026 static struct gsc_variant gsc_v_5433_variant = { 1027 .pix_max = &gsc_v_5433_max, 1028 .pix_min = &gsc_v_100_min, 1029 .pix_align = &gsc_v_100_align, 1030 .in_buf_cnt = 32, 1031 .out_buf_cnt = 32, 1032 .sc_up_max = 8, 1033 .sc_down_max = 16, 1034 .poly_sc_down_max = 4, 1035 .pre_sc_down_max = 4, 1036 .local_sc_down = 2, 1037 }; 1038 1039 static struct gsc_driverdata gsc_v_100_drvdata = { 1040 .variant = { 1041 [0] = &gsc_v_100_variant, 1042 [1] = &gsc_v_100_variant, 1043 [2] = &gsc_v_100_variant, 1044 [3] = &gsc_v_100_variant, 1045 }, 1046 .num_entities = 4, 1047 .clk_names = { "gscl" }, 1048 .num_clocks = 1, 1049 }; 1050 1051 static struct gsc_driverdata gsc_v_5250_drvdata = { 1052 .variant = { 1053 [0] = &gsc_v_5250_variant, 1054 [1] = &gsc_v_5250_variant, 1055 [2] = &gsc_v_5250_variant, 1056 [3] = &gsc_v_5250_variant, 1057 }, 1058 .num_entities = 4, 1059 .clk_names = { "gscl" }, 1060 .num_clocks = 1, 1061 }; 1062 1063 static struct gsc_driverdata gsc_v_5420_drvdata = { 1064 .variant = { 1065 [0] = &gsc_v_5420_variant, 1066 [1] = &gsc_v_5420_variant, 1067 }, 1068 .num_entities = 2, 1069 .clk_names = { "gscl" }, 1070 .num_clocks = 1, 1071 }; 1072 1073 static struct gsc_driverdata gsc_5433_drvdata = { 1074 .variant = { 1075 [0] = &gsc_v_5433_variant, 1076 [1] = &gsc_v_5433_variant, 1077 [2] = &gsc_v_5433_variant, 1078 }, 1079 .num_entities = 3, 1080 .clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" }, 1081 .num_clocks = 4, 1082 }; 1083 1084 static const struct of_device_id exynos_gsc_match[] = { 1085 { 1086 .compatible = "samsung,exynos5250-gsc", 1087 .data = &gsc_v_5250_drvdata, 1088 }, 1089 { 1090 .compatible = "samsung,exynos5420-gsc", 1091 .data = &gsc_v_5420_drvdata, 1092 }, 1093 { 1094 .compatible = "samsung,exynos5433-gsc", 1095 .data = &gsc_5433_drvdata, 1096 }, 1097 { 1098 .compatible = "samsung,exynos5-gsc", 1099 .data = &gsc_v_100_drvdata, 1100 }, 1101 {}, 1102 }; 1103 MODULE_DEVICE_TABLE(of, exynos_gsc_match); 1104 1105 static int gsc_probe(struct platform_device *pdev) 1106 { 1107 struct gsc_dev *gsc; 1108 struct device *dev = &pdev->dev; 1109 const struct gsc_driverdata *drv_data = of_device_get_match_data(dev); 1110 int irq; 1111 int ret; 1112 int i; 1113 1114 gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL); 1115 if (!gsc) 1116 return -ENOMEM; 1117 1118 ret = of_alias_get_id(pdev->dev.of_node, "gsc"); 1119 if (ret < 0) 1120 return ret; 1121 1122 if (drv_data == &gsc_v_100_drvdata) 1123 dev_info(dev, "compatible 'exynos5-gsc' is deprecated\n"); 1124 1125 gsc->id = ret; 1126 if (gsc->id >= drv_data->num_entities) { 1127 dev_err(dev, "Invalid platform device id: %d\n", gsc->id); 1128 return -EINVAL; 1129 } 1130 1131 gsc->num_clocks = drv_data->num_clocks; 1132 gsc->variant = drv_data->variant[gsc->id]; 1133 gsc->pdev = pdev; 1134 1135 init_waitqueue_head(&gsc->irq_queue); 1136 spin_lock_init(&gsc->slock); 1137 mutex_init(&gsc->lock); 1138 1139 gsc->regs = devm_platform_ioremap_resource(pdev, 0); 1140 if (IS_ERR(gsc->regs)) 1141 return PTR_ERR(gsc->regs); 1142 1143 irq = platform_get_irq(pdev, 0); 1144 if (irq < 0) 1145 return irq; 1146 1147 for (i = 0; i < gsc->num_clocks; i++) { 1148 gsc->clock[i] = devm_clk_get(dev, drv_data->clk_names[i]); 1149 if (IS_ERR(gsc->clock[i])) { 1150 dev_err(dev, "failed to get clock: %s\n", 1151 drv_data->clk_names[i]); 1152 return PTR_ERR(gsc->clock[i]); 1153 } 1154 } 1155 1156 for (i = 0; i < gsc->num_clocks; i++) { 1157 ret = clk_prepare_enable(gsc->clock[i]); 1158 if (ret) { 1159 dev_err(dev, "clock prepare failed for clock: %s\n", 1160 drv_data->clk_names[i]); 1161 while (--i >= 0) 1162 clk_disable_unprepare(gsc->clock[i]); 1163 return ret; 1164 } 1165 } 1166 1167 ret = devm_request_irq(dev, irq, gsc_irq_handler, 1168 0, pdev->name, gsc); 1169 if (ret) { 1170 dev_err(dev, "failed to install irq (%d)\n", ret); 1171 goto err_clk; 1172 } 1173 1174 ret = v4l2_device_register(dev, &gsc->v4l2_dev); 1175 if (ret) 1176 goto err_clk; 1177 1178 ret = gsc_register_m2m_device(gsc); 1179 if (ret) 1180 goto err_v4l2; 1181 1182 platform_set_drvdata(pdev, gsc); 1183 1184 gsc_hw_set_sw_reset(gsc); 1185 gsc_wait_reset(gsc); 1186 1187 vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); 1188 1189 dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id); 1190 1191 pm_runtime_set_active(dev); 1192 pm_runtime_enable(dev); 1193 1194 return 0; 1195 1196 err_v4l2: 1197 v4l2_device_unregister(&gsc->v4l2_dev); 1198 err_clk: 1199 for (i = gsc->num_clocks - 1; i >= 0; i--) 1200 clk_disable_unprepare(gsc->clock[i]); 1201 return ret; 1202 } 1203 1204 static int gsc_remove(struct platform_device *pdev) 1205 { 1206 struct gsc_dev *gsc = platform_get_drvdata(pdev); 1207 int i; 1208 1209 gsc_unregister_m2m_device(gsc); 1210 v4l2_device_unregister(&gsc->v4l2_dev); 1211 1212 vb2_dma_contig_clear_max_seg_size(&pdev->dev); 1213 1214 pm_runtime_disable(&pdev->dev); 1215 1216 if (!pm_runtime_status_suspended(&pdev->dev)) 1217 for (i = 0; i < gsc->num_clocks; i++) 1218 clk_disable_unprepare(gsc->clock[i]); 1219 1220 pm_runtime_set_suspended(&pdev->dev); 1221 1222 dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); 1223 return 0; 1224 } 1225 1226 #ifdef CONFIG_PM 1227 static int gsc_m2m_suspend(struct gsc_dev *gsc) 1228 { 1229 unsigned long flags; 1230 int timeout; 1231 1232 spin_lock_irqsave(&gsc->slock, flags); 1233 if (!gsc_m2m_pending(gsc)) { 1234 spin_unlock_irqrestore(&gsc->slock, flags); 1235 return 0; 1236 } 1237 clear_bit(ST_M2M_SUSPENDED, &gsc->state); 1238 set_bit(ST_M2M_SUSPENDING, &gsc->state); 1239 spin_unlock_irqrestore(&gsc->slock, flags); 1240 1241 timeout = wait_event_timeout(gsc->irq_queue, 1242 test_bit(ST_M2M_SUSPENDED, &gsc->state), 1243 GSC_SHUTDOWN_TIMEOUT); 1244 1245 clear_bit(ST_M2M_SUSPENDING, &gsc->state); 1246 return timeout == 0 ? -EAGAIN : 0; 1247 } 1248 1249 static void gsc_m2m_resume(struct gsc_dev *gsc) 1250 { 1251 struct gsc_ctx *ctx; 1252 unsigned long flags; 1253 1254 spin_lock_irqsave(&gsc->slock, flags); 1255 /* Clear for full H/W setup in first run after resume */ 1256 ctx = gsc->m2m.ctx; 1257 gsc->m2m.ctx = NULL; 1258 spin_unlock_irqrestore(&gsc->slock, flags); 1259 1260 if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state)) 1261 gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); 1262 } 1263 1264 static int gsc_runtime_resume(struct device *dev) 1265 { 1266 struct gsc_dev *gsc = dev_get_drvdata(dev); 1267 int ret = 0; 1268 int i; 1269 1270 pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state); 1271 1272 for (i = 0; i < gsc->num_clocks; i++) { 1273 ret = clk_prepare_enable(gsc->clock[i]); 1274 if (ret) { 1275 while (--i >= 0) 1276 clk_disable_unprepare(gsc->clock[i]); 1277 return ret; 1278 } 1279 } 1280 1281 gsc_hw_set_sw_reset(gsc); 1282 gsc_wait_reset(gsc); 1283 gsc_m2m_resume(gsc); 1284 1285 return 0; 1286 } 1287 1288 static int gsc_runtime_suspend(struct device *dev) 1289 { 1290 struct gsc_dev *gsc = dev_get_drvdata(dev); 1291 int ret = 0; 1292 int i; 1293 1294 ret = gsc_m2m_suspend(gsc); 1295 if (ret) 1296 return ret; 1297 1298 for (i = gsc->num_clocks - 1; i >= 0; i--) 1299 clk_disable_unprepare(gsc->clock[i]); 1300 1301 pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state); 1302 return ret; 1303 } 1304 #endif 1305 1306 static const struct dev_pm_ops gsc_pm_ops = { 1307 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 1308 pm_runtime_force_resume) 1309 SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL) 1310 }; 1311 1312 static struct platform_driver gsc_driver = { 1313 .probe = gsc_probe, 1314 .remove = gsc_remove, 1315 .driver = { 1316 .name = GSC_MODULE_NAME, 1317 .pm = &gsc_pm_ops, 1318 .of_match_table = exynos_gsc_match, 1319 } 1320 }; 1321 1322 module_platform_driver(gsc_driver); 1323 1324 MODULE_AUTHOR("Hyunwong Kim <khw0178.kim@samsung.com>"); 1325 MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series G-Scaler driver"); 1326 MODULE_LICENSE("GPL"); 1327