/*
* Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SIZEOF_I2C_TRANSBUF 128
struct mt9m114_reg {
u16 cmd; /* command */
u16 addr;
u16 val;
};
static struct mt9m114_reg mode_1280x960_30fps[] = {
{MT9M114_SENSOR_WORD_WRITE, 0x001A, 0x0001},
{MT9M114_SENSOR_WAIT_MS, 0, 10},
{MT9M114_SENSOR_WORD_WRITE, 0x001A, 0x0000},
{MT9M114_SENSOR_WAIT_MS, 0, 50},
{MT9M114_SENSOR_WORD_WRITE, 0x301A, 0x0234},
{MT9M114_SENSOR_WORD_WRITE, 0x098E, 0x1000},
{MT9M114_SENSOR_BYTE_WRITE, 0xC97E, 0x01},
{MT9M114_SENSOR_WORD_WRITE, 0xC980, 0x0120},
{MT9M114_SENSOR_WORD_WRITE, 0xC982, 0x0700},
{MT9M114_SENSOR_WORD_WRITE, 0xC800, 0x0004},
{MT9M114_SENSOR_WORD_WRITE, 0xC802, 0x0004},
{MT9M114_SENSOR_WORD_WRITE, 0xC804, 0x03CB},
{MT9M114_SENSOR_WORD_WRITE, 0xC806, 0x050B},
{MT9M114_SENSOR_WORD_WRITE, 0xC808, 0x02DC},
{MT9M114_SENSOR_WORD_WRITE, 0xC80A, 0x6C00},
{MT9M114_SENSOR_WORD_WRITE, 0xC80C, 0x0001},
{MT9M114_SENSOR_WORD_WRITE, 0xC80E, 0x00DB},
{MT9M114_SENSOR_WORD_WRITE, 0xC810, 0x05B3},
{MT9M114_SENSOR_WORD_WRITE, 0xC812, 0x03EE},
{MT9M114_SENSOR_WORD_WRITE, 0xC814, 0x0636},
{MT9M114_SENSOR_WORD_WRITE, 0xC816, 0x0060},
{MT9M114_SENSOR_WORD_WRITE, 0xC818, 0x03C3},
{MT9M114_SENSOR_WORD_WRITE, 0xC834, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC854, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC856, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC858, 0x0500},
{MT9M114_SENSOR_WORD_WRITE, 0xC85A, 0x03C0},
{MT9M114_SENSOR_BYTE_WRITE, 0xC85C, 0x03},
{MT9M114_SENSOR_WORD_WRITE, 0xC868, 0x0500},
{MT9M114_SENSOR_WORD_WRITE, 0xC86A, 0x03C0},
{MT9M114_SENSOR_WORD_WRITE, 0xC88C, 0x1E02},
{MT9M114_SENSOR_WORD_WRITE, 0xC88E, 0x0780},
{MT9M114_SENSOR_WORD_WRITE, 0xC914, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC916, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC918, 0x04FF},
{MT9M114_SENSOR_WORD_WRITE, 0xC91A, 0x03BF},
{MT9M114_SENSOR_WORD_WRITE, 0xC91C, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC91E, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC920, 0x00FF},
{MT9M114_SENSOR_WORD_WRITE, 0xC922, 0x00BF},
{MT9M114_SENSOR_BYTE_WRITE, 0xE801, 0x00},
{MT9M114_SENSOR_WORD_WRITE, 0x316A, 0x8270},
{MT9M114_SENSOR_WORD_WRITE, 0x316C, 0x8270},
{MT9M114_SENSOR_WORD_WRITE, 0x3ED0, 0x2305},
{MT9M114_SENSOR_WORD_WRITE, 0x3ED2, 0x77CF},
{MT9M114_SENSOR_WORD_WRITE, 0x316E, 0x8202},
{MT9M114_SENSOR_WORD_WRITE, 0x3180, 0x87FF},
{MT9M114_SENSOR_WORD_WRITE, 0x30D4, 0x6080},
{MT9M114_SENSOR_WORD_WRITE, 0xA802, 0x0008},
{MT9M114_SENSOR_WORD_WRITE, 0x3E14, 0xFF39},
{MT9M114_SENSOR_WORD_WRITE, 0x301A, 0x8234},
{MT9M114_SENSOR_WORD_WRITE, 0x098E, 0x495E},
{MT9M114_SENSOR_WORD_WRITE, 0xC95E, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0x3640, 0x02B0},
{MT9M114_SENSOR_WORD_WRITE, 0x3642, 0x8063},
{MT9M114_SENSOR_WORD_WRITE, 0x3644, 0x78D0},
{MT9M114_SENSOR_WORD_WRITE, 0x3646, 0x50CC},
{MT9M114_SENSOR_WORD_WRITE, 0x3648, 0x3511},
{MT9M114_SENSOR_WORD_WRITE, 0x364A, 0x0110},
{MT9M114_SENSOR_WORD_WRITE, 0x364C, 0xBD8A},
{MT9M114_SENSOR_WORD_WRITE, 0x364E, 0x0CD1},
{MT9M114_SENSOR_WORD_WRITE, 0x3650, 0x24ED},
{MT9M114_SENSOR_WORD_WRITE, 0x3652, 0x7C11},
{MT9M114_SENSOR_WORD_WRITE, 0x3654, 0x0150},
{MT9M114_SENSOR_WORD_WRITE, 0x3656, 0x124C},
{MT9M114_SENSOR_WORD_WRITE, 0x3658, 0x3130},
{MT9M114_SENSOR_WORD_WRITE, 0x365A, 0x508C},
{MT9M114_SENSOR_WORD_WRITE, 0x365C, 0x21F1},
{MT9M114_SENSOR_WORD_WRITE, 0x365E, 0x0090},
{MT9M114_SENSOR_WORD_WRITE, 0x3660, 0xBFCA},
{MT9M114_SENSOR_WORD_WRITE, 0x3662, 0x0A11},
{MT9M114_SENSOR_WORD_WRITE, 0x3664, 0x4F4B},
{MT9M114_SENSOR_WORD_WRITE, 0x3666, 0x28B1},
{MT9M114_SENSOR_WORD_WRITE, 0x3680, 0x50A9},
{MT9M114_SENSOR_WORD_WRITE, 0x3682, 0xA04B},
{MT9M114_SENSOR_WORD_WRITE, 0x3684, 0x0E2D},
{MT9M114_SENSOR_WORD_WRITE, 0x3686, 0x73EC},
{MT9M114_SENSOR_WORD_WRITE, 0x3688, 0x164F},
{MT9M114_SENSOR_WORD_WRITE, 0x368A, 0xF829},
{MT9M114_SENSOR_WORD_WRITE, 0x368C, 0xC1A8},
{MT9M114_SENSOR_WORD_WRITE, 0x368E, 0xB0EC},
{MT9M114_SENSOR_WORD_WRITE, 0x3690, 0xE76A},
{MT9M114_SENSOR_WORD_WRITE, 0x3692, 0x69AF},
{MT9M114_SENSOR_WORD_WRITE, 0x3694, 0x378C},
{MT9M114_SENSOR_WORD_WRITE, 0x3696, 0xA70D},
{MT9M114_SENSOR_WORD_WRITE, 0x3698, 0x884F},
{MT9M114_SENSOR_WORD_WRITE, 0x369A, 0xEE8B},
{MT9M114_SENSOR_WORD_WRITE, 0x369C, 0x5DEF},
{MT9M114_SENSOR_WORD_WRITE, 0x369E, 0x27CC},
{MT9M114_SENSOR_WORD_WRITE, 0x36A0, 0xCAAC},
{MT9M114_SENSOR_WORD_WRITE, 0x36A2, 0x840E},
{MT9M114_SENSOR_WORD_WRITE, 0x36A4, 0xDAA9},
{MT9M114_SENSOR_WORD_WRITE, 0x36A6, 0xF00C},
{MT9M114_SENSOR_WORD_WRITE, 0x36C0, 0x1371},
{MT9M114_SENSOR_WORD_WRITE, 0x36C2, 0x272F},
{MT9M114_SENSOR_WORD_WRITE, 0x36C4, 0x2293},
{MT9M114_SENSOR_WORD_WRITE, 0x36C6, 0xE6D0},
{MT9M114_SENSOR_WORD_WRITE, 0x36C8, 0xEC32},
{MT9M114_SENSOR_WORD_WRITE, 0x36CA, 0x11B1},
{MT9M114_SENSOR_WORD_WRITE, 0x36CC, 0x7BAF},
{MT9M114_SENSOR_WORD_WRITE, 0x36CE, 0x5813},
{MT9M114_SENSOR_WORD_WRITE, 0x36D0, 0xB871},
{MT9M114_SENSOR_WORD_WRITE, 0x36D2, 0x8913},
{MT9M114_SENSOR_WORD_WRITE, 0x36D4, 0x4610},
{MT9M114_SENSOR_WORD_WRITE, 0x36D6, 0x7EEE},
{MT9M114_SENSOR_WORD_WRITE, 0x36D8, 0x0DF3},
{MT9M114_SENSOR_WORD_WRITE, 0x36DA, 0xB84F},
{MT9M114_SENSOR_WORD_WRITE, 0x36DC, 0xB532},
{MT9M114_SENSOR_WORD_WRITE, 0x36DE, 0x1171},
{MT9M114_SENSOR_WORD_WRITE, 0x36E0, 0x13CF},
{MT9M114_SENSOR_WORD_WRITE, 0x36E2, 0x22F3},
{MT9M114_SENSOR_WORD_WRITE, 0x36E4, 0xE090},
{MT9M114_SENSOR_WORD_WRITE, 0x36E6, 0x8133},
{MT9M114_SENSOR_WORD_WRITE, 0x3700, 0x88AE},
{MT9M114_SENSOR_WORD_WRITE, 0x3702, 0x00EA},
{MT9M114_SENSOR_WORD_WRITE, 0x3704, 0x344F},
{MT9M114_SENSOR_WORD_WRITE, 0x3706, 0xEC88},
{MT9M114_SENSOR_WORD_WRITE, 0x3708, 0x3E91},
{MT9M114_SENSOR_WORD_WRITE, 0x370A, 0xF12D},
{MT9M114_SENSOR_WORD_WRITE, 0x370C, 0xB0EF},
{MT9M114_SENSOR_WORD_WRITE, 0x370E, 0x77CD},
{MT9M114_SENSOR_WORD_WRITE, 0x3710, 0x7930},
{MT9M114_SENSOR_WORD_WRITE, 0x3712, 0x5C12},
{MT9M114_SENSOR_WORD_WRITE, 0x3714, 0x500C},
{MT9M114_SENSOR_WORD_WRITE, 0x3716, 0x22CE},
{MT9M114_SENSOR_WORD_WRITE, 0x3718, 0x2370},
{MT9M114_SENSOR_WORD_WRITE, 0x371A, 0x258F},
{MT9M114_SENSOR_WORD_WRITE, 0x371C, 0x3D30},
{MT9M114_SENSOR_WORD_WRITE, 0x371E, 0x370C},
{MT9M114_SENSOR_WORD_WRITE, 0x3720, 0x03ED},
{MT9M114_SENSOR_WORD_WRITE, 0x3722, 0x9AD0},
{MT9M114_SENSOR_WORD_WRITE, 0x3724, 0x7ECF},
{MT9M114_SENSOR_WORD_WRITE, 0x3726, 0x1093},
{MT9M114_SENSOR_WORD_WRITE, 0x3740, 0x2391},
{MT9M114_SENSOR_WORD_WRITE, 0x3742, 0xAAD0},
{MT9M114_SENSOR_WORD_WRITE, 0x3744, 0x28F2},
{MT9M114_SENSOR_WORD_WRITE, 0x3746, 0xBA4F},
{MT9M114_SENSOR_WORD_WRITE, 0x3748, 0xC536},
{MT9M114_SENSOR_WORD_WRITE, 0x374A, 0x1472},
{MT9M114_SENSOR_WORD_WRITE, 0x374C, 0xD110},
{MT9M114_SENSOR_WORD_WRITE, 0x374E, 0x2933},
{MT9M114_SENSOR_WORD_WRITE, 0x3750, 0xD0D1},
{MT9M114_SENSOR_WORD_WRITE, 0x3752, 0x9F37},
{MT9M114_SENSOR_WORD_WRITE, 0x3754, 0x34D1},
{MT9M114_SENSOR_WORD_WRITE, 0x3756, 0x1C6C},
{MT9M114_SENSOR_WORD_WRITE, 0x3758, 0x3FD2},
{MT9M114_SENSOR_WORD_WRITE, 0x375A, 0xCB72},
{MT9M114_SENSOR_WORD_WRITE, 0x375C, 0xBA96},
{MT9M114_SENSOR_WORD_WRITE, 0x375E, 0x1551},
{MT9M114_SENSOR_WORD_WRITE, 0x3760, 0xB74F},
{MT9M114_SENSOR_WORD_WRITE, 0x3762, 0x1672},
{MT9M114_SENSOR_WORD_WRITE, 0x3764, 0x84F1},
{MT9M114_SENSOR_WORD_WRITE, 0x3766, 0xC2D6},
{MT9M114_SENSOR_WORD_WRITE, 0x3782, 0x01E0},
{MT9M114_SENSOR_WORD_WRITE, 0x3784, 0x0280},
{MT9M114_SENSOR_WORD_WRITE, 0x37C0, 0xA6EA},
{MT9M114_SENSOR_WORD_WRITE, 0x37C2, 0x874B},
{MT9M114_SENSOR_WORD_WRITE, 0x37C4, 0x85CB},
{MT9M114_SENSOR_WORD_WRITE, 0x37C6, 0x968A},
{MT9M114_SENSOR_WORD_WRITE, 0x098E, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC960, 0x0AF0},
{MT9M114_SENSOR_WORD_WRITE, 0xC962, 0x79E2},
{MT9M114_SENSOR_WORD_WRITE, 0xC964, 0x5EC8},
{MT9M114_SENSOR_WORD_WRITE, 0xC966, 0x791F},
{MT9M114_SENSOR_WORD_WRITE, 0xC968, 0x76EE},
{MT9M114_SENSOR_WORD_WRITE, 0xC96A, 0x0FA0},
{MT9M114_SENSOR_WORD_WRITE, 0xC96C, 0x7DFA},
{MT9M114_SENSOR_WORD_WRITE, 0xC96E, 0x7DAF},
{MT9M114_SENSOR_WORD_WRITE, 0xC970, 0x7E02},
{MT9M114_SENSOR_WORD_WRITE, 0xC972, 0x7E0A},
{MT9M114_SENSOR_WORD_WRITE, 0xC974, 0x1964},
{MT9M114_SENSOR_WORD_WRITE, 0xC976, 0x7CDC},
{MT9M114_SENSOR_WORD_WRITE, 0xC978, 0x7838},
{MT9M114_SENSOR_WORD_WRITE, 0xC97A, 0x7C2F},
{MT9M114_SENSOR_WORD_WRITE, 0xC97C, 0x7792},
{MT9M114_SENSOR_WORD_WRITE, 0xC95E, 0x0003},
{MT9M114_SENSOR_WORD_WRITE, 0x098E, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC95E, 0x0003},
{MT9M114_SENSOR_WORD_WRITE, 0xC892, 0x0267},
{MT9M114_SENSOR_WORD_WRITE, 0xC894, 0xFF1A},
{MT9M114_SENSOR_WORD_WRITE, 0xC896, 0xFFB3},
{MT9M114_SENSOR_WORD_WRITE, 0xC898, 0xFF80},
{MT9M114_SENSOR_WORD_WRITE, 0xC89A, 0x0166},
{MT9M114_SENSOR_WORD_WRITE, 0xC89C, 0x0003},
{MT9M114_SENSOR_WORD_WRITE, 0xC89E, 0xFF9A},
{MT9M114_SENSOR_WORD_WRITE, 0xC8A0, 0xFEB4},
{MT9M114_SENSOR_WORD_WRITE, 0xC8A2, 0x024D},
{MT9M114_SENSOR_WORD_WRITE, 0xC8A4, 0x01BF},
{MT9M114_SENSOR_WORD_WRITE, 0xC8A6, 0xFF01},
{MT9M114_SENSOR_WORD_WRITE, 0xC8A8, 0xFFF3},
{MT9M114_SENSOR_WORD_WRITE, 0xC8AA, 0xFF75},
{MT9M114_SENSOR_WORD_WRITE, 0xC8AC, 0x0198},
{MT9M114_SENSOR_WORD_WRITE, 0xC8AE, 0xFFFD},
{MT9M114_SENSOR_WORD_WRITE, 0xC8B0, 0xFF9A},
{MT9M114_SENSOR_WORD_WRITE, 0xC8B2, 0xFEE7},
{MT9M114_SENSOR_WORD_WRITE, 0xC8B4, 0x02A8},
{MT9M114_SENSOR_WORD_WRITE, 0xC8B6, 0x01D9},
{MT9M114_SENSOR_WORD_WRITE, 0xC8B8, 0xFF26},
{MT9M114_SENSOR_WORD_WRITE, 0xC8BA, 0xFFF3},
{MT9M114_SENSOR_WORD_WRITE, 0xC8BC, 0xFFB3},
{MT9M114_SENSOR_WORD_WRITE, 0xC8BE, 0x0132},
{MT9M114_SENSOR_WORD_WRITE, 0xC8C0, 0xFFE8},
{MT9M114_SENSOR_WORD_WRITE, 0xC8C2, 0xFFDA},
{MT9M114_SENSOR_WORD_WRITE, 0xC8C4, 0xFECD},
{MT9M114_SENSOR_WORD_WRITE, 0xC8C6, 0x02C2},
{MT9M114_SENSOR_WORD_WRITE, 0xC8C8, 0x0075},
{MT9M114_SENSOR_WORD_WRITE, 0xC8CA, 0x011C},
{MT9M114_SENSOR_WORD_WRITE, 0xC8CC, 0x009A},
{MT9M114_SENSOR_WORD_WRITE, 0xC8CE, 0x0105},
{MT9M114_SENSOR_WORD_WRITE, 0xC8D0, 0x00A4},
{MT9M114_SENSOR_WORD_WRITE, 0xC8D2, 0x00AC},
{MT9M114_SENSOR_WORD_WRITE, 0xC8D4, 0x0A8C},
{MT9M114_SENSOR_WORD_WRITE, 0xC8D6, 0x0F0A},
{MT9M114_SENSOR_WORD_WRITE, 0xC8D8, 0x1964},
{MT9M114_SENSOR_WORD_WRITE, 0xC914, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC916, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC918, 0x04FF},
{MT9M114_SENSOR_WORD_WRITE, 0xC91A, 0x03BF},
{MT9M114_SENSOR_WORD_WRITE, 0xC904, 0x003B},
{MT9M114_SENSOR_WORD_WRITE, 0xC906, 0x0041},
{MT9M114_SENSOR_BYTE_WRITE, 0xC8F2, 0x03},
{MT9M114_SENSOR_BYTE_WRITE, 0xC8F3, 0x02},
{MT9M114_SENSOR_WORD_WRITE, 0xC906, 0x003C},
{MT9M114_SENSOR_WORD_WRITE, 0xC8F4, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC8F6, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC8F8, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC8FA, 0xE724},
{MT9M114_SENSOR_WORD_WRITE, 0xC8FC, 0x1583},
{MT9M114_SENSOR_WORD_WRITE, 0xC8FE, 0x2045},
{MT9M114_SENSOR_WORD_WRITE, 0xC900, 0x05DC},
{MT9M114_SENSOR_WORD_WRITE, 0xC902, 0x007C},
{MT9M114_SENSOR_BYTE_WRITE, 0xC90C, 0x80},
{MT9M114_SENSOR_BYTE_WRITE, 0xC90D, 0x80},
{MT9M114_SENSOR_BYTE_WRITE, 0xC90E, 0x80},
{MT9M114_SENSOR_BYTE_WRITE, 0xC90F, 0x88},
{MT9M114_SENSOR_BYTE_WRITE, 0xC910, 0x80},
{MT9M114_SENSOR_BYTE_WRITE, 0xC911, 0x80},
{MT9M114_SENSOR_WORD_WRITE, 0xC926, 0x0060},
{MT9M114_SENSOR_WORD_WRITE, 0xC928, 0x009A},
{MT9M114_SENSOR_WORD_WRITE, 0xC946, 0x0070},
{MT9M114_SENSOR_WORD_WRITE, 0xC948, 0x00F3},
{MT9M114_SENSOR_WORD_WRITE, 0xC952, 0x0060},
{MT9M114_SENSOR_WORD_WRITE, 0xC954, 0x009A},
{MT9M114_SENSOR_BYTE_WRITE, 0xC92A, 0x80},
{MT9M114_SENSOR_BYTE_WRITE, 0xC92B, 0x4B},
{MT9M114_SENSOR_BYTE_WRITE, 0xC92C, 0x00},
{MT9M114_SENSOR_BYTE_WRITE, 0xC92D, 0xFF},
{MT9M114_SENSOR_BYTE_WRITE, 0xC92E, 0x3C},
{MT9M114_SENSOR_BYTE_WRITE, 0xC92F, 0x02},
{MT9M114_SENSOR_BYTE_WRITE, 0xC930, 0x06},
{MT9M114_SENSOR_BYTE_WRITE, 0xC931, 0x64},
{MT9M114_SENSOR_BYTE_WRITE, 0xC932, 0x01},
{MT9M114_SENSOR_BYTE_WRITE, 0xC933, 0x0C},
{MT9M114_SENSOR_BYTE_WRITE, 0xC934, 0x3C},
{MT9M114_SENSOR_BYTE_WRITE, 0xC935, 0x3C},
{MT9M114_SENSOR_BYTE_WRITE, 0xC936, 0x3C},
{MT9M114_SENSOR_BYTE_WRITE, 0xC937, 0x0F},
{MT9M114_SENSOR_BYTE_WRITE, 0xC938, 0x64},
{MT9M114_SENSOR_BYTE_WRITE, 0xC939, 0x64},
{MT9M114_SENSOR_BYTE_WRITE, 0xC93A, 0x64},
{MT9M114_SENSOR_BYTE_WRITE, 0xC93B, 0x32},
{MT9M114_SENSOR_WORD_WRITE, 0xC93C, 0x0060},
{MT9M114_SENSOR_WORD_WRITE, 0xC93E, 0x009A},
{MT9M114_SENSOR_WORD_WRITE, 0xC940, 0x00DC},
{MT9M114_SENSOR_BYTE_WRITE, 0xC942, 0x38},
{MT9M114_SENSOR_BYTE_WRITE, 0xC943, 0x30},
{MT9M114_SENSOR_BYTE_WRITE, 0xC944, 0x50},
{MT9M114_SENSOR_BYTE_WRITE, 0xC945, 0x19},
{MT9M114_SENSOR_WORD_WRITE, 0xC94A, 0x00F0},
{MT9M114_SENSOR_WORD_WRITE, 0xC94C, 0x0010},
{MT9M114_SENSOR_WORD_WRITE, 0xC94E, 0x01CD},
{MT9M114_SENSOR_BYTE_WRITE, 0xC950, 0x05},
{MT9M114_SENSOR_BYTE_WRITE, 0xC951, 0x40},
{MT9M114_SENSOR_BYTE_WRITE, 0xC87A, 0x42},
{MT9M114_SENSOR_BYTE_WRITE, 0xC87B, 0x21},
{MT9M114_SENSOR_BYTE_WRITE, 0xC878, 0x0E},
{MT9M114_SENSOR_WORD_WRITE, 0xC890, 0x0080},
{MT9M114_SENSOR_WORD_WRITE, 0xC886, 0x0100},
{MT9M114_SENSOR_WORD_WRITE, 0xC87C, 0x0010},
{MT9M114_SENSOR_BYTE_WRITE, 0xB42A, 0x05},
{MT9M114_SENSOR_BYTE_WRITE, 0xA80A, 0x20},
{MT9M114_SENSOR_WORD_WRITE, 0x098E, 0x0000},
{MT9M114_SENSOR_WORD_WRITE, 0xC984, 0x8041},
{MT9M114_SENSOR_WORD_WRITE, 0x001E, 0x0777},
{MT9M114_SENSOR_WORD_WRITE, 0x098E, 0xDC00},
{MT9M114_SENSOR_BYTE_WRITE, 0xDC00, 0x28},
{MT9M114_SENSOR_WAIT_MS, 0, 50},
{MT9M114_SENSOR_WORD_WRITE, 0x0080, 0x8002},
{MT9M114_SENSOR_TABLE_END, 0x0000}
};
struct mt9m114_info {
struct miscdevice miscdev_info;
struct mt9m114_power_rail power;
struct mt9m114_sensordata sensor_data;
struct i2c_client *i2c_client;
struct mt9m114_platform_data *pdata;
atomic_t in_use;
const struct mt9m114_reg *mode;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
u32 debug_i2c_offset;
#endif
u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
};
struct mt9m114_mode_desc {
u16 xres;
u16 yres;
const struct mt9m114_reg *mode_tbl;
struct mt9m114_modeinfo mode_info;
};
static struct mt9m114_mode_desc mode_table[] = {
{
.xres = 1280,
.yres = 960,
.mode_tbl = mode_1280x960_30fps,
},
{ },
};
static long mt9m114_ioctl(struct file *file,
unsigned int cmd, unsigned long arg);
static inline void mt9m114_msleep(u32 t)
{
usleep_range(t*1000, t*1000 + 500);
}
static int mt9m114_read_reg(struct i2c_client *client, u16 addr, u8 *val)
{
int err;
struct i2c_msg msg[2];
unsigned char data[3];
if (!client->adapter)
return -ENODEV;
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 2;
msg[0].buf = data;
data[0] = (u8) (addr >> 8);
data[1] = (u8) (addr & 0xff);
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = 1;
msg[1].buf = data + 2;
err = i2c_transfer(client->adapter, msg, 2);
if (err != 2)
return -EINVAL;
*val = data[2];
return 0;
}
static int mt9m114_write_bulk_reg(struct i2c_client *client, u8 *data, int len)
{
int err;
struct i2c_msg msg;
if (!client->adapter)
return -ENODEV;
msg.addr = client->addr;
msg.flags = 0;
msg.len = len;
msg.buf = data;
dev_dbg(&client->dev,
"%s {0x%04x,", __func__, (int)data[0] << 8 | data[1]);
for (err = 2; err < len; err++)
dev_dbg(&client->dev, " 0x%02x", data[err]);
dev_dbg(&client->dev, "},\n");
err = i2c_transfer(client->adapter, &msg, 1);
if (err == 1)
return 0;
dev_err(&client->dev, "mt9m114: i2c bulk transfer failed at %x\n",
(int)data[0] << 8 | data[1]);
return err;
}
static int mt9m114_write_reg8(struct i2c_client *client, u16 addr, u8 val)
{
unsigned char data[3];
if (!client->adapter)
return -ENODEV;
data[0] = (u8) (addr >> 8);
data[1] = (u8) (addr & 0xff);
data[2] = (u8) (val & 0xff);
dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, val);
return mt9m114_write_bulk_reg(client, data, sizeof(data));
}
static int mt9m114_write_reg16(struct i2c_client *client, u16 addr, u16 val)
{
unsigned char data[4];
if (!client->adapter)
return -ENODEV;
data[0] = (u8) (addr >> 8);
data[1] = (u8) (addr & 0xff);
data[2] = (u8) (val >> 8);
data[3] = (u8) (val & 0xff);
dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, val);
return mt9m114_write_bulk_reg(client, data, sizeof(data));
}
static int mt9m114_write_table(
struct mt9m114_info *info,
const struct mt9m114_reg table[])
{
int err;
const struct mt9m114_reg *next;
u16 val;
dev_dbg(&info->i2c_client->dev, "yuv %s\n", __func__);
for (next = table; next->cmd != MT9M114_SENSOR_TABLE_END; next++) {
if (next->cmd == MT9M114_SENSOR_WAIT_MS) {
msleep(next->val);
continue;
}
val = next->val;
if (next->cmd == MT9M114_SENSOR_BYTE_WRITE)
err = mt9m114_write_reg8(info->i2c_client, next->addr, val);
else if (next->cmd == MT9M114_SENSOR_WORD_WRITE)
err = mt9m114_write_reg16(info->i2c_client, next->addr, val);
if (err)
return err;
}
return 0;
}
static int mt9m114_open(struct inode *inode, struct file *file)
{
struct miscdevice *miscdev = file->private_data;
struct mt9m114_info *info = dev_get_drvdata(miscdev->parent);
dev_dbg(&info->i2c_client->dev, "mt9m114: open.\n");
info = container_of(miscdev, struct mt9m114_info, miscdev_info);
/* check if the device is in use */
if (atomic_xchg(&info->in_use, 1)) {
dev_info(&info->i2c_client->dev, "%s:BUSY!\n", __func__);
return -EBUSY;
}
file->private_data = info;
if (info->pdata && info->pdata->power_on)
info->pdata->power_on(&info->power);
else {
dev_err(&info->i2c_client->dev,
"%s:no valid power_on function.\n", __func__);
return -EFAULT;
}
return 0;
}
int mt9m114_release(struct inode *inode, struct file *file)
{
struct mt9m114_info *info = file->private_data;
if (info->pdata && info->pdata->power_off)
info->pdata->power_off(&info->power);
file->private_data = NULL;
/* warn if device is already released */
WARN_ON(!atomic_xchg(&info->in_use, 0));
return 0;
}
static int mt9m114_regulator_get(struct mt9m114_info *info,
struct regulator **vreg, char vreg_name[])
{
struct regulator *reg = NULL;
int err = 0;
reg = devm_regulator_get(&info->i2c_client->dev, vreg_name);
if (unlikely(IS_ERR(reg))) {
dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n",
__func__, vreg_name, (int)reg);
err = PTR_ERR(reg);
reg = NULL;
} else {
dev_dbg(&info->i2c_client->dev, "%s: %s\n",
__func__, vreg_name);
}
*vreg = reg;
return err;
}
static int mt9m114_power_get(struct mt9m114_info *info)
{
struct mt9m114_power_rail *pw = &info->power;
dev_dbg(&info->i2c_client->dev, "mt9m114: %s\n", __func__);
/* note: mt9m114 uses i2c address 0x90, which is different from
* most of other sensors that using 0x64 or 0x20.
*
* This needs us to define a new vif2 as 2-0048
* for platform board file that uses mt9m114
* otherwise below could not get the regulator
*
* This rails of "vif2" and "vana" can be modified as needed
* for a new platform.
*
* mt9m114: need to get 1.8v first
*/
mt9m114_regulator_get(info, &pw->iovdd, "vif2"); /* interface 1.8v */
mt9m114_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */
return 0;
}
static const struct file_operations mt9m114_fileops = {
.owner = THIS_MODULE,
.open = mt9m114_open,
.unlocked_ioctl = mt9m114_ioctl,
.release = mt9m114_release,
};
static struct miscdevice mt9m114_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mt9m114",
.fops = &mt9m114_fileops,
};
#ifdef CONFIG_DEBUG_FS
static int mt9m114_stats_show(struct seq_file *s, void *data)
{
static struct mt9m114_info *info;
seq_printf(s, "%-20s : %-20s\n", "Name", "mt9m114-debugfs-testing");
seq_printf(s, "%-20s : 0x%X\n", "Current i2c-offset Addr",
info->debug_i2c_offset);
return 0;
}
static int mt9m114_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, mt9m114_stats_show, inode->i_private);
}
static const struct file_operations mt9m114_stats_fops = {
.open = mt9m114_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int debug_i2c_offset_w(void *data, u64 val)
{
struct mt9m114_info *info = (struct mt9m114_info *)(data);
dev_info(&info->i2c_client->dev,
"mt9m114:%s setting i2c offset to 0x%X\n",
__func__, (u32)val);
info->debug_i2c_offset = (u32)val;
dev_info(&info->i2c_client->dev,
"mt9m114:%s new i2c offset is 0x%X\n", __func__,
info->debug_i2c_offset);
return 0;
}
static int debug_i2c_offset_r(void *data, u64 *val)
{
struct mt9m114_info *info = (struct mt9m114_info *)(data);
*val = (u64)info->debug_i2c_offset;
dev_info(&info->i2c_client->dev,
"mt9m114:%s reading i2c offset is 0x%X\n", __func__,
info->debug_i2c_offset);
return 0;
}
static int debug_i2c_read(void *data, u64 *val)
{
struct mt9m114_info *info = (struct mt9m114_info *)(data);
u8 temp1 = 0;
u8 temp2 = 0;
dev_info(&info->i2c_client->dev,
"mt9m114:%s reading offset 0x%X\n", __func__,
info->debug_i2c_offset);
if (mt9m114_read_reg(info->i2c_client,
info->debug_i2c_offset, &temp1)
|| mt9m114_read_reg(info->i2c_client,
info->debug_i2c_offset+1, &temp2)) {
dev_err(&info->i2c_client->dev,
"mt9m114:%s failed\n", __func__);
return -EIO;
}
dev_info(&info->i2c_client->dev,
"mt9m114:%s read value is 0x%X\n", __func__,
temp1<<8 | temp2);
*val = (u64)(temp1<<8 | temp2);
return 0;
}
static int debug_i2c_write(void *data, u64 val)
{
struct mt9m114_info *info = (struct mt9m114_info *)(data);
dev_info(&info->i2c_client->dev,
"mt9m114:%s writing 0x%X to offset 0x%X\n", __func__,
(u16)val, info->debug_i2c_offset);
if (mt9m114_write_reg16(info->i2c_client,
info->debug_i2c_offset, (u16)val)) {
dev_err(&info->i2c_client->dev,
"mt9m114:%s failed\n", __func__);
return -EIO;
}
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(i2c_offset_fops, debug_i2c_offset_r,
debug_i2c_offset_w, "0x%llx\n");
DEFINE_SIMPLE_ATTRIBUTE(i2c_read_fops, debug_i2c_read,
/*debug_i2c_dummy_w*/ NULL, "0x%llx\n");
DEFINE_SIMPLE_ATTRIBUTE(i2c_write_fops, /*debug_i2c_dummy_r*/NULL,
debug_i2c_write, "0x%llx\n");
static int mt9m114_debug_init(struct mt9m114_info *info)
{
dev_dbg(&info->i2c_client->dev, "%s", __func__);
info->debugfs_root = debugfs_create_dir(mt9m114_device.name, NULL);
if (!info->debugfs_root)
goto err_out;
if (!debugfs_create_file("stats", S_IRUGO,
info->debugfs_root, info, &mt9m114_stats_fops))
goto err_out;
if (!debugfs_create_file("i2c_offset", S_IRUGO | S_IWUSR,
info->debugfs_root, info, &i2c_offset_fops))
goto err_out;
if (!debugfs_create_file("i2c_read", S_IRUGO,
info->debugfs_root, info, &i2c_read_fops))
goto err_out;
if (!debugfs_create_file("i2c_write", S_IWUSR,
info->debugfs_root, info, &i2c_write_fops))
goto err_out;
return 0;
err_out:
dev_err(&info->i2c_client->dev, "ERROR:%s failed", __func__);
if (info->debugfs_root)
debugfs_remove_recursive(info->debugfs_root);
return -ENOMEM;
}
#endif /* CONFIG_DEBUG_FS */
static struct mt9m114_modeinfo def_modeinfo = {
.xres = 1280,
.yres = 960,
};
static struct mt9m114_mode_desc *mt9m114_get_mode(
struct mt9m114_info *info, struct mt9m114_mode *mode)
{
struct mt9m114_mode_desc *mt = mode_table;
while (mt->xres) {
if ((mt->xres == mode->xres) &&
(mt->yres == mode->yres))
break;
mt++;
}
if (!mt->xres)
mt = NULL;
return mt;
}
static int mt9m114_mode_info_init(struct mt9m114_info *info)
{
struct mt9m114_mode_desc *md = mode_table;
const struct mt9m114_reg *mt;
struct mt9m114_modeinfo *mi;
dev_dbg(&info->i2c_client->dev, "%s", __func__);
while (md->xres) {
mi = &md->mode_info;
mt = md->mode_tbl;
memcpy(mi, &def_modeinfo, sizeof(*mi));
dev_dbg(&info->i2c_client->dev, "mode %d x %d ",
md->xres, md->yres);
mi->xres = md->xres;
mi->yres = md->yres;
md++;
}
return 0;
}
static int mt9m114_set_mode(struct mt9m114_info *info,
struct mt9m114_mode *mode)
{
struct mt9m114_mode_desc *sensor_mode;
int err;
dev_info(&info->i2c_client->dev,
"%s: xres %u yres %u\n", __func__, mode->xres, mode->yres);
sensor_mode = mt9m114_get_mode(info, mode);
if (sensor_mode == NULL) {
dev_err(&info->i2c_client->dev,
"%s: invalid params supplied to set mode %d %d\n",
__func__, mode->xres, mode->yres);
return -EINVAL;
}
err = mt9m114_write_table(
info, sensor_mode->mode_tbl);
if (err)
return err;
info->mode = sensor_mode->mode_tbl;
return 0;
}
static long mt9m114_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
int err = 0;
struct mt9m114_info *info = file->private_data;
switch (cmd) {
case MT9M114_SENSOR_IOCTL_SET_MODE:
{
struct mt9m114_mode mode;
dev_dbg(&info->i2c_client->dev, "MT9M114_IOCTL_SET_MODE\n");
if (copy_from_user(&mode, (const void __user *)arg,
sizeof(struct mt9m114_mode))) {
err = -EFAULT;
break;
}
err = mt9m114_set_mode(info, &mode);
break;
}
default:
dev_dbg(&info->i2c_client->dev, "INVALID IOCTL\n");
err = -EINVAL;
}
if (err)
dev_err(&info->i2c_client->dev,
"%s - %x: ERR = %d\n", __func__, cmd, err);
return err;
}
static int mt9m114_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
struct mt9m114_info *info;
dev_dbg(&client->dev, "mt9m114: probing sensor.\n");
info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
dev_err(&client->dev, "%s: kzalloc error\n", __func__);
return -ENOMEM;
}
info->pdata = client->dev.platform_data;
info->i2c_client = client;
atomic_set(&info->in_use, 0);
info->mode = NULL;
i2c_set_clientdata(client, info);
mt9m114_power_get(info);
mt9m114_mode_info_init(info);
memcpy(&info->miscdev_info,
&mt9m114_device,
sizeof(struct miscdevice));
err = misc_register(&info->miscdev_info);
if (err) {
dev_err(&info->i2c_client->dev, "mt9m114: Unable to register misc device!\n");
kfree(info);
return err;
}
#ifdef CONFIG_DEBUG_FS
mt9m114_debug_init(info);
#endif
return 0;
}
static int mt9m114_remove(struct i2c_client *client)
{
struct mt9m114_info *info;
info = i2c_get_clientdata(client);
misc_deregister(&mt9m114_device);
kfree(info);
#ifdef CONFIG_DEBUG_FS
if (info->debugfs_root)
debugfs_remove_recursive(info->debugfs_root);
#endif
return 0;
}
static const struct i2c_device_id mt9m114_id[] = {
{ "mt9m114", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, mt9m114_id);
static struct i2c_driver mt9m114_i2c_driver = {
.driver = {
.name = "mt9m114",
.owner = THIS_MODULE,
},
.probe = mt9m114_probe,
.remove = mt9m114_remove,
.id_table = mt9m114_id,
};
static int __init mt9m114_init(void)
{
pr_info("mt9m114 sensor driver loading\n");
return i2c_add_driver(&mt9m114_i2c_driver);
}
static void __exit mt9m114_exit(void)
{
i2c_del_driver(&mt9m114_i2c_driver);
}
module_init(mt9m114_init);
module_exit(mt9m114_exit);
MODULE_LICENSE("GPL v2");