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