tcm825x.c revision a5e90862114124d79e1a3f34641b00fec51d1806
1a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 2a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * drivers/media/video/tcm825x.c 3a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 4a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * TCM825X camera sensor driver. 5a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 6a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Copyright (C) 2007 Nokia Corporation. 7a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 8a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Contact: Sakari Ailus <sakari.ailus@nokia.com> 9a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 10a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Based on code from David Cohen <david.cohen@indt.org.br> 11a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 12a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * This driver was based on ov9640 sensor driver from MontaVista 13a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 14a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * This program is free software; you can redistribute it and/or 15a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * modify it under the terms of the GNU General Public License 16a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * version 2 as published by the Free Software Foundation. 17a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 18a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * This program is distributed in the hope that it will be useful, but 19a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * WITHOUT ANY WARRANTY; without even the implied warranty of 20a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * General Public License for more details. 22a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 23a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * You should have received a copy of the GNU General Public License 24a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * along with this program; if not, write to the Free Software 25a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 26a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 02110-1301 USA 27a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 28a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 29a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#include <linux/i2c.h> 30a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#include <media/v4l2-int-device.h> 31a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 32a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#include "tcm825x.h" 33a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 34a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 35a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * The sensor has two fps modes: the lower one just gives half the fps 36a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * at the same xclk than the high one. 37a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 38a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define MAX_FPS 30 39a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define MIN_FPS 8 40a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define MAX_HALF_FPS (MAX_FPS / 2) 41a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define HIGH_FPS_MODE_LOWER_LIMIT 14 42a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define DEFAULT_FPS MAX_HALF_FPS 43a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 44a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstruct tcm825x_sensor { 45a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus const struct tcm825x_platform_data *platform_data; 46a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_int_device *v4l2_int_device; 47a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct i2c_client *i2c_client; 48a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_pix_format pix; 49a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_fract timeperframe; 50a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus}; 51a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 52a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* list of image formats supported by TCM825X sensor */ 53a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct v4l2_fmtdesc tcm825x_formats[] = { 54a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 55a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .description = "YUYV (YUV 4:2:2), packed", 56a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .pixelformat = V4L2_PIX_FMT_UYVY, 57a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, { 58a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* Note: V4L2 defines RGB565 as: 59a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 60a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Byte 0 Byte 1 61a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 62a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 63a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * We interpret RGB565 as: 64a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 65a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Byte 0 Byte 1 66a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 67a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 68a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .description = "RGB565, le", 69a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .pixelformat = V4L2_PIX_FMT_RGB565, 70a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 71a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus}; 72a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 73a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats) 74a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 75a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 76a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * TCM825X register configuration for all combinations of pixel format and 77a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * image size 78a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 79a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ }; 80a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ }; 81a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ }; 82a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ }; 83a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ }; 84a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ }; 85a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 86a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT }; 87a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT }; 88a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 89a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* Our own specific controls */ 90a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE 91a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1 92a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2 93a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3 94a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4 95a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME 96a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 97a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* Video controls */ 98a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic struct vcontrol { 99a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_queryctrl qc; 100a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u16 reg; 101a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u16 start_bit; 102a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} video_control[] = { 103a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 104a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 105a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_GAIN, 106a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_INTEGER, 107a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Gain", 108a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 109a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 63, 110a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 1, 111a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 112a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_AG, 113a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 0, 114a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 115a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 116a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 117a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_RED_BALANCE, 118a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_INTEGER, 119a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Red Balance", 120a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 121a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 255, 122a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 1, 123a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 124a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_MRG, 125a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 0, 126a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 127a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 128a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 129a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_BLUE_BALANCE, 130a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_INTEGER, 131a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Blue Balance", 132a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 133a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 255, 134a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 1, 135a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 136a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_MBG, 137a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 0, 138a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 139a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 140a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 141a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_AUTO_WHITE_BALANCE, 142a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_BOOLEAN, 143a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Auto White Balance", 144a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 145a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 1, 146a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 0, 147a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 148a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_AWBSW, 149a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 7, 150a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 151a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 152a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 153a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_EXPOSURE, 154a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_INTEGER, 155a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Exposure Time", 156a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 157a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 0x1fff, 158a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 1, 159a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 160a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_ESRSPD_U, 161a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 0, 162a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 163a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 164a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 165a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_HFLIP, 166a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_BOOLEAN, 167a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Mirror Image", 168a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 169a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 1, 170a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 0, 171a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 172a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_H_INV, 173a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 6, 174a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 175a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 176a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 177a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_VFLIP, 178a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_BOOLEAN, 179a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Vertical Flip", 180a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 181a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 1, 182a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 0, 183a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 184a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_V_INV, 185a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 7, 186a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 187a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* Private controls */ 188a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 189a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 190a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_ALC, 191a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_BOOLEAN, 192a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Auto Luminance Control", 193a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 194a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 1, 195a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 0, 196a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 197a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_ALCSW, 198a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 7, 199a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 200a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 201a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 202a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_H_EDGE_EN, 203a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_INTEGER, 204a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Horizontal Edge Enhancement", 205a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 206a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 0xff, 207a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 1, 208a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 209a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_HDTG, 210a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 0, 211a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 212a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 213a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 214a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_V_EDGE_EN, 215a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_INTEGER, 216a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Vertical Edge Enhancement", 217a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 218a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 0xff, 219a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 1, 220a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 221a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_VDTG, 222a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 0, 223a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 224a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 225a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 226a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_LENS, 227a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_INTEGER, 228a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Lens Shading Compensation", 229a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 230a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 0x3f, 231a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 1, 232a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 233a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_LENS, 234a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 0, 235a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 236a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 237a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { 238a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .id = V4L2_CID_MAX_EXPOSURE_TIME, 239a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = V4L2_CTRL_TYPE_INTEGER, 240a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = "Maximum Exposure Time", 241a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .minimum = 0, 242a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .maximum = 0x3, 243a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .step = 1, 244a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 245a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .reg = TCM825X_ESRLIM, 246a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .start_bit = 5, 247a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 248a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus}; 249a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 250a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 251a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] = 252a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga }; 253a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 254a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusconst static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] = 255a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ &yuv422, &rgb565 }; 256a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 257a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 258a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Read a value from a register in an TCM825X sensor device. The value is 259a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * returned in 'val'. 260a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Returns zero if successful, or non-zero otherwise. 261a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 262a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int tcm825x_read_reg(struct i2c_client *client, int reg) 263a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 264a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int err; 265a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct i2c_msg msg[2]; 266a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u8 reg_buf, data_buf = 0; 267a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 268a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (!client->adapter) 269a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -ENODEV; 270a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 271a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg[0].addr = client->addr; 272a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg[0].flags = 0; 273a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg[0].len = 1; 274a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg[0].buf = ®_buf; 275a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg[1].addr = client->addr; 276a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg[1].flags = I2C_M_RD; 277a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg[1].len = 1; 278a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg[1].buf = &data_buf; 279a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 280a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus reg_buf = reg; 281a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 282a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus err = i2c_transfer(client->adapter, msg, 2); 283a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (err < 0) 284a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return err; 285a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return data_buf; 286a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 287a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 288a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 289a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Write a value to a register in an TCM825X sensor device. 290a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Returns zero if successful, or non-zero otherwise. 291a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 292a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val) 293a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 294a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int err; 295a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct i2c_msg msg[1]; 296a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus unsigned char data[2]; 297a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 298a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (!client->adapter) 299a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -ENODEV; 300a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 301a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg->addr = client->addr; 302a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg->flags = 0; 303a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg->len = 2; 304a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus msg->buf = data; 305a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus data[0] = reg; 306a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus data[1] = val; 307a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus err = i2c_transfer(client->adapter, msg, 1); 308a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (err >= 0) 309a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 310a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return err; 311a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 312a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 313a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int __tcm825x_write_reg_mask(struct i2c_client *client, 314a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u8 reg, u8 val, u8 mask) 315a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 316a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int rc; 317a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 318a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* need to do read - modify - write */ 319a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus rc = tcm825x_read_reg(client, reg); 320a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (rc < 0) 321a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return rc; 322a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 323a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus rc &= (~mask); /* Clear the masked bits */ 324a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val &= mask; /* Enforce mask on value */ 325a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val |= rc; 326a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 327a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* write the new value to the register */ 328a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus rc = tcm825x_write_reg(client, reg, val); 329a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (rc) 330a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return rc; 331a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 332a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 333a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 334a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 335a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define tcm825x_write_reg_mask(client, regmask, val) \ 336a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \ 337a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus TCM825X_MASK((regmask))) 338a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 339a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 340a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 341a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Initialize a list of TCM825X registers. 342a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * The list of registers is terminated by the pair of values 343a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * { TCM825X_REG_TERM, TCM825X_VAL_TERM }. 344a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Returns zero if successful, or non-zero otherwise. 345a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 346a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int tcm825x_write_default_regs(struct i2c_client *client, 347a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus const struct tcm825x_reg *reglist) 348a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 349a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int err; 350a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus const struct tcm825x_reg *next = reglist; 351a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 352a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus while (!((next->reg == TCM825X_REG_TERM) 353a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus && (next->val == TCM825X_VAL_TERM))) { 354a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus err = tcm825x_write_reg(client, next->reg, next->val); 355a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (err) { 356a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus dev_err(&client->dev, "register writing failed\n"); 357a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return err; 358a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 359a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus next++; 360a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 361a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 362a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 363a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 364a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 365a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic struct vcontrol *find_vctrl(int id) 366a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 367a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int i; 368a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 369a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (id < V4L2_CID_BASE) 370a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return NULL; 371a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 372a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus for (i = 0; i < ARRAY_SIZE(video_control); i++) 373a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (video_control[i].qc.id == id) 374a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return &video_control[i]; 375a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 376a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return NULL; 377a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 378a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 379a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 380a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Find the best match for a requested image capture size. The best match 381a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * is chosen as the nearest match that has the same number or fewer pixels 382a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * as the requested size, or the smallest image size if the requested size 383a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * has fewer pixels than the smallest image. 384a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 385a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic enum image_size tcm825x_find_size(struct v4l2_int_device *s, 386a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus unsigned int width, 387a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus unsigned int height) 388a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 389a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus enum image_size isize; 390a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus unsigned long pixels = width * height; 391a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 392a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 393a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus for (isize = subQCIF; isize < VGA; isize++) { 394a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (tcm825x_sizes[isize + 1].height 395a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * tcm825x_sizes[isize + 1].width > pixels) { 396a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize); 397a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 398a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return isize; 399a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 400a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 401a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 402a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus dev_dbg(&sensor->i2c_client->dev, "format default VGA\n"); 403a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 404a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return VGA; 405a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 406a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 407a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 408a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Configure the TCM825X for current image size, pixel format, and 409a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * frame period. fper is the frame period (in seconds) expressed as a 410a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * fraction. Returns zero if successful, or non-zero otherwise. The 411a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * actual frame period is returned in fper. 412a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 413a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int tcm825x_configure(struct v4l2_int_device *s) 414a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 415a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 416a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_pix_format *pix = &sensor->pix; 417a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus enum image_size isize = tcm825x_find_size(s, pix->width, pix->height); 418a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_fract *fper = &sensor->timeperframe; 419a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus enum pixel_format pfmt; 420a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int err; 421a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u32 tgt_fps; 422a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u8 val; 423a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 424a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* common register initialization */ 425a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus err = tcm825x_write_default_regs( 426a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->i2c_client, sensor->platform_data->default_regs()); 427a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (err) 428a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return err; 429a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 430a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* configure image size */ 431a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val = tcm825x_siz_reg[isize]->val; 432a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus dev_dbg(&sensor->i2c_client->dev, 433a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus "configuring image size %d\n", isize); 434a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus err = tcm825x_write_reg_mask(sensor->i2c_client, 435a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tcm825x_siz_reg[isize]->reg, val); 436a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (err) 437a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return err; 438a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 439a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* configure pixel format */ 440a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus switch (pix->pixelformat) { 441a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus default: 442a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus case V4L2_PIX_FMT_RGB565: 443a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pfmt = RGB565; 444a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus break; 445a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus case V4L2_PIX_FMT_UYVY: 446a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pfmt = YUV422; 447a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus break; 448a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 449a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 450a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus dev_dbg(&sensor->i2c_client->dev, 451a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus "configuring pixel format %d\n", pfmt); 452a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val = tcm825x_fmt_reg[pfmt]->val; 453a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 454a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus err = tcm825x_write_reg_mask(sensor->i2c_client, 455a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tcm825x_fmt_reg[pfmt]->reg, val); 456a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (err) 457a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return err; 458a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 459a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* 460a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be 461a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * set. Frame rate will be halved from the normal. 462a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 463a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tgt_fps = fper->denominator / fper->numerator; 464a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) { 465a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val = tcm825x_read_reg(sensor->i2c_client, 0x02); 466a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val |= 0x80; 467a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tcm825x_write_reg(sensor->i2c_client, 0x02, val); 468a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 469a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 470a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 471a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 472a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 473a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 474a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Given the image capture format in pix, the nominal frame period in 475a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * timeperframe, calculate the required xclk frequency. 476a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * 477a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * TCM825X input frequency characteristics are: 478a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz 479a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 480a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define XCLK_MIN 11900000 481a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define XCLK_MAX 25000000 482a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 483a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_g_ext_clk(struct v4l2_int_device *s, u32 *xclk) 484a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 485a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 486a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_fract *timeperframe = &sensor->timeperframe; 487a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u32 tgt_xclk; /* target xclk */ 488a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u32 tgt_fps; /* target frames per secound */ 489a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 490a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tgt_fps = timeperframe->denominator / timeperframe->numerator; 491a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 492a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ? 493a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (2457 * tgt_fps) / MAX_HALF_FPS : 494a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (2457 * tgt_fps) / MAX_FPS; 495a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tgt_xclk *= 10000; 496a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 497a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tgt_xclk = min(tgt_xclk, (u32)XCLK_MAX); 498a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tgt_xclk = max(tgt_xclk, (u32)XCLK_MIN); 499a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 500a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus *xclk = tgt_xclk; 501a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 502a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 503a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 504a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 505a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_s_ext_clk(struct v4l2_int_device *s, u32 xclk) 506a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 507a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (xclk > XCLK_MAX || xclk < XCLK_MIN) 508a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EINVAL; 509a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 510a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 511a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 512a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 513a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_queryctrl(struct v4l2_int_device *s, 514a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_queryctrl *qc) 515a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 516a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct vcontrol *control; 517a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 518a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus control = find_vctrl(qc->id); 519a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 520a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (control == NULL) 521a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EINVAL; 522a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 523a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus *qc = control->qc; 524a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 525a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 526a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 527a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 528a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_g_ctrl(struct v4l2_int_device *s, 529a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_control *vc) 530a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 531a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 532a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct i2c_client *client = sensor->i2c_client; 533a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int val, r; 534a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct vcontrol *lvc; 535a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 536a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* exposure time is special, spread accross 2 registers */ 537a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (vc->id == V4L2_CID_EXPOSURE) { 538a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int val_lower, val_upper; 539a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 540a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val_upper = tcm825x_read_reg(client, 541a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus TCM825X_ADDR(TCM825X_ESRSPD_U)); 542a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (val_upper < 0) 543a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return val_upper; 544a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val_lower = tcm825x_read_reg(client, 545a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus TCM825X_ADDR(TCM825X_ESRSPD_L)); 546a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (val_lower < 0) 547a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return val_lower; 548a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 549a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus vc->value = ((val_upper & 0x1f) << 8) | (val_lower); 550a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 551a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 552a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 553a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus lvc = find_vctrl(vc->id); 554a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (lvc == NULL) 555a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EINVAL; 556a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 557a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg)); 558a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (r < 0) 559a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return r; 560a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val = r & TCM825X_MASK(lvc->reg); 561a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val >>= lvc->start_bit; 562a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 563a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (val < 0) 564a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return val; 565a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 566a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus vc->value = val; 567a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 568a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 569a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 570a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_s_ctrl(struct v4l2_int_device *s, 571a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_control *vc) 572a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 573a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 574a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct i2c_client *client = sensor->i2c_client; 575a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct vcontrol *lvc; 576a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int val = vc->value; 577a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 578a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* exposure time is special, spread accross 2 registers */ 579a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (vc->id == V4L2_CID_EXPOSURE) { 580a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int val_lower, val_upper; 581a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L); 582a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U); 583a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 584a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (tcm825x_write_reg_mask(client, 585a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus TCM825X_ESRSPD_U, val_upper)) 586a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EIO; 587a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 588a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (tcm825x_write_reg_mask(client, 589a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus TCM825X_ESRSPD_L, val_lower)) 590a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EIO; 591a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 592a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 593a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 594a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 595a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus lvc = find_vctrl(vc->id); 596a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (lvc == NULL) 597a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EINVAL; 598a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 599a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus val = val << lvc->start_bit; 600a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (tcm825x_write_reg_mask(client, lvc->reg, val)) 601a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EIO; 602a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 603a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 604a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 605a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 606a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_enum_fmt_cap(struct v4l2_int_device *s, 607a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_fmtdesc *fmt) 608a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 609a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int index = fmt->index; 610a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 611a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus switch (fmt->type) { 612a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus case V4L2_BUF_TYPE_VIDEO_CAPTURE: 613a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (index >= TCM825X_NUM_CAPTURE_FORMATS) 614a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EINVAL; 615a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus break; 616a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 617a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus default: 618a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EINVAL; 619a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 620a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 621a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus fmt->flags = tcm825x_formats[index].flags; 622a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus strlcpy(fmt->description, tcm825x_formats[index].description, 623a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sizeof(fmt->description)); 624a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus fmt->pixelformat = tcm825x_formats[index].pixelformat; 625a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 626a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 627a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 628a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 629a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_try_fmt_cap(struct v4l2_int_device *s, 630a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_format *f) 631a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 632a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 633a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus enum image_size isize; 634a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int ifmt; 635a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_pix_format *pix = &f->fmt.pix; 636a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 637a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus isize = tcm825x_find_size(s, pix->width, pix->height); 638a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %d\n", 639a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus isize, TCM825X_NUM_CAPTURE_FORMATS); 640a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 641a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->width = tcm825x_sizes[isize].width; 642a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->height = tcm825x_sizes[isize].height; 643a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 644a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++) 645a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat) 646a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus break; 647a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 648a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (ifmt == TCM825X_NUM_CAPTURE_FORMATS) 649a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus ifmt = 0; /* Default = YUV 4:2:2 */ 650a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 651a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->pixelformat = tcm825x_formats[ifmt].pixelformat; 652a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->field = V4L2_FIELD_NONE; 653a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL; 654a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->sizeimage = pix->bytesperline * pix->height; 655a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->priv = 0; 656a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n", 657a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->pixelformat); 658a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 659a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus switch (pix->pixelformat) { 660a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus case V4L2_PIX_FMT_UYVY: 661a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus default: 662a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->colorspace = V4L2_COLORSPACE_JPEG; 663a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus break; 664a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus case V4L2_PIX_FMT_RGB565: 665a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus pix->colorspace = V4L2_COLORSPACE_SRGB; 666a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus break; 667a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 668a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 669a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 670a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 671a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 672a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_s_fmt_cap(struct v4l2_int_device *s, 673a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_format *f) 674a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 675a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 676a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_pix_format *pix = &f->fmt.pix; 677a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int rval; 678a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 679a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus rval = ioctl_try_fmt_cap(s, f); 680a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (rval) 681a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return rval; 682a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 683a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus rval = tcm825x_configure(s); 684a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 685a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->pix = *pix; 686a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 687a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return rval; 688a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 689a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 690a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_g_fmt_cap(struct v4l2_int_device *s, 691a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_format *f) 692a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 693a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 694a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 695a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus f->fmt.pix = sensor->pix; 696a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 697a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 698a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 699a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 700a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_g_parm(struct v4l2_int_device *s, 701a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_streamparm *a) 702a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 703a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 704a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_captureparm *cparm = &a->parm.capture; 705a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 706a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 707a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EINVAL; 708a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 709a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus memset(a, 0, sizeof(*a)); 710a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 711a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 712a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus cparm->capability = V4L2_CAP_TIMEPERFRAME; 713a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus cparm->timeperframe = sensor->timeperframe; 714a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 715a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 716a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 717a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 718a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_s_parm(struct v4l2_int_device *s, 719a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_streamparm *a) 720a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 721a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 722a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; 723a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus u32 tgt_fps; /* target frames per secound */ 724a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int rval; 725a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 726a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 727a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EINVAL; 728a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 729a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if ((timeperframe->numerator == 0) 730a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus || (timeperframe->denominator == 0)) { 731a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus timeperframe->denominator = DEFAULT_FPS; 732a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus timeperframe->numerator = 1; 733a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 734a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 735a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tgt_fps = timeperframe->denominator / timeperframe->numerator; 736a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 737a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (tgt_fps > MAX_FPS) { 738a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus timeperframe->denominator = MAX_FPS; 739a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus timeperframe->numerator = 1; 740a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } else if (tgt_fps < MIN_FPS) { 741a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus timeperframe->denominator = MIN_FPS; 742a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus timeperframe->numerator = 1; 743a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 744a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 745a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->timeperframe = *timeperframe; 746a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 747a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus rval = tcm825x_configure(s); 748a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 749a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return rval; 750a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 751a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 752a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_s_power(struct v4l2_int_device *s, int on) 753a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 754a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 755a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 756a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return sensor->platform_data->power_set(on); 757a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 758a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 759a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf) 760a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 761a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 762a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 763a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return sensor->platform_data->needs_reset(s, buf, &sensor->pix); 764a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 765a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 766a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_reset(struct v4l2_int_device *s) 767a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 768a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EBUSY; 769a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 770a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 771a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_init(struct v4l2_int_device *s) 772a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 773a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return tcm825x_configure(s); 774a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 775a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 776a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_dev_exit(struct v4l2_int_device *s) 777a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 778a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 779a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 780a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 781a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int ioctl_dev_init(struct v4l2_int_device *s) 782a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 783a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = s->priv; 784a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int r; 785a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 786a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus r = tcm825x_read_reg(sensor->i2c_client, 0x01); 787a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (r < 0) 788a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return r; 789a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (r == 0) { 790a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus dev_err(&sensor->i2c_client->dev, "device not detected\n"); 791a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EIO; 792a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus } 793a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 794a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 795a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 796a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus#define NUM_IOCTLS 17 797a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 798a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[NUM_IOCTLS] = { 799a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_dev_init_num, 800a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_dev_init }, 801a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_dev_exit_num, 802a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_dev_exit }, 803a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_s_power_num, 804a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_s_power }, 805a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_g_ext_clk_num, 806a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_g_ext_clk }, 807a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_s_ext_clk_num, 808a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_s_ext_clk }, 809a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_g_needs_reset_num, 810a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_g_needs_reset }, 811a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_reset_num, 812a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_reset }, 813a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_init_num, 814a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_init }, 815a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_enum_fmt_cap_num, 816a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_enum_fmt_cap }, 817a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_try_fmt_cap_num, 818a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_try_fmt_cap }, 819a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_g_fmt_cap_num, 820a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_g_fmt_cap }, 821a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_s_fmt_cap_num, 822a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_s_fmt_cap }, 823a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_g_parm_num, 824a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_g_parm }, 825a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_s_parm_num, 826a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_s_parm }, 827a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_queryctrl_num, 828a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_queryctrl }, 829a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_g_ctrl_num, 830a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_g_ctrl }, 831a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus { vidioc_int_s_ctrl_num, 832a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus (v4l2_int_ioctl_func *)&ioctl_s_ctrl }, 833a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus}; 834a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 835a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic struct v4l2_int_slave tcm825x_slave = { 836a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .ioctls = tcm825x_ioctl_desc, 837a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc), 838a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus}; 839a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 840a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic struct tcm825x_sensor tcm825x; 841a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 842a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic struct v4l2_int_device tcm825x_int_device = { 843a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .module = THIS_MODULE, 844a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = TCM825X_NAME, 845a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .priv = &tcm825x, 846a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .type = v4l2_int_type_slave, 847a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .u = { 848a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .slave = &tcm825x_slave, 849a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 850a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus}; 851a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 852a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int tcm825x_probe(struct i2c_client *client) 853a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 854a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = &tcm825x; 855a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int rval; 856a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 857a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (i2c_get_clientdata(client)) 858a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -EBUSY; 859a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 860a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->platform_data = client->dev.platform_data; 861a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 862a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (sensor->platform_data == NULL 863a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus && !sensor->platform_data->is_okay()) 864a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -ENODEV; 865a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 866a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->v4l2_int_device = &tcm825x_int_device; 867a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 868a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->i2c_client = client; 869a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus i2c_set_clientdata(client, sensor); 870a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 871a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* Make the default capture format QVGA RGB565 */ 872a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->pix.width = tcm825x_sizes[QVGA].width; 873a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->pix.height = tcm825x_sizes[QVGA].height; 874a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565; 875a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 876a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus rval = v4l2_int_device_register(sensor->v4l2_int_device); 877a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (rval) 878a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus i2c_set_clientdata(client, NULL); 879a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 880a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return rval; 881a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 882a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 883a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int __exit tcm825x_remove(struct i2c_client *client) 884a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 885a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus struct tcm825x_sensor *sensor = i2c_get_clientdata(client); 886a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 887a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (!client->adapter) 888a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return -ENODEV; /* our client isn't attached */ 889a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 890a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus v4l2_int_device_unregister(sensor->v4l2_int_device); 891a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus i2c_set_clientdata(client, NULL); 892a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 893a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return 0; 894a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 895a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 896a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic struct i2c_driver tcm825x_i2c_driver = { 897a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .driver = { 898a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .name = TCM825X_NAME, 899a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 900a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .probe = &tcm825x_probe, 901a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .remove = __exit_p(&tcm825x_remove), 902a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus}; 903a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 904a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic struct tcm825x_sensor tcm825x = { 905a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .timeperframe = { 906a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .numerator = 1, 907a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus .denominator = DEFAULT_FPS, 908a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus }, 909a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus}; 910a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 911a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic int __init tcm825x_init(void) 912a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 913a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int rval; 914a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus int i = 0; 915a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 916a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus /* Just an experiment --- don't use *_cb functions yet. */ 917a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus tcm825x_ioctl_desc[i++] = vidioc_int_dev_init_cb(&ioctl_dev_init); 918a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus BUG_ON(i >= NUM_IOCTLS); 919a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 920a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus rval = i2c_add_driver(&tcm825x_i2c_driver); 921a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus if (rval) 922a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n", 923a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus __FUNCTION__); 924a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 925a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus return rval; 926a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 927a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 928a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusstatic void __exit tcm825x_exit(void) 929a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus{ 930a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus i2c_del_driver(&tcm825x_i2c_driver); 931a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus} 932a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 933a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus/* 934a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * FIXME: Menelaus isn't ready (?) at module_init stage, so use 935a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus * late_initcall for now. 936a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus */ 937a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailuslate_initcall(tcm825x_init); 938a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailusmodule_exit(tcm825x_exit); 939a5e90862114124d79e1a3f34641b00fec51d1806Sakari Ailus 940a5e90862114124d79e1a3f34641b00fec51d1806Sakari AilusMODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>"); 941a5e90862114124d79e1a3f34641b00fec51d1806Sakari AilusMODULE_DESCRIPTION("TCM825x camera sensor driver"); 942a5e90862114124d79e1a3f34641b00fec51d1806Sakari AilusMODULE_LICENSE("GPL"); 943