sun8i_rotate.c (22151B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Allwinner sun8i DE2 rotation driver 4 * 5 * Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> 6 */ 7 8#include <linux/clk.h> 9#include <linux/interrupt.h> 10#include <linux/io.h> 11#include <linux/iopoll.h> 12#include <linux/module.h> 13#include <linux/of.h> 14#include <linux/of_device.h> 15#include <linux/pm_runtime.h> 16#include <linux/reset.h> 17 18#include <media/v4l2-device.h> 19#include <media/v4l2-event.h> 20#include <media/v4l2-ioctl.h> 21#include <media/v4l2-mem2mem.h> 22 23#include "sun8i-formats.h" 24#include "sun8i-rotate.h" 25 26static inline u32 rotate_read(struct rotate_dev *dev, u32 reg) 27{ 28 return readl(dev->base + reg); 29} 30 31static inline void rotate_write(struct rotate_dev *dev, u32 reg, u32 value) 32{ 33 writel(value, dev->base + reg); 34} 35 36static inline void rotate_set_bits(struct rotate_dev *dev, u32 reg, u32 bits) 37{ 38 writel(readl(dev->base + reg) | bits, dev->base + reg); 39} 40 41static void rotate_calc_addr_pitch(dma_addr_t buffer, 42 u32 bytesperline, u32 height, 43 const struct rotate_format *fmt, 44 dma_addr_t *addr, u32 *pitch) 45{ 46 u32 size; 47 int i; 48 49 for (i = 0; i < fmt->planes; i++) { 50 pitch[i] = bytesperline; 51 addr[i] = buffer; 52 if (i > 0) 53 pitch[i] /= fmt->hsub / fmt->bpp[i]; 54 size = pitch[i] * height; 55 if (i > 0) 56 size /= fmt->vsub; 57 buffer += size; 58 } 59} 60 61static void rotate_device_run(void *priv) 62{ 63 struct rotate_ctx *ctx = priv; 64 struct rotate_dev *dev = ctx->dev; 65 struct vb2_v4l2_buffer *src, *dst; 66 const struct rotate_format *fmt; 67 dma_addr_t addr[3]; 68 u32 val, pitch[3]; 69 70 src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); 71 dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); 72 73 v4l2_m2m_buf_copy_metadata(src, dst, true); 74 75 val = ROTATE_GLB_CTL_MODE(ROTATE_MODE_COPY_ROTATE); 76 if (ctx->hflip) 77 val |= ROTATE_GLB_CTL_HFLIP; 78 if (ctx->vflip) 79 val |= ROTATE_GLB_CTL_VFLIP; 80 val |= ROTATE_GLB_CTL_ROTATION(ctx->rotate / 90); 81 if (ctx->rotate != 90 && ctx->rotate != 270) 82 val |= ROTATE_GLB_CTL_BURST_LEN(ROTATE_BURST_64); 83 else 84 val |= ROTATE_GLB_CTL_BURST_LEN(ROTATE_BURST_8); 85 rotate_write(dev, ROTATE_GLB_CTL, val); 86 87 fmt = rotate_find_format(ctx->src_fmt.pixelformat); 88 if (!fmt) 89 return; 90 91 rotate_write(dev, ROTATE_IN_FMT, ROTATE_IN_FMT_FORMAT(fmt->hw_format)); 92 93 rotate_calc_addr_pitch(vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0), 94 ctx->src_fmt.bytesperline, ctx->src_fmt.height, 95 fmt, addr, pitch); 96 97 rotate_write(dev, ROTATE_IN_SIZE, 98 ROTATE_SIZE(ctx->src_fmt.width, ctx->src_fmt.height)); 99 100 rotate_write(dev, ROTATE_IN_PITCH0, pitch[0]); 101 rotate_write(dev, ROTATE_IN_PITCH1, pitch[1]); 102 rotate_write(dev, ROTATE_IN_PITCH2, pitch[2]); 103 104 rotate_write(dev, ROTATE_IN_ADDRL0, addr[0]); 105 rotate_write(dev, ROTATE_IN_ADDRL1, addr[1]); 106 rotate_write(dev, ROTATE_IN_ADDRL2, addr[2]); 107 108 rotate_write(dev, ROTATE_IN_ADDRH0, 0); 109 rotate_write(dev, ROTATE_IN_ADDRH1, 0); 110 rotate_write(dev, ROTATE_IN_ADDRH2, 0); 111 112 fmt = rotate_find_format(ctx->dst_fmt.pixelformat); 113 if (!fmt) 114 return; 115 116 rotate_calc_addr_pitch(vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0), 117 ctx->dst_fmt.bytesperline, ctx->dst_fmt.height, 118 fmt, addr, pitch); 119 120 rotate_write(dev, ROTATE_OUT_SIZE, 121 ROTATE_SIZE(ctx->dst_fmt.width, ctx->dst_fmt.height)); 122 123 rotate_write(dev, ROTATE_OUT_PITCH0, pitch[0]); 124 rotate_write(dev, ROTATE_OUT_PITCH1, pitch[1]); 125 rotate_write(dev, ROTATE_OUT_PITCH2, pitch[2]); 126 127 rotate_write(dev, ROTATE_OUT_ADDRL0, addr[0]); 128 rotate_write(dev, ROTATE_OUT_ADDRL1, addr[1]); 129 rotate_write(dev, ROTATE_OUT_ADDRL2, addr[2]); 130 131 rotate_write(dev, ROTATE_OUT_ADDRH0, 0); 132 rotate_write(dev, ROTATE_OUT_ADDRH1, 0); 133 rotate_write(dev, ROTATE_OUT_ADDRH2, 0); 134 135 rotate_set_bits(dev, ROTATE_INT, ROTATE_INT_FINISH_IRQ_EN); 136 rotate_set_bits(dev, ROTATE_GLB_CTL, ROTATE_GLB_CTL_START); 137} 138 139static irqreturn_t rotate_irq(int irq, void *data) 140{ 141 struct vb2_v4l2_buffer *buffer; 142 struct rotate_dev *dev = data; 143 struct rotate_ctx *ctx; 144 unsigned int val; 145 146 ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); 147 if (!ctx) { 148 v4l2_err(&dev->v4l2_dev, 149 "Instance released before the end of transaction\n"); 150 return IRQ_NONE; 151 } 152 153 val = rotate_read(dev, ROTATE_INT); 154 if (!(val & ROTATE_INT_FINISH_IRQ)) 155 return IRQ_NONE; 156 157 /* clear flag and disable irq */ 158 rotate_write(dev, ROTATE_INT, ROTATE_INT_FINISH_IRQ); 159 160 buffer = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 161 v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_DONE); 162 163 buffer = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 164 v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_DONE); 165 166 v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); 167 168 return IRQ_HANDLED; 169} 170 171static inline struct rotate_ctx *rotate_file2ctx(struct file *file) 172{ 173 return container_of(file->private_data, struct rotate_ctx, fh); 174} 175 176static void rotate_prepare_format(struct v4l2_pix_format *pix_fmt) 177{ 178 unsigned int height, width, alignment, sizeimage, size, bpl; 179 const struct rotate_format *fmt; 180 int i; 181 182 fmt = rotate_find_format(pix_fmt->pixelformat); 183 if (!fmt) 184 return; 185 186 width = ALIGN(pix_fmt->width, fmt->hsub); 187 height = ALIGN(pix_fmt->height, fmt->vsub); 188 189 /* all pitches have to be 16 byte aligned */ 190 alignment = 16; 191 if (fmt->planes > 1) 192 alignment *= fmt->hsub / fmt->bpp[1]; 193 bpl = ALIGN(width * fmt->bpp[0], alignment); 194 195 sizeimage = 0; 196 for (i = 0; i < fmt->planes; i++) { 197 size = bpl * height; 198 if (i > 0) { 199 size *= fmt->bpp[i]; 200 size /= fmt->hsub; 201 size /= fmt->vsub; 202 } 203 sizeimage += size; 204 } 205 206 pix_fmt->width = width; 207 pix_fmt->height = height; 208 pix_fmt->bytesperline = bpl; 209 pix_fmt->sizeimage = sizeimage; 210} 211 212static int rotate_querycap(struct file *file, void *priv, 213 struct v4l2_capability *cap) 214{ 215 strscpy(cap->driver, ROTATE_NAME, sizeof(cap->driver)); 216 strscpy(cap->card, ROTATE_NAME, sizeof(cap->card)); 217 snprintf(cap->bus_info, sizeof(cap->bus_info), 218 "platform:%s", ROTATE_NAME); 219 220 return 0; 221} 222 223static int rotate_enum_fmt_vid_cap(struct file *file, void *priv, 224 struct v4l2_fmtdesc *f) 225{ 226 return rotate_enum_fmt(f, true); 227} 228 229static int rotate_enum_fmt_vid_out(struct file *file, void *priv, 230 struct v4l2_fmtdesc *f) 231{ 232 return rotate_enum_fmt(f, false); 233} 234 235static int rotate_enum_framesizes(struct file *file, void *priv, 236 struct v4l2_frmsizeenum *fsize) 237{ 238 const struct rotate_format *fmt; 239 240 if (fsize->index != 0) 241 return -EINVAL; 242 243 fmt = rotate_find_format(fsize->pixel_format); 244 if (!fmt) 245 return -EINVAL; 246 247 fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 248 fsize->stepwise.min_width = ROTATE_MIN_WIDTH; 249 fsize->stepwise.min_height = ROTATE_MIN_HEIGHT; 250 fsize->stepwise.max_width = ROTATE_MAX_WIDTH; 251 fsize->stepwise.max_height = ROTATE_MAX_HEIGHT; 252 fsize->stepwise.step_width = fmt->hsub; 253 fsize->stepwise.step_height = fmt->vsub; 254 255 return 0; 256} 257 258static int rotate_set_cap_format(struct rotate_ctx *ctx, 259 struct v4l2_pix_format *f, 260 u32 rotate) 261{ 262 const struct rotate_format *fmt; 263 264 fmt = rotate_find_format(ctx->src_fmt.pixelformat); 265 if (!fmt) 266 return -EINVAL; 267 268 if (fmt->flags & ROTATE_FLAG_YUV) 269 f->pixelformat = V4L2_PIX_FMT_YUV420; 270 else 271 f->pixelformat = ctx->src_fmt.pixelformat; 272 273 f->field = V4L2_FIELD_NONE; 274 275 if (rotate == 90 || rotate == 270) { 276 f->width = ctx->src_fmt.height; 277 f->height = ctx->src_fmt.width; 278 } else { 279 f->width = ctx->src_fmt.width; 280 f->height = ctx->src_fmt.height; 281 } 282 283 rotate_prepare_format(f); 284 285 return 0; 286} 287 288static int rotate_g_fmt_vid_cap(struct file *file, void *priv, 289 struct v4l2_format *f) 290{ 291 struct rotate_ctx *ctx = rotate_file2ctx(file); 292 293 f->fmt.pix = ctx->dst_fmt; 294 295 return 0; 296} 297 298static int rotate_g_fmt_vid_out(struct file *file, void *priv, 299 struct v4l2_format *f) 300{ 301 struct rotate_ctx *ctx = rotate_file2ctx(file); 302 303 f->fmt.pix = ctx->src_fmt; 304 305 return 0; 306} 307 308static int rotate_try_fmt_vid_cap(struct file *file, void *priv, 309 struct v4l2_format *f) 310{ 311 struct rotate_ctx *ctx = rotate_file2ctx(file); 312 313 return rotate_set_cap_format(ctx, &f->fmt.pix, ctx->rotate); 314} 315 316static int rotate_try_fmt_vid_out(struct file *file, void *priv, 317 struct v4l2_format *f) 318{ 319 if (!rotate_find_format(f->fmt.pix.pixelformat)) 320 f->fmt.pix.pixelformat = V4L2_PIX_FMT_ARGB32; 321 322 if (f->fmt.pix.width < ROTATE_MIN_WIDTH) 323 f->fmt.pix.width = ROTATE_MIN_WIDTH; 324 if (f->fmt.pix.height < ROTATE_MIN_HEIGHT) 325 f->fmt.pix.height = ROTATE_MIN_HEIGHT; 326 327 if (f->fmt.pix.width > ROTATE_MAX_WIDTH) 328 f->fmt.pix.width = ROTATE_MAX_WIDTH; 329 if (f->fmt.pix.height > ROTATE_MAX_HEIGHT) 330 f->fmt.pix.height = ROTATE_MAX_HEIGHT; 331 332 f->fmt.pix.field = V4L2_FIELD_NONE; 333 334 rotate_prepare_format(&f->fmt.pix); 335 336 return 0; 337} 338 339static int rotate_s_fmt_vid_cap(struct file *file, void *priv, 340 struct v4l2_format *f) 341{ 342 struct rotate_ctx *ctx = rotate_file2ctx(file); 343 struct vb2_queue *vq; 344 int ret; 345 346 ret = rotate_try_fmt_vid_cap(file, priv, f); 347 if (ret) 348 return ret; 349 350 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 351 if (vb2_is_busy(vq)) 352 return -EBUSY; 353 354 ctx->dst_fmt = f->fmt.pix; 355 356 return 0; 357} 358 359static int rotate_s_fmt_vid_out(struct file *file, void *priv, 360 struct v4l2_format *f) 361{ 362 struct rotate_ctx *ctx = rotate_file2ctx(file); 363 struct vb2_queue *vq; 364 int ret; 365 366 ret = rotate_try_fmt_vid_out(file, priv, f); 367 if (ret) 368 return ret; 369 370 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); 371 if (vb2_is_busy(vq)) 372 return -EBUSY; 373 374 /* 375 * Capture queue has to be also checked, because format and size 376 * depends on output format and size. 377 */ 378 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); 379 if (vb2_is_busy(vq)) 380 return -EBUSY; 381 382 ctx->src_fmt = f->fmt.pix; 383 384 /* Propagate colorspace information to capture. */ 385 ctx->dst_fmt.colorspace = f->fmt.pix.colorspace; 386 ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func; 387 ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc; 388 ctx->dst_fmt.quantization = f->fmt.pix.quantization; 389 390 return rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate); 391} 392 393static const struct v4l2_ioctl_ops rotate_ioctl_ops = { 394 .vidioc_querycap = rotate_querycap, 395 396 .vidioc_enum_framesizes = rotate_enum_framesizes, 397 398 .vidioc_enum_fmt_vid_cap = rotate_enum_fmt_vid_cap, 399 .vidioc_g_fmt_vid_cap = rotate_g_fmt_vid_cap, 400 .vidioc_try_fmt_vid_cap = rotate_try_fmt_vid_cap, 401 .vidioc_s_fmt_vid_cap = rotate_s_fmt_vid_cap, 402 403 .vidioc_enum_fmt_vid_out = rotate_enum_fmt_vid_out, 404 .vidioc_g_fmt_vid_out = rotate_g_fmt_vid_out, 405 .vidioc_try_fmt_vid_out = rotate_try_fmt_vid_out, 406 .vidioc_s_fmt_vid_out = rotate_s_fmt_vid_out, 407 408 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 409 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 410 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 411 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 412 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 413 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 414 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 415 416 .vidioc_streamon = v4l2_m2m_ioctl_streamon, 417 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 418 419 .vidioc_log_status = v4l2_ctrl_log_status, 420 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 421 .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 422}; 423 424static int rotate_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, 425 unsigned int *nplanes, unsigned int sizes[], 426 struct device *alloc_devs[]) 427{ 428 struct rotate_ctx *ctx = vb2_get_drv_priv(vq); 429 struct v4l2_pix_format *pix_fmt; 430 431 if (V4L2_TYPE_IS_OUTPUT(vq->type)) 432 pix_fmt = &ctx->src_fmt; 433 else 434 pix_fmt = &ctx->dst_fmt; 435 436 if (*nplanes) { 437 if (sizes[0] < pix_fmt->sizeimage) 438 return -EINVAL; 439 } else { 440 sizes[0] = pix_fmt->sizeimage; 441 *nplanes = 1; 442 } 443 444 return 0; 445} 446 447static int rotate_buf_prepare(struct vb2_buffer *vb) 448{ 449 struct vb2_queue *vq = vb->vb2_queue; 450 struct rotate_ctx *ctx = vb2_get_drv_priv(vq); 451 struct v4l2_pix_format *pix_fmt; 452 453 if (V4L2_TYPE_IS_OUTPUT(vq->type)) 454 pix_fmt = &ctx->src_fmt; 455 else 456 pix_fmt = &ctx->dst_fmt; 457 458 if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage) 459 return -EINVAL; 460 461 vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage); 462 463 return 0; 464} 465 466static void rotate_buf_queue(struct vb2_buffer *vb) 467{ 468 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 469 struct rotate_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 470 471 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 472} 473 474static void rotate_queue_cleanup(struct vb2_queue *vq, u32 state) 475{ 476 struct rotate_ctx *ctx = vb2_get_drv_priv(vq); 477 struct vb2_v4l2_buffer *vbuf; 478 479 do { 480 if (V4L2_TYPE_IS_OUTPUT(vq->type)) 481 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); 482 else 483 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); 484 485 if (vbuf) 486 v4l2_m2m_buf_done(vbuf, state); 487 } while (vbuf); 488} 489 490static int rotate_start_streaming(struct vb2_queue *vq, unsigned int count) 491{ 492 if (V4L2_TYPE_IS_OUTPUT(vq->type)) { 493 struct rotate_ctx *ctx = vb2_get_drv_priv(vq); 494 struct device *dev = ctx->dev->dev; 495 int ret; 496 497 ret = pm_runtime_resume_and_get(dev); 498 if (ret < 0) { 499 dev_err(dev, "Failed to enable module\n"); 500 501 return ret; 502 } 503 } 504 505 return 0; 506} 507 508static void rotate_stop_streaming(struct vb2_queue *vq) 509{ 510 if (V4L2_TYPE_IS_OUTPUT(vq->type)) { 511 struct rotate_ctx *ctx = vb2_get_drv_priv(vq); 512 513 pm_runtime_put(ctx->dev->dev); 514 } 515 516 rotate_queue_cleanup(vq, VB2_BUF_STATE_ERROR); 517} 518 519static const struct vb2_ops rotate_qops = { 520 .queue_setup = rotate_queue_setup, 521 .buf_prepare = rotate_buf_prepare, 522 .buf_queue = rotate_buf_queue, 523 .start_streaming = rotate_start_streaming, 524 .stop_streaming = rotate_stop_streaming, 525 .wait_prepare = vb2_ops_wait_prepare, 526 .wait_finish = vb2_ops_wait_finish, 527}; 528 529static int rotate_queue_init(void *priv, struct vb2_queue *src_vq, 530 struct vb2_queue *dst_vq) 531{ 532 struct rotate_ctx *ctx = priv; 533 int ret; 534 535 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 536 src_vq->io_modes = VB2_MMAP | VB2_DMABUF; 537 src_vq->drv_priv = ctx; 538 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 539 src_vq->min_buffers_needed = 1; 540 src_vq->ops = &rotate_qops; 541 src_vq->mem_ops = &vb2_dma_contig_memops; 542 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 543 src_vq->lock = &ctx->dev->dev_mutex; 544 src_vq->dev = ctx->dev->dev; 545 546 ret = vb2_queue_init(src_vq); 547 if (ret) 548 return ret; 549 550 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 551 dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; 552 dst_vq->drv_priv = ctx; 553 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); 554 dst_vq->min_buffers_needed = 2; 555 dst_vq->ops = &rotate_qops; 556 dst_vq->mem_ops = &vb2_dma_contig_memops; 557 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 558 dst_vq->lock = &ctx->dev->dev_mutex; 559 dst_vq->dev = ctx->dev->dev; 560 561 ret = vb2_queue_init(dst_vq); 562 if (ret) 563 return ret; 564 565 return 0; 566} 567 568static int rotate_s_ctrl(struct v4l2_ctrl *ctrl) 569{ 570 struct rotate_ctx *ctx = container_of(ctrl->handler, 571 struct rotate_ctx, 572 ctrl_handler); 573 struct v4l2_pix_format fmt; 574 575 switch (ctrl->id) { 576 case V4L2_CID_HFLIP: 577 ctx->hflip = ctrl->val; 578 break; 579 case V4L2_CID_VFLIP: 580 ctx->vflip = ctrl->val; 581 break; 582 case V4L2_CID_ROTATE: 583 rotate_set_cap_format(ctx, &fmt, ctrl->val); 584 585 /* Check if capture format needs to be changed */ 586 if (fmt.width != ctx->dst_fmt.width || 587 fmt.height != ctx->dst_fmt.height || 588 fmt.bytesperline != ctx->dst_fmt.bytesperline || 589 fmt.sizeimage != ctx->dst_fmt.sizeimage) { 590 struct vb2_queue *vq; 591 592 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 593 V4L2_BUF_TYPE_VIDEO_CAPTURE); 594 if (vb2_is_busy(vq)) 595 return -EBUSY; 596 597 rotate_set_cap_format(ctx, &ctx->dst_fmt, ctrl->val); 598 } 599 600 ctx->rotate = ctrl->val; 601 break; 602 default: 603 return -EINVAL; 604 } 605 606 return 0; 607} 608 609static const struct v4l2_ctrl_ops rotate_ctrl_ops = { 610 .s_ctrl = rotate_s_ctrl, 611}; 612 613static int rotate_setup_ctrls(struct rotate_ctx *ctx) 614{ 615 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); 616 617 v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops, 618 V4L2_CID_HFLIP, 0, 1, 1, 0); 619 620 v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops, 621 V4L2_CID_VFLIP, 0, 1, 1, 0); 622 623 v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops, 624 V4L2_CID_ROTATE, 0, 270, 90, 0); 625 626 if (ctx->ctrl_handler.error) { 627 int err = ctx->ctrl_handler.error; 628 629 v4l2_err(&ctx->dev->v4l2_dev, "control setup failed!\n"); 630 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 631 632 return err; 633 } 634 635 return v4l2_ctrl_handler_setup(&ctx->ctrl_handler); 636} 637 638static int rotate_open(struct file *file) 639{ 640 struct rotate_dev *dev = video_drvdata(file); 641 struct rotate_ctx *ctx = NULL; 642 int ret; 643 644 if (mutex_lock_interruptible(&dev->dev_mutex)) 645 return -ERESTARTSYS; 646 647 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 648 if (!ctx) { 649 mutex_unlock(&dev->dev_mutex); 650 return -ENOMEM; 651 } 652 653 /* default output format */ 654 ctx->src_fmt.pixelformat = V4L2_PIX_FMT_ARGB32; 655 ctx->src_fmt.field = V4L2_FIELD_NONE; 656 ctx->src_fmt.width = 640; 657 ctx->src_fmt.height = 480; 658 rotate_prepare_format(&ctx->src_fmt); 659 660 /* default capture format */ 661 rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate); 662 663 v4l2_fh_init(&ctx->fh, video_devdata(file)); 664 file->private_data = &ctx->fh; 665 ctx->dev = dev; 666 667 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, 668 &rotate_queue_init); 669 if (IS_ERR(ctx->fh.m2m_ctx)) { 670 ret = PTR_ERR(ctx->fh.m2m_ctx); 671 goto err_free; 672 } 673 674 v4l2_fh_add(&ctx->fh); 675 676 ret = rotate_setup_ctrls(ctx); 677 if (ret) 678 goto err_free; 679 680 ctx->fh.ctrl_handler = &ctx->ctrl_handler; 681 682 mutex_unlock(&dev->dev_mutex); 683 684 return 0; 685 686err_free: 687 kfree(ctx); 688 mutex_unlock(&dev->dev_mutex); 689 690 return ret; 691} 692 693static int rotate_release(struct file *file) 694{ 695 struct rotate_dev *dev = video_drvdata(file); 696 struct rotate_ctx *ctx = container_of(file->private_data, 697 struct rotate_ctx, fh); 698 699 mutex_lock(&dev->dev_mutex); 700 701 v4l2_ctrl_handler_free(&ctx->ctrl_handler); 702 v4l2_fh_del(&ctx->fh); 703 v4l2_fh_exit(&ctx->fh); 704 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); 705 706 kfree(ctx); 707 708 mutex_unlock(&dev->dev_mutex); 709 710 return 0; 711} 712 713static const struct v4l2_file_operations rotate_fops = { 714 .owner = THIS_MODULE, 715 .open = rotate_open, 716 .release = rotate_release, 717 .poll = v4l2_m2m_fop_poll, 718 .unlocked_ioctl = video_ioctl2, 719 .mmap = v4l2_m2m_fop_mmap, 720}; 721 722static const struct video_device rotate_video_device = { 723 .name = ROTATE_NAME, 724 .vfl_dir = VFL_DIR_M2M, 725 .fops = &rotate_fops, 726 .ioctl_ops = &rotate_ioctl_ops, 727 .minor = -1, 728 .release = video_device_release_empty, 729 .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, 730}; 731 732static const struct v4l2_m2m_ops rotate_m2m_ops = { 733 .device_run = rotate_device_run, 734}; 735 736static int rotate_probe(struct platform_device *pdev) 737{ 738 struct rotate_dev *dev; 739 struct video_device *vfd; 740 int irq, ret; 741 742 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 743 if (!dev) 744 return -ENOMEM; 745 746 dev->vfd = rotate_video_device; 747 dev->dev = &pdev->dev; 748 749 irq = platform_get_irq(pdev, 0); 750 if (irq <= 0) 751 return irq; 752 753 ret = devm_request_irq(dev->dev, irq, rotate_irq, 754 0, dev_name(dev->dev), dev); 755 if (ret) { 756 dev_err(dev->dev, "Failed to request IRQ\n"); 757 758 return ret; 759 } 760 761 dev->base = devm_platform_ioremap_resource(pdev, 0); 762 if (IS_ERR(dev->base)) 763 return PTR_ERR(dev->base); 764 765 dev->bus_clk = devm_clk_get(dev->dev, "bus"); 766 if (IS_ERR(dev->bus_clk)) { 767 dev_err(dev->dev, "Failed to get bus clock\n"); 768 769 return PTR_ERR(dev->bus_clk); 770 } 771 772 dev->mod_clk = devm_clk_get(dev->dev, "mod"); 773 if (IS_ERR(dev->mod_clk)) { 774 dev_err(dev->dev, "Failed to get mod clock\n"); 775 776 return PTR_ERR(dev->mod_clk); 777 } 778 779 dev->rstc = devm_reset_control_get(dev->dev, NULL); 780 if (IS_ERR(dev->rstc)) { 781 dev_err(dev->dev, "Failed to get reset control\n"); 782 783 return PTR_ERR(dev->rstc); 784 } 785 786 mutex_init(&dev->dev_mutex); 787 788 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); 789 if (ret) { 790 dev_err(dev->dev, "Failed to register V4L2 device\n"); 791 792 return ret; 793 } 794 795 vfd = &dev->vfd; 796 vfd->lock = &dev->dev_mutex; 797 vfd->v4l2_dev = &dev->v4l2_dev; 798 799 snprintf(vfd->name, sizeof(vfd->name), "%s", 800 rotate_video_device.name); 801 video_set_drvdata(vfd, dev); 802 803 ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); 804 if (ret) { 805 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); 806 807 goto err_v4l2; 808 } 809 810 v4l2_info(&dev->v4l2_dev, 811 "Device registered as /dev/video%d\n", vfd->num); 812 813 dev->m2m_dev = v4l2_m2m_init(&rotate_m2m_ops); 814 if (IS_ERR(dev->m2m_dev)) { 815 v4l2_err(&dev->v4l2_dev, 816 "Failed to initialize V4L2 M2M device\n"); 817 ret = PTR_ERR(dev->m2m_dev); 818 819 goto err_video; 820 } 821 822 platform_set_drvdata(pdev, dev); 823 824 pm_runtime_enable(dev->dev); 825 826 return 0; 827 828err_video: 829 video_unregister_device(&dev->vfd); 830err_v4l2: 831 v4l2_device_unregister(&dev->v4l2_dev); 832 833 return ret; 834} 835 836static int rotate_remove(struct platform_device *pdev) 837{ 838 struct rotate_dev *dev = platform_get_drvdata(pdev); 839 840 v4l2_m2m_release(dev->m2m_dev); 841 video_unregister_device(&dev->vfd); 842 v4l2_device_unregister(&dev->v4l2_dev); 843 844 pm_runtime_force_suspend(&pdev->dev); 845 846 return 0; 847} 848 849static int rotate_runtime_resume(struct device *device) 850{ 851 struct rotate_dev *dev = dev_get_drvdata(device); 852 int ret; 853 854 ret = clk_prepare_enable(dev->bus_clk); 855 if (ret) { 856 dev_err(dev->dev, "Failed to enable bus clock\n"); 857 858 return ret; 859 } 860 861 ret = clk_prepare_enable(dev->mod_clk); 862 if (ret) { 863 dev_err(dev->dev, "Failed to enable mod clock\n"); 864 865 goto err_bus_clk; 866 } 867 868 ret = reset_control_deassert(dev->rstc); 869 if (ret) { 870 dev_err(dev->dev, "Failed to apply reset\n"); 871 872 goto err_mod_clk; 873 } 874 875 return 0; 876 877err_mod_clk: 878 clk_disable_unprepare(dev->mod_clk); 879err_bus_clk: 880 clk_disable_unprepare(dev->bus_clk); 881 882 return ret; 883} 884 885static int rotate_runtime_suspend(struct device *device) 886{ 887 struct rotate_dev *dev = dev_get_drvdata(device); 888 889 reset_control_assert(dev->rstc); 890 891 clk_disable_unprepare(dev->mod_clk); 892 clk_disable_unprepare(dev->bus_clk); 893 894 return 0; 895} 896 897static const struct of_device_id rotate_dt_match[] = { 898 { .compatible = "allwinner,sun8i-a83t-de2-rotate" }, 899 { /* sentinel */ } 900}; 901MODULE_DEVICE_TABLE(of, rotate_dt_match); 902 903static const struct dev_pm_ops rotate_pm_ops = { 904 .runtime_resume = rotate_runtime_resume, 905 .runtime_suspend = rotate_runtime_suspend, 906}; 907 908static struct platform_driver rotate_driver = { 909 .probe = rotate_probe, 910 .remove = rotate_remove, 911 .driver = { 912 .name = ROTATE_NAME, 913 .of_match_table = rotate_dt_match, 914 .pm = &rotate_pm_ops, 915 }, 916}; 917module_platform_driver(rotate_driver); 918 919MODULE_LICENSE("GPL v2"); 920MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>"); 921MODULE_DESCRIPTION("Allwinner DE2 rotate driver");