int fimc_hw_wait_stop_input_dma(struct fimc_control *ctrl) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg = readl(ctrl->regs + S3C_MSCTRL); u32 status = S3C_MSCTRL_GET_INDMA_STATUS(cfg); int i = FIMC_FIFOOFF_CNT, j = FIMC_FIFOOFF_CNT; if (pdata->hw_ver == 0x40) return 0; while (status && i--) { cfg = readl(ctrl->regs + S3C_MSCTRL); status = S3C_MSCTRL_GET_INDMA_STATUS(cfg); } cfg = readl(ctrl->regs + S3C_CISTATUS); status = S3C_CISTATUS_GET_ENVID_STATUS(cfg); while (status && j--) { cfg = readl(ctrl->regs + S3C_CISTATUS); status = S3C_CISTATUS_GET_ENVID_STATUS(cfg); } if ((i < 1) || (j < 1)) { fimc_err("Fail : %s\n", __func__); return -EBUSY; } else { return 0; } }
int fimc_hwset_output_scan(struct fimc_control *ctrl, struct v4l2_pix_format *fmt) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg; /* nothing to do: FIMC40 not supported interlaced and weave output */ if (pdata->hw_ver == 0x40) return 0; cfg = readl(ctrl->regs + S3C_CISCCTRL); cfg &= ~S3C_CISCCTRL_SCAN_MASK; if (fmt->field == V4L2_FIELD_INTERLACED || fmt->field == V4L2_FIELD_INTERLACED_TB) cfg |= S3C_CISCCTRL_INTERLACE; else cfg |= S3C_CISCCTRL_PROGRESSIVE; writel(cfg, ctrl->regs + S3C_CISCCTRL); cfg = readl(ctrl->regs + S3C_CIOCTRL); cfg &= ~S3C_CIOCTRL_WEAVE_MASK; if ((ctrl->cap) && (fmt->field == V4L2_FIELD_INTERLACED_TB)) cfg |= S3C_CIOCTRL_WEAVE_OUT; writel(cfg, ctrl->regs + S3C_CIOCTRL); return 0; }
int fimc_hwset_scaler(struct fimc_control *ctrl) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg = readl(ctrl->regs + S3C_CISCCTRL); u32 cfg_ext = readl(ctrl->regs + S3C_CIEXTEN); cfg &= ~(S3C_CISCCTRL_SCALERBYPASS | S3C_CISCCTRL_SCALEUP_H | S3C_CISCCTRL_SCALEUP_V | S3C_CISCCTRL_MAIN_V_RATIO_MASK | S3C_CISCCTRL_MAIN_H_RATIO_MASK); cfg |= (S3C_CISCCTRL_CSCR2Y_WIDE | S3C_CISCCTRL_CSCY2R_WIDE); cfg_ext &= ~S3C_CIEXTEN_MAINHORRATIO_EXT_MASK; cfg_ext &= ~S3C_CIEXTEN_MAINVERRATIO_EXT_MASK; if (ctrl->sc.bypass) cfg |= S3C_CISCCTRL_SCALERBYPASS; if (ctrl->sc.scaleup_h) cfg |= S3C_CISCCTRL_SCALEUP_H; if (ctrl->sc.scaleup_v) cfg |= S3C_CISCCTRL_SCALEUP_V; if (pdata->hw_ver == 0x50) { cfg |= S3C_CISCCTRL_MAINHORRATIO((ctrl->sc.main_hratio >> 6)); cfg |= S3C_CISCCTRL_MAINVERRATIO((ctrl->sc.main_vratio >> 6)); cfg_ext |= S3C_CIEXTEN_MAINHORRATIO_EXT(ctrl->sc.main_vratio); cfg_ext |= S3C_CIEXTEN_MAINVERRATIO_EXT(ctrl->sc.main_vratio); writel(cfg_ext, ctrl->regs + S3C_CIEXTEN); } else {
int fimc_hwset_output_colorspace(struct fimc_control *ctrl, u32 pixelformat) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg; if (pdata->hw_ver != 0x40) { if (pixelformat == V4L2_PIX_FMT_YUV444) { cfg = readl(ctrl->regs + S3C_CIEXTEN); cfg |= S3C_CIEXTEN_YUV444_OUT; writel(cfg, ctrl->regs + S3C_CIEXTEN); return 0; } else { cfg = readl(ctrl->regs + S3C_CIEXTEN); cfg &= ~S3C_CIEXTEN_YUV444_OUT; writel(cfg, ctrl->regs + S3C_CIEXTEN); } } cfg = readl(ctrl->regs + S3C_CITRGFMT); cfg &= ~S3C_CITRGFMT_OUTFORMAT_MASK; switch (pixelformat) { case V4L2_PIX_FMT_JPEG: break; case V4L2_PIX_FMT_RGB565: /* fall through */ case V4L2_PIX_FMT_RGB32: cfg |= S3C_CITRGFMT_OUTFORMAT_RGB; break; case V4L2_PIX_FMT_YUYV: /* fall through */ case V4L2_PIX_FMT_UYVY: /* fall through */ case V4L2_PIX_FMT_VYUY: /* fall through */ case V4L2_PIX_FMT_YVYU: cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422_1PLANE; break; case V4L2_PIX_FMT_NV16: /* fall through */ case V4L2_PIX_FMT_NV61: /* fall through */ case V4L2_PIX_FMT_YUV422P: cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR422; break; case V4L2_PIX_FMT_YUV420: /* fall through */ case V4L2_PIX_FMT_NV12: /* fall through */ case V4L2_PIX_FMT_NV12T: /* fall through */ case V4L2_PIX_FMT_NV21: cfg |= S3C_CITRGFMT_OUTFORMAT_YCBCR420; break; default: fimc_err("%s: invalid pixel format\n", __func__); break; } writel(cfg, ctrl->regs + S3C_CITRGFMT); return 0; }
static int fimc_open(struct file *filp) { struct fimc_control *ctrl; struct s3c_platform_fimc *pdata; int ret; ctrl = video_get_drvdata(video_devdata(filp)); pdata = to_fimc_plat(ctrl->dev); mutex_lock(&ctrl->lock); if (atomic_read(&ctrl->in_use)) { ret = -EBUSY; goto resource_busy; } else { atomic_inc(&ctrl->in_use); } if (pdata->clk_on) pdata->clk_on(to_platform_device(ctrl->dev), ctrl->clk); #if defined(CONFIG_VIDEO_FIMC_FIFO) fimc_hwset_clksrc(ctrl,FIMC_SCLK); fimc_hwset_sclk_enable(ctrl); #endif if (pdata->hw_ver == 0x40) fimc_hw_reset_camera(ctrl); /* Apply things to interface register */ fimc_hwset_reset(ctrl); filp->private_data = ctrl; ctrl->fb.open_fifo = s3cfb_open_fifo; ctrl->fb.close_fifo = s3cfb_close_fifo; ret = s3cfb_direct_ioctl(ctrl->id, S3CFB_GET_LCD_WIDTH, (unsigned long)&ctrl->fb.lcd_hres); if (ret < 0) fimc_err("Fail: S3CFB_GET_LCD_WIDTH\n"); ret = s3cfb_direct_ioctl(ctrl->id, S3CFB_GET_LCD_HEIGHT, (unsigned long)&ctrl->fb.lcd_vres); if (ret < 0) fimc_err("Fail: S3CFB_GET_LCD_HEIGHT\n"); ctrl->mem.curr = ctrl->mem.base; ctrl->status = FIMC_STREAMOFF; mutex_unlock(&ctrl->lock); return 0; resource_busy: mutex_unlock(&ctrl->lock); return ret; }
int fimc_hwset_input_offset(struct fimc_control *ctrl, u32 pixelformat, struct v4l2_rect *bounds, struct v4l2_rect *crop) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); if (pdata->hw_ver == 0x50) fimc50_hwset_input_offset(ctrl, pixelformat, bounds, crop); else fimc40_hwset_input_offset(ctrl, pixelformat, bounds, crop); return 0; }
static int fimc_init_global(struct platform_device *pdev) { struct fimc_control *ctrl; struct s3c_platform_fimc *pdata; struct s3c_platform_camera *cam; struct clk *srclk; int id, i; pdata = to_fimc_plat(&pdev->dev); id = pdev->id; ctrl = get_fimc_ctrl(id); /* Registering external camera modules. re-arrange order to be sure */ for (i = 0; i < FIMC_MAXCAMS; i++) { cam = pdata->camera[i]; if (!cam) break; /* WriteBack doesn't need clock setting */ if(cam->id == CAMERA_WB) { fimc_dev->camera[cam->id] = cam; break; } srclk = clk_get(&pdev->dev, cam->srclk_name); if (IS_ERR(srclk)) { fimc_err("%s: failed to get mclk source\n", __func__); return -EINVAL; } /* mclk */ cam->clk = clk_get(&pdev->dev, cam->clk_name); if (IS_ERR(cam->clk)) { fimc_err("%s: failed to get mclk source\n", __func__); return -EINVAL; } if (cam->clk->set_parent) { cam->clk->parent = srclk; cam->clk->set_parent(cam->clk, srclk); } /* Assign camera device to fimc */ fimc_dev->camera[cam->id] = cam; } fimc_dev->initialized = 1; return 0; }
int fimc_hwset_input_lineskip(struct fimc_control *ctrl) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg = 0; if (pdata->hw_ver == 0x40) return 0; cfg = S3C_CIILINESKIP(ctrl->sc.skipline); writel(cfg, ctrl->regs + S3C_CIILINESKIP_Y); writel(cfg, ctrl->regs + S3C_CIILINESKIP_CB); writel(cfg, ctrl->regs + S3C_CIILINESKIP_CR); return 0; }
static int fimc_init_global(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct s3c_platform_camera *cam; struct clk *srclk; int i; #ifdef VIEW_FUNCTION_CALL printk("[FIMC_DEV] %s(%d)\n", __func__, __LINE__); #endif pdata = to_fimc_plat(&pdev->dev); /* Registering external camera modules. re-arrange order to be sure */ for (i = 0; i < FIMC_MAXCAMS; i++) { cam = pdata->camera[i]; if (!cam) break; srclk = clk_get(&pdev->dev, cam->srclk_name); if (IS_ERR(srclk)) { dev_err(&pdev->dev, "%s: failed to get mclk source\n", __func__); return -EINVAL; } /* mclk */ cam->clk = clk_get(&pdev->dev, cam->clk_name); if (IS_ERR(cam->clk)) { dev_err(&pdev->dev, "%s: failed to get mclk source\n", __func__); return -EINVAL; } if (cam->clk->set_parent) { cam->clk->parent = srclk; cam->clk->set_parent(cam->clk, srclk); } /* Assign camera device to fimc */ fimc_dev->camera[cam->id] = cam; } fimc_dev->initialized = 1; return 0; }
int fimc_hwset_camera_type(struct fimc_control *ctrl) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); switch (pdata->hw_ver) { case 0x40: fimc40_hwset_camera_type(ctrl); break; case 0x43: case 0x45: fimc43_hwset_camera_type(ctrl); break; default: fimc43_hwset_camera_type(ctrl); break; } return 0; }
static int s3c_fimc_unregister_controller(struct platform_device *pdev) { struct s3c_fimc_control *ctrl; struct s3c_platform_fimc *pdata; int id = pdev->id; ctrl = &s3c_fimc.ctrl[id]; s3c_fimc_free_output_memory(&ctrl->out_frame); pdata = to_fimc_plat(ctrl->dev); if (!pdata->shared_io) iounmap(ctrl->regs); memset(ctrl, 0, sizeof(*ctrl)); return 0; }
int fimc_hwset_intput_field(struct fimc_control *ctrl, enum v4l2_field field) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg; if (pdata->hw_ver == 0x40) return 0; cfg = readl(ctrl->regs + S3C_MSCTRL); cfg &= ~S3C_MSCTRL_FIELD_MASK; if (field == V4L2_FIELD_NONE) cfg |= S3C_MSCTRL_FIELD_NORMAL; else if (field == V4L2_FIELD_INTERLACED_TB) cfg |= S3C_MSCTRL_FIELD_WEAVE; writel(cfg, ctrl->regs + S3C_MSCTRL); return 0; }
static int fimc_streamoff(struct file *filp, void *fh, enum v4l2_buf_type i) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; struct s3c_platform_fimc *pdata; int ret = -1; pdata = to_fimc_plat(ctrl->dev); if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_streamoff_capture(fh); } else if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT) { ret = fimc_streamoff_output(fh); } else { fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } return ret; }
static int fimc_unregister_controller(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct fimc_control *ctrl; int id = pdev->id; #ifdef VIEW_FUNCTION_CALL printk("[FIMC_DEV] %s(%d)\n", __func__, __LINE__); #endif pdata = to_fimc_plat(&pdev->dev); ctrl = get_fimc_ctrl(id); if (pdata->clk_off) pdata->clk_off(pdev, ctrl->clk); iounmap(ctrl->regs); memset(ctrl, 0, sizeof(*ctrl)); return 0; }
int fimc_hw_wait_winoff(struct fimc_control *ctrl) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg = readl(ctrl->regs + S3C_CISTATUS); u32 status = S3C_CISTATUS_GET_LCD_STATUS(cfg); int i = FIMC_FIFOOFF_CNT; if (pdata->hw_ver == 0x40) return 0; while (status && i--) { cfg = readl(ctrl->regs + S3C_CISTATUS); status = S3C_CISTATUS_GET_LCD_STATUS(cfg); } if (i < 1) { fimc_err("Fail : %s\n", __func__); return -EBUSY; } else return 0; }
int fimc_resume(struct platform_device *pdev) { struct fimc_control *ctrl; struct s3c_platform_fimc *pdata; int id = pdev->id; ctrl = get_fimc_ctrl(id); pdata = to_fimc_plat(ctrl->dev); if (pdata->clk_on) pdata->clk_on(pdev, ctrl->clk); if (ctrl->out) fimc_resume_out(ctrl); else if (ctrl->cap) fimc_resume_cap(ctrl); else ctrl->status = FIMC_STREAMOFF; return 0; }
int fimc_hwset_scaler(struct fimc_control *ctrl, struct fimc_scaler *sc) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); switch (pdata->hw_ver) { case 0x40: fimc40_hwset_scaler(ctrl, sc); break; case 0x43: case 0x45: fimc43_hwset_scaler(ctrl, sc); break; case 0x50: fimc50_hwset_scaler(ctrl, sc); break; default: fimc43_hwset_scaler(ctrl, sc); break; } return 0; }
int fimc_suspend(struct platform_device *pdev, pm_message_t state) { struct fimc_control *ctrl; struct s3c_platform_fimc *pdata; int id; id = pdev->id; ctrl = get_fimc_ctrl(id); pdata = to_fimc_plat(ctrl->dev); if (ctrl->out) fimc_suspend_out(ctrl); else if (ctrl->cap) fimc_suspend_cap(ctrl); else ctrl->status = FIMC_OFF_SLEEP; if (pdata->clk_off) pdata->clk_off(pdev, ctrl->clk); return 0; }
static int fimc_unregister_controller(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct fimc_control *ctrl; int id = pdev->id; pdata = to_fimc_plat(&pdev->dev); ctrl = get_fimc_ctrl(id); free_irq(ctrl->irq, ctrl); mutex_destroy(&ctrl->lock); mutex_destroy(&ctrl->v4l2_lock); kfree(&ctrl->wq); if (pdata->clk_off) pdata->clk_off(pdev, ctrl->clk); iounmap(ctrl->regs); memset(ctrl, 0, sizeof(*ctrl)); return 0; }
static int fimc_g_ctrl(struct file *filp, void *fh, struct v4l2_control *c) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); int ret = -1; /* can get hw version at any time */ if (c->id == V4L2_CID_FIMC_VERSION) { c->value = pdata->hw_ver; return 0; } if (ctrl->cap != NULL) { ret = fimc_g_ctrl_capture(fh, c); } else if (ctrl->out != NULL) { ret = fimc_g_ctrl_output(fh, c); } else { fimc_err("%s: Invalid case\n", __func__); return -EINVAL; } return ret; }
int fimc_hwset_org_output_size(struct fimc_control *ctrl, u32 width, u32 height) { struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); u32 cfg = 0; cfg |= S3C_ORGOSIZE_HORIZONTAL(width); cfg |= S3C_ORGOSIZE_VERTICAL(height); writel(cfg, ctrl->regs + S3C_ORGOSIZE); if (pdata->hw_ver != 0x40) { cfg = readl(ctrl->regs + S3C_CIGCTRL); cfg &= ~S3C_CIGCTRL_CSC_MASK; if (width >= FIMC_HD_WIDTH) cfg |= S3C_CIGCTRL_CSC_ITU709; else cfg |= S3C_CIGCTRL_CSC_ITU601; writel(cfg, ctrl->regs + S3C_CIGCTRL); } return 0; }
/* * Assign v4l2 device and subdev to fimc * it is called per every fimc ctrl registering */ static int fimc_configure_subdev(struct platform_device *pdev, int id) { struct s3c_platform_fimc *pdata; struct s3c_platform_camera *cam; struct i2c_adapter *i2c_adap; struct i2c_board_info *i2c_info; struct v4l2_subdev *sd; struct fimc_control *ctrl; unsigned short addr; char *name; ctrl = get_fimc_ctrl(id); pdata = to_fimc_plat(&pdev->dev); cam = pdata->camera[id]; /* Subdev registration */ if (cam) { i2c_adap = i2c_get_adapter(cam->i2c_busnum); if (!i2c_adap) { fimc_info1("subdev i2c_adapter missing-skip " "registration\n"); } i2c_info = cam->info; if (!i2c_info) { fimc_err("%s: subdev i2c board info missing\n", __func__); return -ENODEV; } name = i2c_info->type; if (!name) { fimc_info1("subdev i2c dirver name missing-skip " "registration\n"); return -ENODEV; } addr = i2c_info->addr; if (!addr) { fimc_info1("subdev i2c address missing-skip " "registration\n"); return -ENODEV; } /* * NOTE: first time subdev being registered, * s_config is called and try to initialize subdev device * but in this point, we are not giving MCLK and power to subdev * so nothing happens but pass platform data through */ sd = v4l2_i2c_new_subdev_board(&ctrl->v4l2_dev, i2c_adap, name, i2c_info, &addr); if (!sd) { fimc_err("%s: v4l2 subdev board registering failed\n", __func__); } /* Assign camera device to fimc */ fimc_dev->camera[cam->id] = cam; /* Assign subdev to proper camera device pointer */ fimc_dev->camera[cam->id]->sd = sd; } return 0; }
static int fimc_open(struct file *filp) { struct fimc_control *ctrl; struct s3c_platform_fimc *pdata; unsigned long flags; int ret; u32 cfg; #ifdef VIEW_FUNCTION_CALL printk("[FIMC_DEV] %s(%d)\n", __func__, __LINE__); #endif /* An ugly hack to make the i2c pins output low */ if (unlikely(make_i2c_pin_low == 1)) { cfg = readl(S5P64XX_GPD1DAT); cfg &= ~(0x1 << 0); writel(cfg, S5P64XX_GPD1DAT); cfg = readl(S5P64XX_GPD1DAT); cfg &= ~(0x1 << 1); writel(cfg, S5P64XX_GPD1DAT); make_i2c_pin_low = 0; } ctrl = video_get_drvdata(video_devdata(filp)); #ifdef S5P6442_POWER_GATING_CAM del_timer(&g_fimc_domain_timer); // fimc0 controller for Camera if(ctrl->id == CAM_ID){ spin_lock_irqsave(&fimc_domain_lock, flags); gFIMC_CNT[CAM_ID]++; s5p6442_idle_pm_gpiocfg(S5P6442_CAM_ID, S5P6442_ACTIVE_MODE); s5p6442_pwrgate_config(S5P6442_CAM_ID, S5P6442_ACTIVE_MODE); spin_unlock_irqrestore(&fimc_domain_lock, flags); } // gFIMC_CNT++; // } #endif #ifdef CONFIG_CPU_FREQ if(ctrl->id == CAM_ID){ set_dvfs_level(0); } #endif /* CONFIG_CPU_FREQ */ pdata = to_fimc_plat(ctrl->dev); mutex_lock(&ctrl->lock); if (atomic_read(&ctrl->in_use)) { ret = -EBUSY; goto resource_busy; } else { atomic_inc(&ctrl->in_use); } if (pdata->clk_on) pdata->clk_on(to_platform_device(ctrl->dev), ctrl->clk); /* Apply things to interface register */ fimc_hwset_reset(ctrl); filp->private_data = ctrl; ctrl->fb.open_fifo = s3cfb_open_fifo; ctrl->fb.close_fifo = s3cfb_close_fifo; ret = s3cfb_direct_ioctl(ctrl->id, S3CFB_GET_LCD_WIDTH, (unsigned long)&ctrl->fb.lcd_hres); if (ret < 0) dev_err(ctrl->dev, "Fail: S3CFB_GET_LCD_WIDTH\n"); ret = s3cfb_direct_ioctl(ctrl->id, S3CFB_GET_LCD_HEIGHT, (unsigned long)&ctrl->fb.lcd_vres); if (ret < 0) dev_err(ctrl->dev, "Fail: S3CFB_GET_LCD_HEIGHT\n"); ctrl->status = FIMC_STREAMOFF; #if 0 /* To do : have to send ctrl to the fimd driver. */ ret = s3cfb_direct_ioctl(ctrl->id, S3CFB_SET_SUSPEND_FIFO, (unsigned long)fimc_sleep); if (ret < 0) dev_err(ctrl->dev, "s3cfb_direct_ioctl(S3CFB_SET_SUSPEND_FIFO) fail\n"); ret = s3cfb_direct_ioctl(ctrl->id, S3CFB_SET_RESUME_FIFO, (unsigned long)fimc_wakeup); if (ret < 0) dev_err(ctrl->dev, "s3cfb_direct_ioctl(S3CFB_SET_SUSPEND_FIFO) fail\n"); #endif mutex_unlock(&ctrl->lock); return 0; resource_busy: mutex_unlock(&ctrl->lock); return ret; }
static int fimc_release(struct file *filp) { struct fimc_control *ctrl = filp->private_data; struct s3c_platform_fimc *pdata; unsigned long flags; int ret = 0, i; #ifdef VIEW_FUNCTION_CALL printk("[FIMC_DEV] %s(%d)\n", __func__, __LINE__); #endif pdata = to_fimc_plat(ctrl->dev); atomic_dec(&ctrl->in_use); filp->private_data = NULL; /* FIXME: turning off actual working camera */ if (ctrl->cam) { /* shutdown the MCLK */ clk_disable(ctrl->cam->clk); /* shutdown */ if (ctrl->cam->cam_power) ctrl->cam->cam_power(0); /* should be initialized at the next open */ ctrl->cam->initialized = 0; } if (ctrl->cap) { for (i = 0; i < FIMC_CAPBUFS; i++) { fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 0); fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 1); } kfree(ctrl->cap); ctrl->cap = NULL; } if (ctrl->out) { if (ctrl->status != FIMC_STREAMOFF) { ret = fimc_outdev_stop_streaming(ctrl); if (ret < 0) dev_err(ctrl->dev, "Fail: fimc_stop_streaming\n"); ctrl->status = FIMC_STREAMOFF; } kfree(ctrl->out); ctrl->out = NULL; } if (pdata->clk_off) pdata->clk_off(to_platform_device(ctrl->dev), ctrl->clk); #ifdef S5P6442_POWER_GATING_CAM // gFIMC_CNT--; if(ctrl->id == CAM_ID){ spin_lock_irqsave(&fimc_domain_lock, flags); s5p6442_idle_pm_gpiocfg(S5P6442_CAM_ID, S5P6442_LP_MODE); gFIMC_CNT[ctrl->id]--; if((gFIMC_CNT[0] <= 0) && (gFIMC_CNT[1] <= 0) && (gFIMC_CNT[2] <= 0)){ s5p6442_pwrgate_config(S5P6442_CAM_ID, S5P6442_LP_MODE); } spin_unlock_irqrestore(&fimc_domain_lock, flags); } #endif #ifdef CONFIG_CPU_FREQ if(ctrl->id == CAM_ID){ set_dvfs_level(1); } #endif /* CONFIG_CPU_FREQ */ dev_info(ctrl->dev, "%s: successfully released\n", __func__); return 0; }
static int __devinit fimc_probe(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct fimc_control *ctrl; int ret; if (!fimc_dev) { fimc_dev = kzalloc(sizeof(*fimc_dev), GFP_KERNEL); if (!fimc_dev) { dev_err(&pdev->dev, "%s: not enough memory\n", __func__); goto err_fimc; } } ctrl = fimc_register_controller(pdev); if (!ctrl) { printk(KERN_ERR "%s: cannot register fimc\n", __func__); goto err_fimc; } pdata = to_fimc_plat(&pdev->dev); if (pdata->cfg_gpio) pdata->cfg_gpio(pdev); /* V4L2 device-subdev registration */ ret = v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev); if (ret) { fimc_err("%s: v4l2 device register failed\n", __func__); goto err_v4l2; } /* things to initialize once */ if (!fimc_dev->initialized) { ret = fimc_init_global(pdev); if (ret) goto err_global; } /* v4l2 subdev configuration */ ret = fimc_configure_subdev(pdev, ctrl->id); if (ret) { fimc_err("%s: subdev[%d] registering failed\n", __func__, ctrl->id); } /* video device register */ ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id); if (ret) { fimc_err("%s: cannot register video driver\n", __func__); goto err_global; } video_set_drvdata(ctrl->vd, ctrl); ret = device_create_file(&(pdev->dev), &dev_attr_log_level); if (ret < 0) fimc_err("failed to add sysfs entries\n"); fimc_info1("controller %d registered successfully\n", ctrl->id); return 0; err_global: clk_disable(ctrl->clk); clk_put(ctrl->clk); err_v4l2: fimc_unregister_controller(pdev); err_fimc: return -EINVAL; }
static struct fimc_control *fimc_register_controller(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct fimc_control *ctrl; struct resource *res; int id, mdev_id; id = pdev->id; mdev_id = S3C_MDEV_FIMC0 + id; pdata = to_fimc_plat(&pdev->dev); ctrl = get_fimc_ctrl(id); ctrl->id = id; ctrl->dev = &pdev->dev; ctrl->vd = &fimc_video_device[id]; ctrl->vd->minor = id; /* alloc from bank1 as default */ ctrl->mem.base = s3c_get_media_memory_bank(mdev_id, 1); ctrl->mem.size = s3c_get_media_memsize_bank(mdev_id, 1); ctrl->mem.curr = ctrl->mem.base; ctrl->status = FIMC_STREAMOFF; ctrl->limit = &fimc_limits[id]; ctrl->log = FIMC_LOG_DEFAULT; sprintf(ctrl->name, "%s%d", FIMC_NAME, id); strcpy(ctrl->vd->name, ctrl->name); atomic_set(&ctrl->in_use, 0); mutex_init(&ctrl->lock); mutex_init(&ctrl->v4l2_lock); spin_lock_init(&ctrl->lock_in); spin_lock_init(&ctrl->lock_out); init_waitqueue_head(&ctrl->wq); /* get resource for io memory */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { fimc_err("%s: failed to get io memory region\n", __func__); return NULL; } /* request mem region */ res = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (!res) { fimc_err("%s: failed to request io memory region\n", __func__); return NULL; } /* ioremap for register block */ ctrl->regs = ioremap(res->start, res->end - res->start + 1); if (!ctrl->regs) { fimc_err("%s: failed to remap io region\n", __func__); return NULL; } /* irq */ ctrl->irq = platform_get_irq(pdev, 0); if (request_irq(ctrl->irq, fimc_irq, IRQF_DISABLED, ctrl->name, ctrl)) fimc_err("%s: request_irq failed\n", __func__); fimc_hwset_reset(ctrl); return ctrl; }
static int fimc_release(struct file *filp) { struct fimc_control *ctrl = filp->private_data; struct s3c_platform_fimc *pdata; struct fimc_overlay_buf *buf; struct mm_struct *mm = current->mm; int ret = 0, i; ctrl->mem.curr = ctrl->mem.base; atomic_dec(&ctrl->in_use); filp->private_data = NULL; pdata = to_fimc_plat(ctrl->dev); /* FIXME: turning off actual working camera */ if (ctrl->cam) { /* shutdown the MCLK */ clk_disable(ctrl->cam->clk); /* shutdown */ if (ctrl->cam->cam_power) ctrl->cam->cam_power(0); /* should be initialized at the next open */ ctrl->cam->initialized = 0; } if (ctrl->cap) { for (i = 0; i < FIMC_CAPBUFS; i++) { fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 0); fimc_dma_free(ctrl, &ctrl->cap->bufs[i], 1); } kfree(ctrl->cap); ctrl->cap = NULL; } if (ctrl->out) { if (ctrl->status != FIMC_STREAMOFF) { ret = fimc_outdev_stop_streaming(ctrl); if (ret < 0) fimc_err("Fail: fimc_stop_streaming\n"); ctrl->status = FIMC_STREAMOFF; } buf = &ctrl->out->overlay.buf; for (i = 0; i < FIMC_OUTBUFS; i++) { if (buf->vir_addr[i]) { ret = do_munmap(mm, buf->vir_addr[i], buf->size[i]); if (ret < 0) fimc_err("%s: do_munmap fail\n", __func__); } } kfree(ctrl->out); ctrl->out = NULL; } if (pdata->clk_off) pdata->clk_off(to_platform_device(ctrl->dev), ctrl->clk); fimc_info1("%s: successfully released\n", __func__); return 0; }
static int fimc_init_camera(struct fimc_control *ctrl) { struct fimc_global *fimc = get_fimc_dev(); struct s3c_platform_fimc *pdata; struct s3c_platform_camera *cam; struct v4l2_streamparm stream; int ret; pdata = to_fimc_plat(ctrl->dev); if (pdata->default_cam >= FIMC_MAXCAMS) { dev_err(ctrl->dev, "%s: invalid camera index\n", __func__); return -EINVAL; } if (!fimc->camera[pdata->default_cam]) { dev_err(ctrl->dev, "no external camera device\n"); return -ENODEV; } /* * ctrl->cam may not be null if already s_input called, * otherwise, that should be default_cam if ctrl->cam is null. */ if (!ctrl->cam) ctrl->cam = fimc->camera[pdata->default_cam]; cam = ctrl->cam; /* do nothing if already initialized */ if (cam->initialized) return 0; /* * WriteBack mode doesn't need to set clock and power, * but it needs to set source width, height depend on LCD resolution. */ if (cam->id == CAMERA_WB) { s3cfb_direct_ioctl(0, S3CFB_GET_LCD_WIDTH, (unsigned long)&cam->width); s3cfb_direct_ioctl(0, S3CFB_GET_LCD_HEIGHT, (unsigned long)&cam->height); cam->window.width = cam->width; cam->window.height = cam->height; cam->initialized = 1; return 0; } /* set rate for mclk */ if (cam->clk->set_rate) { clk_disable(cam->clk); cam->clk->set_rate(cam->clk, cam->clk_rate); clk_enable(cam->clk); dev_info(ctrl->dev, "clock for camera: %d\n", cam->clk_rate); } /* enable camera power if needed */ if (cam->cam_power) cam->cam_power(1); /* camera s/w reset*/ fimc_hwset_hw_reset(); /* subdev call for init */ ret = v4l2_subdev_call(cam->sd, core, init, 0); if (ret == -ENOIOCTLCMD) { dev_err(ctrl->dev, "%s: init subdev api not supported\n", __func__); return ret; } /*set resolution SVGA*/ stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; stream.parm.capture.capturemode = 0; ret = v4l2_subdev_call(cam->sd, video, s_parm, &stream); if (ret == -ENOIOCTLCMD) { dev_err(ctrl->dev, "%s: init subdev api not supported\n", __func__); return ret; } if (cam->type == CAM_TYPE_MIPI) { /* * subdev call for sleep/wakeup: * no error although no s_stream api support */ v4l2_subdev_call(cam->sd, video, s_stream, 0); s3c_csis_start(cam->mipi_lanes, cam->mipi_settle, \ cam->mipi_align, cam->width, cam->height); v4l2_subdev_call(cam->sd, video, s_stream, 1); } cam->initialized = 1; return 0; }
static struct s3c_fimc_control *s3c_fimc_register_controller(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct s3c_fimc_control *ctrl; struct resource *res; int i = S3C_FIMC_MAX_CTRLS - 1; int id = pdev->id; pdata = to_fimc_plat(&pdev->dev); //printk("[CAM]s3c_fimc_register_controller.id=%d\n",id); ctrl = &s3c_fimc.ctrl[id]; ctrl->id = id; ctrl->dev = &pdev->dev; ctrl->vd = &s3c_fimc_video_device[id]; ctrl->rot90 = 0; ctrl->vd->minor = id; ctrl->out_frame.nr_frames = pdata->nr_frames; ctrl->out_frame.skip_frames = 0; ctrl->scaler.line_length = pdata->line_length; sprintf(ctrl->name, "%s%d", S3C_FIMC_NAME, id); strcpy(ctrl->vd->name, ctrl->name); ctrl->open_lcdfifo = s3cfb_enable_local; ctrl->close_lcdfifo = s3cfb_enable_dma; atomic_set(&ctrl->in_use, 0); mutex_init(&ctrl->lock); init_waitqueue_head(&ctrl->waitq); /* get resource for io memory */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { err("failed to get io memory region\n"); return NULL; } if (!pdata->shared_io) { /* request mem region */ res = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (!res) { err("failed to request io memory region\n"); return NULL; } /* ioremap for register block */ ctrl->regs = ioremap(res->start, res->end - res->start + 1); } else { while (i >= 0 && ctrl->regs == NULL) { ctrl->regs = s3c_fimc.ctrl[i].regs; i--; } } if (!ctrl->regs) { err("failed to remap io region\n"); return NULL; } /* irq */ ctrl->irq = platform_get_irq(pdev, 0); if (request_irq(ctrl->irq, s3c_fimc_irq, IRQF_DISABLED, ctrl->name, ctrl)) err("request_irq failed\n"); s3c_fimc_reset(ctrl); s3c_fimc_set_active_camera(ctrl, 0);//note: only one camera type return ctrl; }
static int s3c_fimc_probe(struct platform_device *pdev) { struct s3c_platform_fimc *pdata; struct s3c_fimc_control *ctrl; struct clk *srclk; int ret; ctrl = s3c_fimc_register_controller(pdev); if (!ctrl) { err("cannot register fimc controller\n"); goto err_fimc; } pdata = to_fimc_plat(&pdev->dev); if (pdata->cfg_gpio) pdata->cfg_gpio(pdev); /* fimc source clock */ srclk = clk_get(&pdev->dev, pdata->srclk_name); if (IS_ERR(srclk)) { err("failed to get source clock of fimc\n"); goto err_clk_io; } /* fimc clock */ ctrl->clock = clk_get(&pdev->dev, pdata->clk_name); if (IS_ERR(ctrl->clock)) { err("failed to get fimc clock source\n"); goto err_clk_io; } /* set parent clock */ if (ctrl->clock->set_parent) ctrl->clock->set_parent(ctrl->clock, srclk); /* set clockrate for FIMC interface block */ if (ctrl->clock->set_rate) ctrl->clock->set_rate(ctrl->clock, pdata->clockrate); clk_enable(ctrl->clock); /* things to initialize once */ if (ctrl->id == 0) { ret = s3c_fimc_init_global(pdev); if (ret) goto err_global; } ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id); if (ret) { err("cannot register video driver\n"); goto err_video; } info("controller %d registered successfully\n", ctrl->id); return 0; err_video: clk_put(s3c_fimc.cam_clock); err_global: clk_disable(ctrl->clock); clk_put(ctrl->clock); err_clk_io: s3c_fimc_unregister_controller(pdev); err_fimc: return -EINVAL; }