1// SPDX-License-Identifier: GPL-2.0-or-later 2 3/* 4 * The Capture code for Fujitsu M-5MOLS ISP 5 * 6 * Copyright (C) 2011 Samsung Electronics Co., Ltd. 7 * Author: HeungJun Kim <riverful.kim@samsung.com> 8 * 9 * Copyright (C) 2009 Samsung Electronics Co., Ltd. 10 * Author: Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> 11 */ 12 13#include <linux/i2c.h> 14#include <linux/slab.h> 15#include <linux/irq.h> 16#include <linux/interrupt.h> 17#include <linux/delay.h> 18#include <linux/gpio.h> 19#include <linux/regulator/consumer.h> 20#include <linux/videodev2.h> 21#include <media/v4l2-ctrls.h> 22#include <media/v4l2-device.h> 23#include <media/v4l2-subdev.h> 24#include <media/i2c/m5mols.h> 25#include <media/drv-intf/exynos-fimc.h> 26 27#include "m5mols.h" 28#include "m5mols_reg.h" 29 30/** 31 * m5mols_read_rational - I2C read of a rational number 32 * @sd: sub-device, as pointed by struct v4l2_subdev 33 * @addr_num: numerator register 34 * @addr_den: denominator register 35 * @val: place to store the division result 36 * 37 * Read numerator and denominator from registers @addr_num and @addr_den 38 * respectively and return the division result in @val. 39 */ 40static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, 41 u32 addr_den, u32 *val) 42{ 43 u32 num, den; 44 45 int ret = m5mols_read_u32(sd, addr_num, &num); 46 if (!ret) 47 ret = m5mols_read_u32(sd, addr_den, &den); 48 if (ret) 49 return ret; 50 *val = den == 0 ? 0 : num / den; 51 return ret; 52} 53 54/** 55 * m5mols_capture_info - Gather captured image information 56 * @info: M-5MOLS driver data structure 57 * 58 * For now it gathers only EXIF information and file size. 59 */ 60static int m5mols_capture_info(struct m5mols_info *info) 61{ 62 struct m5mols_exif *exif = &info->cap.exif; 63 struct v4l2_subdev *sd = &info->sd; 64 int ret; 65 66 ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU, 67 EXIF_INFO_EXPTIME_DE, &exif->exposure_time); 68 if (ret) 69 return ret; 70 ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE, 71 &exif->shutter_speed); 72 if (ret) 73 return ret; 74 ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE, 75 &exif->aperture); 76 if (ret) 77 return ret; 78 ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE, 79 &exif->brightness); 80 if (ret) 81 return ret; 82 ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE, 83 &exif->exposure_bias); 84 if (ret) 85 return ret; 86 87 ret = m5mols_read_u16(sd, EXIF_INFO_ISO, &exif->iso_speed); 88 if (!ret) 89 ret = m5mols_read_u16(sd, EXIF_INFO_FLASH, &exif->flash); 90 if (!ret) 91 ret = m5mols_read_u16(sd, EXIF_INFO_SDR, &exif->sdr); 92 if (!ret) 93 ret = m5mols_read_u16(sd, EXIF_INFO_QVAL, &exif->qval); 94 if (ret) 95 return ret; 96 97 if (!ret) 98 ret = m5mols_read_u32(sd, CAPC_IMAGE_SIZE, &info->cap.main); 99 if (!ret) 100 ret = m5mols_read_u32(sd, CAPC_THUMB_SIZE, &info->cap.thumb); 101 if (!ret) 102 info->cap.total = info->cap.main + info->cap.thumb; 103 104 return ret; 105} 106 107int m5mols_start_capture(struct m5mols_info *info) 108{ 109 unsigned int framesize = info->cap.buf_size - M5MOLS_JPEG_TAGS_SIZE; 110 struct v4l2_subdev *sd = &info->sd; 111 int ret; 112 113 /* 114 * Synchronize the controls, set the capture frame resolution and color 115 * format. The frame capture is initiated during switching from Monitor 116 * to Capture mode. 117 */ 118 ret = m5mols_set_mode(info, REG_MONITOR); 119 if (!ret) 120 ret = m5mols_restore_controls(info); 121 if (!ret) 122 ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); 123 if (!ret) 124 ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution); 125 if (!ret) 126 ret = m5mols_write(sd, CAPP_JPEG_SIZE_MAX, framesize); 127 if (!ret) 128 ret = m5mols_set_mode(info, REG_CAPTURE); 129 if (!ret) 130 /* Wait until a frame is captured to ISP internal memory */ 131 ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); 132 if (ret) 133 return ret; 134 135 /* 136 * Initiate the captured data transfer to a MIPI-CSI receiver. 137 */ 138 ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); 139 if (!ret) 140 ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); 141 if (!ret) { 142 bool captured = false; 143 unsigned int size; 144 145 /* Wait for the capture completion interrupt */ 146 ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000); 147 if (!ret) { 148 captured = true; 149 ret = m5mols_capture_info(info); 150 } 151 size = captured ? info->cap.main : 0; 152 v4l2_dbg(1, m5mols_debug, sd, "%s: size: %d, thumb.: %d B\n", 153 __func__, size, info->cap.thumb); 154 155 v4l2_subdev_notify(sd, S5P_FIMC_TX_END_NOTIFY, &size); 156 } 157 158 return ret; 159} 160