| /* |
| * imx135.c - imx135 sensor driver |
| * |
| * 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 <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <linux/delay.h> |
| #include <linux/fs.h> |
| #include <linux/i2c.h> |
| #include <linux/clk.h> |
| #include <linux/miscdevice.h> |
| #include <linux/slab.h> |
| #include <linux/uaccess.h> |
| #include <linux/regulator/consumer.h> |
| #include <media/imx135.h> |
| #include <linux/gpio.h> |
| #include <linux/module.h> |
| |
| #include <linux/kernel.h> |
| #include <linux/debugfs.h> |
| #include <linux/seq_file.h> |
| #include <linux/of.h> |
| #include <linux/of_device.h> |
| #include <linux/of_gpio.h> |
| |
| #include "nvc_utilities.h" |
| |
| struct imx135_reg { |
| u16 addr; |
| u8 val; |
| }; |
| |
| struct imx135_info { |
| struct miscdevice miscdev_info; |
| int mode; |
| struct imx135_power_rail power; |
| struct imx135_sensordata sensor_data; |
| struct i2c_client *i2c_client; |
| struct imx135_platform_data *pdata; |
| struct clk *mclk; |
| struct mutex imx135_camera_lock; |
| struct dentry *debugdir; |
| atomic_t in_use; |
| }; |
| |
| #define IMX135_TABLE_WAIT_MS 0 |
| #define IMX135_TABLE_END 1 |
| #define IMX135_MAX_RETRIES 3 |
| #define IMX135_WAIT_MS 3 |
| |
| #define IMX135_4208x3120_HDR |
| |
| #define MAX_BUFFER_SIZE 32 |
| #define IMX135_FRAME_LENGTH_ADDR_MSB 0x0340 |
| #define IMX135_FRAME_LENGTH_ADDR_LSB 0x0341 |
| #define IMX135_COARSE_TIME_ADDR_MSB 0x0202 |
| #define IMX135_COARSE_TIME_ADDR_LSB 0x0203 |
| #define IMX135_COARSE_TIME_SHORT_ADDR_MSB 0x0230 |
| #define IMX135_COARSE_TIME_SHORT_ADDR_LSB 0x0231 |
| #define IMX135_GAIN_ADDR 0x0205 |
| #define IMX135_GAIN_SHORT_ADDR 0x0233 |
| |
| #ifdef IMX135_4208x3120_HDR |
| /* HDR */ |
| static struct imx135_reg mode_4208x3120[] = { |
| /* software reset */ |
| {0x0103, 0x01}, |
| /* global settings */ |
| {0x0101, 0x00}, |
| {0x0105, 0x01}, |
| {0x0110, 0x00}, |
| {0x0220, 0x01}, |
| {0x3302, 0x11}, |
| {0x3833, 0x20}, |
| {0x3873, 0x03}, |
| {0x3893, 0x00}, |
| {0x3906, 0x08}, |
| {0x3907, 0x01}, |
| {0x391B, 0x00}, |
| {0x3C09, 0x01}, |
| {0x600A, 0x00}, |
| {0x3008, 0xB0}, |
| {0x320A, 0x01}, |
| {0x320D, 0x10}, |
| {0x3216, 0x2E}, |
| {0x322C, 0x02}, |
| {0x3409, 0x0C}, |
| {0x340C, 0x2D}, |
| {0x3411, 0x39}, |
| {0x3414, 0x1E}, |
| {0x3427, 0x04}, |
| {0x3480, 0x1E}, |
| {0x3484, 0x1E}, |
| {0x3488, 0x1E}, |
| {0x348C, 0x1E}, |
| {0x3490, 0x1E}, |
| {0x3494, 0x1E}, |
| {0x3511, 0x8F}, |
| {0x364F, 0x2D}, |
| |
| /* Clock Setting */ |
| {0x011E, 0x18}, |
| {0x011F, 0x00}, |
| {0x0301, 0x05}, |
| {0x0303, 0x01}, |
| {0x0305, 0x0C}, |
| {0x0309, 0x05}, |
| {0x030B, 0x01}, |
| {0x030C, 0x01}, |
| {0x030D, 0xC2}, |
| {0x030E, 0x01}, |
| {0x3A06, 0x11}, |
| |
| /* Mode Settings */ |
| {0x0108, 0x03}, |
| {0x0112, 0x0E}, |
| {0x0113, 0x0A}, |
| {0x0381, 0x01}, |
| {0x0383, 0x01}, |
| {0x0385, 0x01}, |
| {0x0387, 0x01}, |
| {0x0390, 0x00}, |
| {0x0391, 0x11}, |
| {0x0392, 0x00}, |
| {0x0401, 0x00}, |
| {0x0404, 0x00}, |
| {0x0405, 0x10}, |
| {0x4082, 0x01}, |
| {0x4083, 0x01}, |
| {0x7006, 0x04}, |
| |
| /* Optinal/Function settings */ |
| {0x0700, 0x00}, |
| {0x3A63, 0x00}, |
| {0x4100, 0xF8}, |
| {0x4203, 0xFF}, |
| {0x4344, 0x00}, |
| {0x441C, 0x01}, |
| |
| /* Size Setting */ |
| {0x0340, 0x0C}, |
| {0x0341, 0xD0}, |
| {0x0342, 0x11}, |
| {0x0343, 0xDC}, |
| {0x0344, 0x00}, |
| {0x0345, 0x00}, |
| {0x0346, 0x00}, |
| {0x0347, 0x00}, |
| {0x0348, 0x10}, |
| {0x0349, 0x6F}, |
| {0x034A, 0x0C}, |
| {0x034B, 0x2F}, |
| {0x034C, 0x10}, |
| {0x034D, 0x70}, |
| {0x034E, 0x0C}, |
| {0x034F, 0x30}, |
| {0x0350, 0x00}, |
| {0x0351, 0x00}, |
| {0x0352, 0x00}, |
| {0x0353, 0x00}, |
| {0x0354, 0x10}, |
| {0x0355, 0x70}, |
| {0x0356, 0x0C}, |
| {0x0357, 0x30}, |
| {0x301D, 0x30}, |
| {0x3310, 0x10}, |
| {0x3311, 0x70}, |
| {0x3312, 0x0C}, |
| {0x3313, 0x30}, |
| {0x331C, 0x01}, |
| {0x331D, 0x68}, |
| {0x4084, 0x00}, |
| {0x4085, 0x00}, |
| {0x4086, 0x00}, |
| {0x4087, 0x00}, |
| {0x4400, 0x00}, |
| |
| /* Global Timing Setting */ |
| {0x0830, 0x87}, |
| {0x0831, 0x3F}, |
| {0x0832, 0x67}, |
| {0x0833, 0x3F}, |
| {0x0834, 0x3F}, |
| {0x0835, 0x4F}, |
| {0x0836, 0xDF}, |
| {0x0837, 0x47}, |
| {0x0839, 0x1F}, |
| {0x083A, 0x17}, |
| {0x083B, 0x02}, |
| |
| /* Integration Time Setting */ |
| {0x0202, 0x0C}, |
| {0x0203, 0xCC}, |
| |
| /* Gain Setting */ |
| {0x0205, 0x00}, |
| {0x020E, 0x01}, |
| {0x020F, 0x00}, |
| {0x0210, 0x01}, |
| {0x0211, 0x00}, |
| {0x0212, 0x01}, |
| {0x0213, 0x00}, |
| {0x0214, 0x01}, |
| {0x0215, 0x00}, |
| |
| /* HDR Setting */ |
| {0x0230, 0x00}, |
| {0x0231, 0x00}, |
| {0x0233, 0x00}, |
| {0x0234, 0x00}, |
| {0x0235, 0x40}, |
| {0x0238, 0x01}, |
| {0x0239, 0x04}, |
| {0x023B, 0x00}, |
| {0x023C, 0x01}, |
| {0x33B0, 0x10}, |
| {0x33B1, 0x70}, |
| {0x33B3, 0x01}, |
| {0x33B4, 0x01}, |
| {0x3800, 0x00}, |
| |
| {0x3A43, 0x01}, |
| /* stream on */ |
| {0x0100, 0x01}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| #else |
| /* standard */ |
| static struct imx135_reg mode_4208x3120[] = { |
| /* software reset */ |
| {0x0103, 0x01}, |
| /* global settings */ |
| {0x0101, 0x00}, |
| {0x0105, 0x01}, |
| {0x0110, 0x00}, |
| {0x0220, 0x01}, |
| {0x3302, 0x11}, |
| {0x3833, 0x20}, |
| {0x3893, 0x00}, |
| {0x3906, 0x08}, |
| {0x3907, 0x01}, |
| {0x391B, 0x01}, |
| {0x3C09, 0x01}, |
| {0x600A, 0x00}, |
| {0x3008, 0xB0}, |
| {0x320A, 0x01}, |
| {0x320D, 0x10}, |
| {0x3216, 0x2E}, |
| {0x322C, 0x02}, |
| {0x3409, 0x0C}, |
| {0x340C, 0x2D}, |
| {0x3411, 0x39}, |
| {0x3414, 0x1E}, |
| {0x3427, 0x04}, |
| {0x3480, 0x1E}, |
| {0x3484, 0x1E}, |
| {0x3488, 0x1E}, |
| {0x348C, 0x1E}, |
| {0x3490, 0x1E}, |
| {0x3494, 0x1E}, |
| {0x3511, 0x8F}, |
| {0x364F, 0x2D}, |
| |
| /* Clock Setting */ |
| {0x011E, 0x18}, |
| {0x011F, 0x00}, |
| {0x0301, 0x05}, |
| {0x0303, 0x01}, |
| {0x0305, 0x0C}, |
| {0x0309, 0x05}, |
| {0x030B, 0x01}, |
| {0x030C, 0x01}, |
| {0x030D, 0xC2}, |
| {0x030E, 0x01}, |
| {0x3A06, 0x11}, |
| |
| /* Mode Settings */ |
| {0x0108, 0x03}, |
| {0x0112, 0x0A}, |
| {0x0113, 0x0A}, |
| {0x0381, 0x01}, |
| {0x0383, 0x01}, |
| {0x0385, 0x01}, |
| {0x0387, 0x01}, |
| {0x0390, 0x00}, |
| {0x0391, 0x11}, |
| {0x0392, 0x00}, |
| {0x0401, 0x00}, |
| {0x0404, 0x00}, |
| {0x0405, 0x10}, |
| {0x4082, 0x01}, |
| {0x4083, 0x01}, |
| {0x7006, 0x04}, |
| |
| /* Optinal/Function settings */ |
| {0x0700, 0x00}, |
| {0x3A63, 0x00}, |
| {0x4100, 0xF8}, |
| {0x4203, 0xFF}, |
| {0x4344, 0x00}, |
| {0x441C, 0x01}, |
| |
| /* Size Setting */ |
| {0x0340, 0x0C}, |
| {0x0341, 0xD0}, |
| {0x0342, 0x11}, |
| {0x0343, 0xDC}, |
| {0x0344, 0x00}, |
| {0x0345, 0x00}, |
| {0x0346, 0x00}, |
| {0x0347, 0x00}, |
| {0x0348, 0x10}, |
| {0x0349, 0x6F}, |
| {0x034A, 0x0C}, |
| {0x034B, 0x2F}, |
| {0x034C, 0x10}, |
| {0x034D, 0x70}, |
| {0x034E, 0x0C}, |
| {0x034F, 0x30}, |
| {0x0350, 0x00}, |
| {0x0351, 0x00}, |
| {0x0352, 0x00}, |
| {0x0353, 0x00}, |
| {0x0354, 0x10}, |
| {0x0355, 0x70}, |
| {0x0356, 0x0C}, |
| {0x0357, 0x30}, |
| {0x301D, 0x30}, |
| {0x3310, 0x10}, |
| {0x3311, 0x70}, |
| {0x3312, 0x0C}, |
| {0x3313, 0x30}, |
| {0x331C, 0x01}, |
| {0x331D, 0x68}, |
| {0x4084, 0x00}, |
| {0x4085, 0x00}, |
| {0x4086, 0x00}, |
| {0x4087, 0x00}, |
| {0x4400, 0x00}, |
| |
| /* Global Timing Setting */ |
| {0x0830, 0x87}, |
| {0x0831, 0x3F}, |
| {0x0832, 0x67}, |
| {0x0833, 0x3F}, |
| {0x0834, 0x3F}, |
| {0x0835, 0x4F}, |
| {0x0836, 0xDF}, |
| {0x0837, 0x47}, |
| {0x0839, 0x1F}, |
| {0x083A, 0x17}, |
| {0x083B, 0x02}, |
| |
| /* Integration Time Setting */ |
| {0x0202, 0x0C}, |
| {0x0203, 0xCC}, |
| |
| /* Gain Setting */ |
| {0x0205, 0x04}, |
| {0x020E, 0x01}, |
| {0x020F, 0x00}, |
| {0x0210, 0x01}, |
| {0x0211, 0x00}, |
| {0x0212, 0x01}, |
| {0x0213, 0x00}, |
| {0x0214, 0x01}, |
| {0x0215, 0x00}, |
| |
| /* HDR Setting */ |
| {0x0230, 0x00}, |
| {0x0231, 0x00}, |
| {0x0233, 0x00}, |
| {0x0234, 0x00}, |
| {0x0235, 0x40}, |
| {0x0238, 0x01}, |
| {0x0239, 0x04}, |
| {0x023B, 0x00}, |
| {0x023C, 0x01}, |
| {0x33B0, 0x04}, |
| {0x33B1, 0x00}, |
| {0x33B3, 0x00}, |
| {0x33B4, 0x01}, |
| {0x3800, 0x00}, |
| |
| {0x3A43, 0x01}, |
| /* stream on */ |
| {0x0100, 0x01}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| #endif |
| |
| static struct imx135_reg mode_1920x1080[] = { |
| /* software reset */ |
| {0x0103, 0x01}, |
| /* global settings */ |
| {0x0101, 0x00}, |
| {0x0105, 0x01}, |
| {0x0110, 0x00}, |
| {0x0220, 0x01}, |
| {0x3302, 0x11}, |
| {0x3833, 0x20}, |
| {0x3893, 0x00}, |
| {0x3906, 0x08}, |
| {0x3907, 0x01}, |
| {0x391B, 0x01}, |
| {0x3C09, 0x01}, |
| {0x600A, 0x00}, |
| {0x3008, 0xB0}, |
| {0x320A, 0x01}, |
| {0x320D, 0x10}, |
| {0x3216, 0x2E}, |
| {0x322C, 0x02}, |
| {0x3409, 0x0C}, |
| {0x340C, 0x2D}, |
| {0x3411, 0x39}, |
| {0x3414, 0x1E}, |
| {0x3427, 0x04}, |
| {0x3480, 0x1E}, |
| {0x3484, 0x1E}, |
| {0x3488, 0x1E}, |
| {0x348C, 0x1E}, |
| {0x3490, 0x1E}, |
| {0x3494, 0x1E}, |
| {0x3511, 0x8F}, |
| {0x364F, 0x2D}, |
| |
| /* Clock Setting */ |
| {0x011E, 0x18}, |
| {0x011F, 0x00}, |
| {0x0301, 0x05}, |
| {0x0303, 0x01}, |
| {0x0305, 0x0C}, |
| {0x0309, 0x05}, |
| {0x030B, 0x02}, |
| {0x030C, 0x01}, |
| {0x030D, 0xC2}, |
| {0x030E, 0x01}, |
| {0x3A06, 0x12}, |
| |
| /* Mode Settings */ |
| {0x0108, 0x03}, |
| {0x0112, 0x0A}, |
| {0x0113, 0x0A}, |
| {0x0381, 0x01}, |
| {0x0383, 0x01}, |
| {0x0385, 0x01}, |
| {0x0387, 0x01}, |
| {0x0390, 0x01}, |
| {0x0391, 0x22}, |
| {0x0392, 0x00}, |
| {0x0401, 0x02}, |
| {0x0404, 0x00}, |
| {0x0405, 0x11}, |
| {0x4082, 0x00}, |
| {0x4083, 0x00}, |
| {0x7006, 0x04}, |
| |
| /* Optinal/Function settings */ |
| {0x0700, 0x00}, |
| {0x3A63, 0x00}, |
| {0x4100, 0xF8}, |
| {0x4203, 0xFF}, |
| {0x4344, 0x00}, |
| {0x441C, 0x01}, |
| |
| /* Size Setting */ |
| {0x0340, 0x0A}, |
| {0x0341, 0x40}, |
| {0x0342, 0x11}, |
| {0x0343, 0xDC}, |
| {0x0344, 0x00}, |
| {0x0345, 0x40}, |
| {0x0346, 0x01}, |
| {0x0347, 0x9C}, |
| {0x0348, 0x10}, |
| {0x0349, 0x2F}, |
| {0x034A, 0x0A}, |
| {0x034B, 0x93}, |
| {0x034C, 0x07}, |
| {0x034D, 0x80}, |
| {0x034E, 0x04}, |
| {0x034F, 0x38}, |
| {0x0350, 0x00}, |
| {0x0351, 0x00}, |
| {0x0352, 0x00}, |
| {0x0353, 0x00}, |
| {0x0354, 0x07}, |
| {0x0355, 0xF8}, |
| {0x0356, 0x04}, |
| {0x0357, 0x7C}, |
| {0x301D, 0x30}, |
| {0x3310, 0x07}, |
| {0x3311, 0x80}, |
| {0x3312, 0x04}, |
| {0x3313, 0x38}, |
| {0x331C, 0x00}, |
| {0x331D, 0xD2}, |
| {0x4084, 0x07}, |
| {0x4085, 0x80}, |
| {0x4086, 0x04}, |
| {0x4087, 0x38}, |
| {0x4400, 0x00}, |
| |
| /* Global Timing Setting */ |
| {0x0830, 0x67}, |
| {0x0831, 0x27}, |
| {0x0832, 0x47}, |
| {0x0833, 0x27}, |
| {0x0834, 0x27}, |
| {0x0835, 0x1F}, |
| {0x0836, 0x87}, |
| {0x0837, 0x2F}, |
| {0x0839, 0x1F}, |
| {0x083A, 0x17}, |
| {0x083B, 0x02}, |
| |
| /* Integration Time Setting */ |
| {0x0202, 0x0A}, |
| {0x0203, 0x3C}, |
| |
| /* Gain Setting */ |
| {0x0205, 0x00}, |
| {0x020E, 0x01}, |
| {0x020F, 0x00}, |
| {0x0210, 0x01}, |
| {0x0211, 0x00}, |
| {0x0212, 0x01}, |
| {0x0213, 0x00}, |
| {0x0214, 0x01}, |
| {0x0215, 0x00}, |
| |
| /* HDR Setting */ |
| {0x0230, 0x00}, |
| {0x0231, 0x00}, |
| {0x0233, 0x00}, |
| {0x0234, 0x00}, |
| {0x0235, 0x40}, |
| {0x0238, 0x01}, |
| {0x0239, 0x04}, |
| {0x023B, 0x00}, |
| {0x023C, 0x01}, |
| {0x33B0, 0x04}, |
| {0x33B1, 0x00}, |
| {0x33B3, 0x00}, |
| {0x33B4, 0x01}, |
| {0x3800, 0x00}, |
| |
| {0x3A43, 0x01}, |
| /* stream on */ |
| {0x0100, 0x01}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| |
| #ifdef IMX135_1280x720_90_FPS |
| /* 720p 90fps */ |
| static struct imx135_reg mode_1280x720[] = { |
| /* software reset */ |
| {0x0103, 0x01}, |
| /* global settings */ |
| {0x0101, 0x00}, |
| {0x0105, 0x01}, |
| {0x0110, 0x00}, |
| {0x0220, 0x01}, |
| {0x3302, 0x11}, |
| {0x3833, 0x20}, |
| {0x3893, 0x00}, |
| {0x3906, 0x08}, |
| {0x3907, 0x01}, |
| {0x391B, 0x01}, |
| {0x3C09, 0x01}, |
| {0x600A, 0x00}, |
| {0x3008, 0xB0}, |
| {0x320A, 0x01}, |
| {0x320D, 0x10}, |
| {0x3216, 0x2E}, |
| {0x322C, 0x02}, |
| {0x3409, 0x0C}, |
| {0x340C, 0x2D}, |
| {0x3411, 0x39}, |
| {0x3414, 0x1E}, |
| {0x3427, 0x04}, |
| {0x3480, 0x1E}, |
| {0x3484, 0x1E}, |
| {0x3488, 0x1E}, |
| {0x348C, 0x1E}, |
| {0x3490, 0x1E}, |
| {0x3494, 0x1E}, |
| {0x3511, 0x8F}, |
| {0x364F, 0x2D}, |
| |
| /* Clock Setting */ |
| {0x011E, 0x18}, |
| {0x011F, 0x00}, |
| {0x0301, 0x05}, |
| {0x0303, 0x01}, |
| {0x0305, 0x0C}, |
| {0x0309, 0x05}, |
| {0x030B, 0x02}, |
| {0x030C, 0x01}, |
| {0x030D, 0xC2}, |
| {0x030E, 0x01}, |
| {0x3A06, 0x12}, |
| |
| /* Mode Settings */ |
| {0x0108, 0x03}, |
| {0x0112, 0x0A}, |
| {0x0113, 0x0A}, |
| {0x0381, 0x01}, |
| {0x0383, 0x01}, |
| {0x0385, 0x01}, |
| {0x0387, 0x01}, |
| {0x0390, 0x01}, |
| {0x0391, 0x22}, |
| {0x0392, 0x00}, |
| {0x0401, 0x00}, |
| {0x0404, 0x00}, |
| {0x0405, 0x10}, |
| {0x4082, 0x01}, |
| {0x4083, 0x01}, |
| {0x7006, 0x04}, |
| |
| /* Optinal/Function settings */ |
| {0x0700, 0x00}, |
| {0x3A63, 0x00}, |
| {0x4100, 0xF8}, |
| {0x4203, 0xFF}, |
| {0x4344, 0x00}, |
| {0x441C, 0x01}, |
| |
| /* Size Setting */ |
| {0x0340, 0x03}, |
| {0x0341, 0x6A}, |
| {0x0342, 0x11}, |
| {0x0343, 0xDC}, |
| {0x0344, 0x03}, |
| {0x0345, 0x38}, |
| {0x0346, 0x03}, |
| {0x0347, 0x48}, |
| {0x0348, 0x0D}, |
| {0x0349, 0x37}, |
| {0x034A, 0x08}, |
| {0x034B, 0xE7}, |
| {0x034C, 0x05}, |
| {0x034D, 0x00}, |
| {0x034E, 0x02}, |
| {0x034F, 0xD0}, |
| {0x0350, 0x00}, |
| {0x0351, 0x00}, |
| {0x0352, 0x00}, |
| {0x0353, 0x00}, |
| {0x0354, 0x05}, |
| {0x0355, 0x00}, |
| {0x0356, 0x02}, |
| {0x0357, 0xD0}, |
| {0x301D, 0x30}, |
| {0x3310, 0x05}, |
| {0x3311, 0x00}, |
| {0x3312, 0x02}, |
| {0x3313, 0xD0}, |
| {0x331C, 0x00}, |
| {0x331D, 0x10}, |
| {0x4084, 0x00}, |
| {0x4085, 0x00}, |
| {0x4086, 0x00}, |
| {0x4087, 0x00}, |
| {0x4400, 0x00}, |
| |
| /* Global Timing Setting */ |
| {0x0830, 0x67}, |
| {0x0831, 0x27}, |
| {0x0832, 0x47}, |
| {0x0833, 0x27}, |
| {0x0834, 0x27}, |
| {0x0835, 0x1F}, |
| {0x0836, 0x87}, |
| {0x0837, 0x2F}, |
| {0x0839, 0x1F}, |
| {0x083A, 0x17}, |
| {0x083B, 0x02}, |
| |
| /* Integration Time Setting */ |
| {0x0202, 0x03}, |
| {0x0203, 0x66}, |
| |
| /* Gain Setting */ |
| {0x0205, 0x00}, |
| {0x020E, 0x01}, |
| {0x020F, 0x00}, |
| {0x0210, 0x01}, |
| {0x0211, 0x00}, |
| {0x0212, 0x01}, |
| {0x0213, 0x00}, |
| {0x0214, 0x01}, |
| {0x0215, 0x00}, |
| |
| /* HDR Setting */ |
| {0x0230, 0x00}, |
| {0x0231, 0x00}, |
| {0x0233, 0x00}, |
| {0x0234, 0x00}, |
| {0x0235, 0x40}, |
| {0x0238, 0x01}, |
| {0x0239, 0x04}, |
| {0x023B, 0x00}, |
| {0x023C, 0x01}, |
| {0x33B0, 0x04}, |
| {0x33B1, 0x00}, |
| {0x33B3, 0x00}, |
| {0x33B4, 0x01}, |
| {0x3800, 0x00}, |
| |
| {0x3A43, 0x01}, |
| /* stream on */ |
| {0x0100, 0x01}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| #else |
| /* 720p 30fps */ |
| static struct imx135_reg mode_1280x720[] = { |
| /* software reset */ |
| {0x0103, 0x01}, |
| /* global settings */ |
| {0x0101, 0x00}, |
| {0x0105, 0x01}, |
| {0x0110, 0x00}, |
| {0x0220, 0x01}, |
| {0x3302, 0x11}, |
| {0x3833, 0x20}, |
| {0x3893, 0x00}, |
| {0x3906, 0x08}, |
| {0x3907, 0x01}, |
| {0x391B, 0x01}, |
| {0x3C09, 0x01}, |
| {0x600A, 0x00}, |
| {0x3008, 0xB0}, |
| {0x320A, 0x01}, |
| {0x320D, 0x10}, |
| {0x3216, 0x2E}, |
| {0x322C, 0x02}, |
| {0x3409, 0x0C}, |
| {0x340C, 0x2D}, |
| {0x3411, 0x39}, |
| {0x3414, 0x1E}, |
| {0x3427, 0x04}, |
| {0x3480, 0x1E}, |
| {0x3484, 0x1E}, |
| {0x3488, 0x1E}, |
| {0x348C, 0x1E}, |
| {0x3490, 0x1E}, |
| {0x3494, 0x1E}, |
| {0x3511, 0x8F}, |
| {0x364F, 0x2D}, |
| |
| /* Clock Setting */ |
| {0x011E, 0x18}, |
| {0x011F, 0x00}, |
| {0x0301, 0x05}, |
| {0x0303, 0x01}, |
| {0x0305, 0x0C}, |
| {0x0309, 0x05}, |
| {0x030B, 0x02}, |
| {0x030C, 0x01}, |
| {0x030D, 0xC2}, |
| {0x030E, 0x01}, |
| {0x3A06, 0x12}, |
| |
| /* Mode Settings */ |
| {0x0108, 0x03}, |
| {0x0112, 0x0A}, |
| {0x0113, 0x0A}, |
| {0x0381, 0x01}, |
| {0x0383, 0x01}, |
| {0x0385, 0x01}, |
| {0x0387, 0x01}, |
| {0x0390, 0x01}, |
| {0x0391, 0x22}, |
| {0x0392, 0x00}, |
| {0x0401, 0x02}, |
| {0x0404, 0x00}, |
| {0x0405, 0x1A}, |
| {0x4082, 0x00}, |
| {0x4083, 0x00}, |
| {0x7006, 0x04}, |
| |
| /* Optinal/Function settings */ |
| {0x0700, 0x00}, |
| {0x3A63, 0x00}, |
| {0x4100, 0xF8}, |
| {0x4203, 0xFF}, |
| {0x4344, 0x00}, |
| {0x441C, 0x01}, |
| |
| /* Size Setting */ |
| {0x0340, 0x0A}, |
| {0x0341, 0x40}, |
| {0x0342, 0x11}, |
| {0x0343, 0xDC}, |
| {0x0344, 0x00}, |
| {0x0345, 0x18}, |
| {0x0346, 0x01}, |
| {0x0347, 0x88}, |
| {0x0348, 0x10}, |
| {0x0349, 0x57}, |
| {0x034A, 0x0A}, |
| {0x034B, 0xAB}, |
| {0x034C, 0x05}, |
| {0x034D, 0x00}, |
| {0x034E, 0x02}, |
| {0x034F, 0xD0}, |
| {0x0350, 0x00}, |
| {0x0351, 0x00}, |
| {0x0352, 0x00}, |
| {0x0353, 0x00}, |
| {0x0354, 0x08}, |
| {0x0355, 0x20}, |
| {0x0356, 0x04}, |
| {0x0357, 0x92}, |
| {0x301D, 0x30}, |
| {0x3310, 0x05}, |
| {0x3311, 0x00}, |
| {0x3312, 0x02}, |
| {0x3313, 0xD0}, |
| {0x331C, 0x02}, |
| {0x331D, 0x18}, |
| {0x4084, 0x05}, |
| {0x4085, 0x00}, |
| {0x4086, 0x02}, |
| {0x4087, 0xD0}, |
| {0x4400, 0x00}, |
| |
| /* Global Timing Setting */ |
| {0x0830, 0x67}, |
| {0x0831, 0x27}, |
| {0x0832, 0x47}, |
| {0x0833, 0x27}, |
| {0x0834, 0x27}, |
| {0x0835, 0x1F}, |
| {0x0836, 0x87}, |
| {0x0837, 0x2F}, |
| {0x0839, 0x1F}, |
| {0x083A, 0x17}, |
| {0x083B, 0x02}, |
| |
| /* Integration Time Setting */ |
| {0x0202, 0x0A}, |
| {0x0203, 0x3C}, |
| |
| /* Gain Setting */ |
| {0x0205, 0x00}, |
| {0x020E, 0x01}, |
| {0x020F, 0x00}, |
| {0x0210, 0x01}, |
| {0x0211, 0x00}, |
| {0x0212, 0x01}, |
| {0x0213, 0x00}, |
| {0x0214, 0x01}, |
| {0x0215, 0x00}, |
| |
| /* HDR Setting */ |
| {0x0230, 0x00}, |
| {0x0231, 0x00}, |
| {0x0233, 0x00}, |
| {0x0234, 0x00}, |
| {0x0235, 0x40}, |
| {0x0238, 0x01}, |
| {0x0239, 0x04}, |
| {0x023B, 0x00}, |
| {0x023C, 0x01}, |
| {0x33B0, 0x04}, |
| {0x33B1, 0x00}, |
| {0x33B3, 0x00}, |
| {0x33B4, 0x01}, |
| {0x3800, 0x00}, |
| |
| {0x3A43, 0x01}, |
| /* stream on */ |
| {0x0100, 0x01}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| #endif |
| |
| static struct imx135_reg mode_2616x1472[] = { |
| /* software reset */ |
| {0x0103, 0x01}, |
| /* global settings */ |
| {0x0101, 0x00}, |
| {0x0105, 0x01}, |
| {0x0110, 0x00}, |
| {0x0220, 0x01}, |
| {0x3302, 0x11}, |
| {0x3833, 0x20}, |
| {0x3873, 0x03}, |
| {0x3893, 0x00}, |
| {0x3906, 0x08}, |
| {0x3907, 0x01}, |
| {0x391B, 0x00}, |
| {0x3C09, 0x01}, |
| {0x600A, 0x00}, |
| {0x3008, 0xB0}, |
| {0x320A, 0x01}, |
| {0x320D, 0x10}, |
| {0x3216, 0x2E}, |
| {0x322C, 0x02}, |
| {0x3409, 0x0C}, |
| {0x340C, 0x2D}, |
| {0x3411, 0x39}, |
| {0x3414, 0x1E}, |
| {0x3427, 0x04}, |
| {0x3480, 0x1E}, |
| {0x3484, 0x1E}, |
| {0x3488, 0x1E}, |
| {0x348C, 0x1E}, |
| {0x3490, 0x1E}, |
| {0x3494, 0x1E}, |
| {0x3511, 0x8F}, |
| {0x364F, 0x2D}, |
| |
| /* Clock Setting */ |
| {0x011E, 0x18}, |
| {0x011F, 0x00}, |
| {0x0301, 0x05}, |
| {0x0303, 0x01}, |
| {0x0305, 0x0C}, |
| {0x0309, 0x05}, |
| {0x030B, 0x01}, |
| {0x030C, 0x01}, |
| {0x030D, 0xC2}, |
| {0x030E, 0x01}, |
| {0x3A06, 0x11}, |
| |
| /* Mode Settings */ |
| {0x0108, 0x03}, |
| {0x0112, 0x0E}, |
| {0x0113, 0x0A}, |
| {0x0381, 0x01}, |
| {0x0383, 0x01}, |
| {0x0385, 0x01}, |
| {0x0387, 0x01}, |
| {0x0390, 0x00}, |
| {0x0391, 0x11}, |
| {0x0392, 0x00}, |
| {0x0401, 0x00}, |
| {0x0404, 0x00}, |
| {0x0405, 0x10}, |
| {0x4082, 0x01}, |
| {0x4083, 0x01}, |
| {0x7006, 0x04}, |
| |
| /* Optinal/Function settings */ |
| {0x0700, 0x00}, |
| {0x3A63, 0x00}, |
| {0x4100, 0xF8}, |
| {0x4203, 0xFF}, |
| {0x4344, 0x00}, |
| {0x441C, 0x01}, |
| |
| /* Size Setting */ |
| {0x0340, 0x0A}, |
| {0x0341, 0x40}, |
| {0x0342, 0x11}, |
| {0x0343, 0xDC}, |
| {0x0344, 0x03}, |
| {0x0345, 0x1C}, |
| {0x0346, 0x03}, |
| {0x0347, 0x38}, |
| {0x0348, 0x0D}, |
| {0x0349, 0x53}, |
| {0x034A, 0x08}, |
| {0x034B, 0xF7}, |
| {0x034C, 0x0A}, |
| {0x034D, 0x38}, |
| {0x034E, 0x05}, |
| {0x034F, 0xC0}, |
| {0x0350, 0x00}, |
| {0x0351, 0x00}, |
| {0x0352, 0x00}, |
| {0x0353, 0x00}, |
| {0x0354, 0x0A}, |
| {0x0355, 0x38}, |
| {0x0356, 0x05}, |
| {0x0357, 0xC0}, |
| {0x301D, 0x30}, |
| {0x3310, 0x0A}, |
| {0x3311, 0x38}, |
| {0x3312, 0x05}, |
| {0x3313, 0xC0}, |
| {0x331C, 0x08}, |
| {0x331D, 0xD4}, |
| {0x4084, 0x00}, |
| {0x4085, 0x00}, |
| {0x4086, 0x00}, |
| {0x4087, 0x00}, |
| {0x4400, 0x00}, |
| |
| /* Global Timing Setting */ |
| {0x0830, 0x87}, |
| {0x0831, 0x3F}, |
| {0x0832, 0x67}, |
| {0x0833, 0x3F}, |
| {0x0834, 0x3F}, |
| {0x0835, 0x4F}, |
| {0x0836, 0xDF}, |
| {0x0837, 0x47}, |
| {0x0839, 0x1F}, |
| {0x083A, 0x17}, |
| {0x083B, 0x02}, |
| |
| /* Integration Time Setting */ |
| {0x0202, 0x0A}, |
| {0x0203, 0x3C}, |
| |
| /* Gain Setting */ |
| {0x0205, 0x00}, |
| {0x020E, 0x01}, |
| {0x020F, 0x00}, |
| {0x0210, 0x01}, |
| {0x0211, 0x00}, |
| {0x0212, 0x01}, |
| {0x0213, 0x00}, |
| {0x0214, 0x01}, |
| {0x0215, 0x00}, |
| |
| /* HDR Setting */ |
| {0x0230, 0x00}, |
| {0x0231, 0x00}, |
| {0x0233, 0x00}, |
| {0x0234, 0x00}, |
| {0x0235, 0x40}, |
| {0x0238, 0x01}, |
| {0x0239, 0x04}, |
| {0x023B, 0x00}, |
| {0x023C, 0x01}, |
| {0x33B0, 0x0A}, |
| {0x33B1, 0x38}, |
| {0x33B3, 0x01}, |
| {0x33B4, 0x01}, |
| {0x3800, 0x00}, |
| |
| {0x3A43, 0x01}, |
| /* stream on */ |
| {0x0100, 0x01}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| |
| static struct imx135_reg mode_3896x2192[] = { |
| /* software reset */ |
| {0x0103, 0x01}, |
| /* global settings */ |
| {0x0101, 0x00}, |
| {0x0105, 0x01}, |
| {0x0110, 0x00}, |
| {0x0220, 0x01}, |
| {0x3302, 0x11}, |
| {0x3833, 0x20}, |
| {0x3873, 0x03}, |
| {0x3893, 0x00}, |
| {0x3906, 0x08}, |
| {0x3907, 0x01}, |
| {0x391B, 0x00}, |
| {0x3C09, 0x01}, |
| {0x600A, 0x00}, |
| {0x3008, 0xB0}, |
| {0x320A, 0x01}, |
| {0x320D, 0x10}, |
| {0x3216, 0x2E}, |
| {0x322C, 0x02}, |
| {0x3409, 0x0C}, |
| {0x340C, 0x2D}, |
| {0x3411, 0x39}, |
| {0x3414, 0x1E}, |
| {0x3427, 0x04}, |
| {0x3480, 0x1E}, |
| {0x3484, 0x1E}, |
| {0x3488, 0x1E}, |
| {0x348C, 0x1E}, |
| {0x3490, 0x1E}, |
| {0x3494, 0x1E}, |
| {0x3511, 0x8F}, |
| {0x364F, 0x2D}, |
| |
| /* Clock Setting */ |
| {0x011E, 0x18}, |
| {0x011F, 0x00}, |
| {0x0301, 0x05}, |
| {0x0303, 0x01}, |
| {0x0305, 0x0C}, |
| {0x0309, 0x05}, |
| {0x030B, 0x01}, |
| {0x030C, 0x01}, |
| {0x030D, 0xC2}, |
| {0x030E, 0x01}, |
| {0x3A06, 0x11}, |
| |
| /* Mode Settings */ |
| {0x0108, 0x03}, |
| {0x0112, 0x0E}, |
| {0x0113, 0x0A}, |
| {0x0381, 0x01}, |
| {0x0383, 0x01}, |
| {0x0385, 0x01}, |
| {0x0387, 0x01}, |
| {0x0390, 0x00}, |
| {0x0391, 0x11}, |
| {0x0392, 0x00}, |
| {0x0401, 0x00}, |
| {0x0404, 0x00}, |
| {0x0405, 0x10}, |
| {0x4082, 0x01}, |
| {0x4083, 0x01}, |
| {0x7006, 0x04}, |
| |
| /* Optinal/Function settings */ |
| {0x0700, 0x00}, |
| {0x3A63, 0x00}, |
| {0x4100, 0xF8}, |
| {0x4203, 0xFF}, |
| {0x4344, 0x00}, |
| {0x441C, 0x01}, |
| |
| /* Size Setting */ |
| {0x0340, 0x0A}, |
| {0x0341, 0x40}, |
| {0x0342, 0x11}, |
| {0x0343, 0xDC}, |
| {0x0344, 0x00}, |
| {0x0345, 0x9C}, |
| {0x0346, 0x01}, |
| {0x0347, 0xD0}, |
| {0x0348, 0x0F}, |
| {0x0349, 0xD3}, |
| {0x034A, 0x0A}, |
| {0x034B, 0x5F}, |
| {0x034C, 0x0F}, |
| {0x034D, 0x38}, |
| {0x034E, 0x08}, |
| {0x034F, 0x90}, |
| {0x0350, 0x00}, |
| {0x0351, 0x00}, |
| {0x0352, 0x00}, |
| {0x0353, 0x00}, |
| {0x0354, 0x0F}, |
| {0x0355, 0x38}, |
| {0x0356, 0x08}, |
| {0x0357, 0x90}, |
| {0x301D, 0x30}, |
| {0x3310, 0x0F}, |
| {0x3311, 0x38}, |
| {0x3312, 0x08}, |
| {0x3313, 0x90}, |
| {0x331C, 0x0F}, |
| {0x331D, 0x32}, |
| {0x4084, 0x00}, |
| {0x4085, 0x00}, |
| {0x4086, 0x00}, |
| {0x4087, 0x00}, |
| {0x4400, 0x00}, |
| |
| /* Global Timing Setting */ |
| {0x0830, 0x87}, |
| {0x0831, 0x3F}, |
| {0x0832, 0x67}, |
| {0x0833, 0x3F}, |
| {0x0834, 0x3F}, |
| {0x0835, 0x4F}, |
| {0x0836, 0xDF}, |
| {0x0837, 0x47}, |
| {0x0839, 0x1F}, |
| {0x083A, 0x17}, |
| {0x083B, 0x02}, |
| |
| /* Integration Time Setting */ |
| {0x0202, 0x0A}, |
| {0x0203, 0x3C}, |
| |
| /* Gain Setting */ |
| {0x0205, 0x00}, |
| {0x020E, 0x01}, |
| {0x020F, 0x00}, |
| {0x0210, 0x01}, |
| {0x0211, 0x00}, |
| {0x0212, 0x01}, |
| {0x0213, 0x00}, |
| {0x0214, 0x01}, |
| {0x0215, 0x00}, |
| |
| /* HDR Setting */ |
| {0x0230, 0x00}, |
| {0x0231, 0x00}, |
| {0x0233, 0x00}, |
| {0x0234, 0x00}, |
| {0x0235, 0x40}, |
| {0x0238, 0x01}, |
| {0x0239, 0x04}, |
| {0x023B, 0x00}, |
| {0x023C, 0x01}, |
| {0x33B0, 0x0F}, |
| {0x33B1, 0x38}, |
| {0x33B3, 0x01}, |
| {0x33B4, 0x01}, |
| {0x3800, 0x00}, |
| |
| {0x3A43, 0x01}, |
| /* stream on */ |
| {0x0100, 0x01}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| |
| static struct imx135_reg mode_quality_hdr[] = { |
| /* defect correction */ |
| {0x380A, 0x00}, |
| {0x380B, 0x00}, |
| {0x4103, 0x00}, |
| /* color artifact */ |
| {0x4243, 0x9A}, |
| {0x4330, 0x01}, |
| {0x4331, 0x90}, |
| {0x4332, 0x02}, |
| {0x4333, 0x58}, |
| {0x4334, 0x03}, |
| {0x4335, 0x20}, |
| {0x4336, 0x03}, |
| {0x4337, 0x84}, |
| {0x433C, 0x01}, |
| {0x4340, 0x02}, |
| {0x4341, 0x58}, |
| {0x4342, 0x03}, |
| {0x4343, 0x52}, |
| /* moire reduction */ |
| {0x4364, 0x0B}, |
| {0x4368, 0x00}, |
| {0x4369, 0x0F}, |
| {0x436A, 0x03}, |
| {0x436B, 0xA8}, |
| {0x436C, 0x00}, |
| {0x436D, 0x00}, |
| {0x436E, 0x00}, |
| {0x436F, 0x06}, |
| /* CNR parameter */ |
| {0x4281, 0x21}, |
| {0x4282, 0x18}, |
| {0x4283, 0x04}, |
| {0x4284, 0x08}, |
| {0x4287, 0x7F}, |
| {0x4288, 0x08}, |
| {0x428B, 0x7F}, |
| {0x428C, 0x08}, |
| {0x428F, 0x7F}, |
| {0x4297, 0x00}, |
| {0x4298, 0x7E}, |
| {0x4299, 0x7E}, |
| {0x429A, 0x7E}, |
| {0x42A4, 0xFB}, |
| {0x42A5, 0x7E}, |
| {0x42A6, 0xDF}, |
| {0x42A7, 0xB7}, |
| {0x42AF, 0x03}, |
| |
| /* ARNR Parameter Settings */ |
| {0x4207, 0x03}, |
| {0x4216, 0x08}, |
| {0x4217, 0x08}, |
| |
| /* DLC parameter */ |
| {0x4218, 0x00}, |
| {0x421B, 0x20}, |
| {0x421F, 0x04}, |
| {0x4222, 0x02}, |
| {0x4223, 0x22}, |
| {0x422E, 0x54}, |
| {0x422F, 0xFB}, |
| {0x4230, 0xFF}, |
| {0x4231, 0xFE}, |
| {0x4232, 0xFF}, |
| {0x4235, 0x58}, |
| {0x4236, 0xF7}, |
| {0x4237, 0xFD}, |
| {0x4239, 0x4E}, |
| {0x423A, 0xFC}, |
| {0x423B, 0xFD}, |
| |
| /* HDR Setting */ |
| {0x4300, 0x00}, |
| {0x4316, 0x12}, |
| {0x4317, 0x22}, |
| {0x4318, 0x00}, |
| {0x4319, 0x00}, |
| {0x431A, 0x00}, |
| {0x4324, 0x03}, |
| {0x4325, 0x20}, |
| {0x4326, 0x03}, |
| {0x4327, 0x84}, |
| {0x4328, 0x03}, |
| {0x4329, 0x20}, |
| {0x432A, 0x03}, |
| {0x432B, 0x20}, |
| {0x432C, 0x01}, |
| {0x432D, 0x01}, |
| {0x4338, 0x02}, |
| {0x4339, 0x00}, |
| {0x433A, 0x00}, |
| {0x433B, 0x02}, |
| {0x435A, 0x03}, |
| {0x435B, 0x84}, |
| {0x435E, 0x01}, |
| {0x435F, 0xFF}, |
| {0x4360, 0x01}, |
| {0x4361, 0xF4}, |
| {0x4362, 0x03}, |
| {0x4363, 0x84}, |
| {0x437B, 0x01}, |
| {0x4401, 0x3F}, |
| {0x4402, 0xFF}, |
| {0x4404, 0x13}, |
| {0x4405, 0x26}, |
| {0x4406, 0x07}, |
| {0x4408, 0x20}, |
| {0x4409, 0xE5}, |
| {0x440A, 0xFB}, |
| {0x440C, 0xF6}, |
| {0x440D, 0xEA}, |
| {0x440E, 0x20}, |
| {0x4410, 0x00}, |
| {0x4411, 0x00}, |
| {0x4412, 0x3F}, |
| {0x4413, 0xFF}, |
| {0x4414, 0x1F}, |
| {0x4415, 0xFF}, |
| {0x4416, 0x20}, |
| {0x4417, 0x00}, |
| {0x4418, 0x1F}, |
| {0x4419, 0xFF}, |
| {0x441A, 0x20}, |
| {0x441B, 0x00}, |
| {0x441D, 0x40}, |
| {0x441E, 0x1E}, |
| {0x441F, 0x38}, |
| {0x4420, 0x01}, |
| {0x4444, 0x00}, |
| {0x4445, 0x00}, |
| {0x4446, 0x1D}, |
| {0x4447, 0xF9}, |
| {0x4452, 0x00}, |
| {0x4453, 0xA0}, |
| {0x4454, 0x08}, |
| {0x4455, 0x00}, |
| {0x4456, 0x0F}, |
| {0x4457, 0xFF}, |
| {0x4458, 0x18}, |
| {0x4459, 0x18}, |
| {0x445A, 0x3F}, |
| {0x445B, 0x3A}, |
| {0x445C, 0x00}, |
| {0x445D, 0x28}, |
| {0x445E, 0x01}, |
| {0x445F, 0x90}, |
| {0x4460, 0x00}, |
| {0x4461, 0x60}, |
| {0x4462, 0x00}, |
| {0x4463, 0x00}, |
| {0x4464, 0x00}, |
| {0x4465, 0x00}, |
| {0x446C, 0x01}, |
| {0x446D, 0x00}, |
| {0x446E, 0x00}, |
| |
| /* LSC setting */ |
| {0x452A, 0x02}, |
| |
| /* White balance */ |
| {0x0712, 0x01}, |
| {0x0713, 0x00}, |
| {0x0714, 0x01}, |
| {0x0715, 0x00}, |
| {0x0716, 0x01}, |
| {0x0717, 0x00}, |
| {0x0718, 0x01}, |
| {0x0719, 0x00}, |
| |
| /* Shading */ |
| {0x4500, 0x1F}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| |
| static struct imx135_reg mode_quality[] = { |
| /* defect correction */ |
| {0x380A, 0x00}, |
| {0x380B, 0x00}, |
| {0x4103, 0x00}, |
| /* color artifact */ |
| {0x4243, 0x9A}, |
| {0x4330, 0x01}, |
| {0x4331, 0x90}, |
| {0x4332, 0x02}, |
| {0x4333, 0x58}, |
| {0x4334, 0x03}, |
| {0x4335, 0x20}, |
| {0x4336, 0x03}, |
| {0x4337, 0x84}, |
| {0x433C, 0x01}, |
| {0x4340, 0x02}, |
| {0x4341, 0x58}, |
| {0x4342, 0x03}, |
| {0x4343, 0x52}, |
| /* moire reduction */ |
| {0x4364, 0x0B}, |
| {0x4368, 0x00}, |
| {0x4369, 0x0F}, |
| {0x436A, 0x03}, |
| {0x436B, 0xA8}, |
| {0x436C, 0x00}, |
| {0x436D, 0x00}, |
| {0x436E, 0x00}, |
| {0x436F, 0x06}, |
| /* CNR parameter */ |
| {0x4281, 0x21}, |
| {0x4282, 0x18}, |
| {0x4283, 0x04}, |
| {0x4284, 0x08}, |
| {0x4287, 0x7F}, |
| {0x4288, 0x08}, |
| {0x428B, 0x7F}, |
| {0x428C, 0x08}, |
| {0x428F, 0x7F}, |
| {0x4297, 0x00}, |
| {0x4298, 0x7E}, |
| {0x4299, 0x7E}, |
| {0x429A, 0x7E}, |
| {0x42A4, 0xFB}, |
| {0x42A5, 0x7E}, |
| {0x42A6, 0xDF}, |
| {0x42A7, 0xB7}, |
| {0x42AF, 0x03}, |
| |
| /* ARNR Parameter Settings */ |
| {0x4207, 0x03}, |
| {0x4216, 0x08}, |
| {0x4217, 0x08}, |
| |
| /* DLC parameter */ |
| {0x4218, 0x00}, |
| {0x421B, 0x20}, |
| {0x421F, 0x04}, |
| {0x4222, 0x02}, |
| {0x4223, 0x22}, |
| {0x422E, 0x54}, |
| {0x422F, 0xFB}, |
| {0x4230, 0xFF}, |
| {0x4231, 0xFE}, |
| {0x4232, 0xFF}, |
| {0x4235, 0x58}, |
| {0x4236, 0xF7}, |
| {0x4237, 0xFD}, |
| {0x4239, 0x4E}, |
| {0x423A, 0xFC}, |
| {0x423B, 0xFD}, |
| |
| /* HDR Setting */ |
| {0x4300, 0x00}, |
| {0x4316, 0x12}, |
| {0x4317, 0x22}, |
| {0x4318, 0x00}, |
| {0x4319, 0x00}, |
| {0x431A, 0x00}, |
| {0x4324, 0x03}, |
| {0x4325, 0x20}, |
| {0x4326, 0x03}, |
| {0x4327, 0x84}, |
| {0x4328, 0x03}, |
| {0x4329, 0x20}, |
| {0x432A, 0x03}, |
| {0x432B, 0x20}, |
| {0x432C, 0x01}, |
| {0x432D, 0x01}, |
| {0x4338, 0x02}, |
| {0x4339, 0x00}, |
| {0x433A, 0x00}, |
| {0x433B, 0x02}, |
| {0x435A, 0x03}, |
| {0x435B, 0x84}, |
| {0x435E, 0x01}, |
| {0x435F, 0xFF}, |
| {0x4360, 0x01}, |
| {0x4361, 0xF4}, |
| {0x4362, 0x03}, |
| {0x4363, 0x84}, |
| {0x437B, 0x01}, |
| {0x4401, 0x3F}, |
| {0x4402, 0xFF}, |
| {0x4404, 0x13}, |
| {0x4405, 0x26}, |
| {0x4406, 0x07}, |
| {0x4408, 0x20}, |
| {0x4409, 0xE5}, |
| {0x440A, 0xFB}, |
| {0x440C, 0xF6}, |
| {0x440D, 0xEA}, |
| {0x440E, 0x20}, |
| {0x4410, 0x00}, |
| {0x4411, 0x00}, |
| {0x4412, 0x3F}, |
| {0x4413, 0xFF}, |
| {0x4414, 0x1F}, |
| {0x4415, 0xFF}, |
| {0x4416, 0x20}, |
| {0x4417, 0x00}, |
| {0x4418, 0x1F}, |
| {0x4419, 0xFF}, |
| {0x441A, 0x20}, |
| {0x441B, 0x00}, |
| {0x441D, 0x40}, |
| {0x441E, 0x1E}, |
| {0x441F, 0x38}, |
| {0x4420, 0x01}, |
| {0x4444, 0x00}, |
| {0x4445, 0x00}, |
| {0x4446, 0x1D}, |
| {0x4447, 0xF9}, |
| {0x4452, 0x00}, |
| {0x4453, 0xA0}, |
| {0x4454, 0x08}, |
| {0x4455, 0x00}, |
| {0x4456, 0x0F}, |
| {0x4457, 0xFF}, |
| {0x4458, 0x18}, |
| {0x4459, 0x18}, |
| {0x445A, 0x3F}, |
| {0x445B, 0x3A}, |
| {0x445C, 0x00}, |
| {0x445D, 0x28}, |
| {0x445E, 0x01}, |
| {0x445F, 0x90}, |
| {0x4460, 0x00}, |
| {0x4461, 0x60}, |
| {0x4462, 0x00}, |
| {0x4463, 0x00}, |
| {0x4464, 0x00}, |
| {0x4465, 0x00}, |
| {0x446C, 0x01}, |
| {0x446D, 0x00}, |
| {0x446E, 0x00}, |
| |
| /* LSC setting */ |
| {0x452A, 0x02}, |
| |
| /* White balance */ |
| {0x0712, 0x01}, |
| {0x0713, 0x00}, |
| {0x0714, 0x01}, |
| {0x0715, 0x00}, |
| {0x0716, 0x01}, |
| {0x0717, 0x00}, |
| {0x0718, 0x01}, |
| {0x0719, 0x00}, |
| |
| /* Shading */ |
| {0x4500, 0x1F}, |
| |
| {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, |
| {IMX135_TABLE_END, 0x00} |
| }; |
| |
| enum { |
| IMX135_MODE_4208X3120, |
| IMX135_MODE_1920X1080, |
| IMX135_MODE_1280X720, |
| IMX135_MODE_2616X1472, |
| IMX135_MODE_3896X2192, |
| IMX135_MODE_QUALITY_HDR, |
| IMX135_MODE_QUALITY, |
| }; |
| |
| static struct imx135_reg *mode_table[] = { |
| [IMX135_MODE_4208X3120] = mode_4208x3120, |
| [IMX135_MODE_1920X1080] = mode_1920x1080, |
| [IMX135_MODE_1280X720] = mode_1280x720, |
| [IMX135_MODE_2616X1472] = mode_2616x1472, |
| [IMX135_MODE_3896X2192] = mode_3896x2192, |
| [IMX135_MODE_QUALITY_HDR] = mode_quality_hdr, |
| [IMX135_MODE_QUALITY] = mode_quality, |
| }; |
| |
| static struct imx135_reg flash_strobe_mod[] = { |
| {0x0800, 0x01}, /* flash strobe output enble on ERS mode */ |
| {0x0801, 0x01}, /* reference dividor fron EXT CLK */ |
| {0x0804, 0x04}, /* shutter sync mode */ |
| {0x0806, 0x00}, /* ref point hi */ |
| {0x0807, 0x00}, /* ref point lo */ |
| {0x0808, 0x00}, /* latency hi from ref point */ |
| {0x0809, 0x00}, /* latency lo from ref point */ |
| {0x080A, 0x09}, /* high period of XHS for ERS hi */ |
| {0x080B, 0x60}, /* high period of XHS for ERS lo */ |
| {0x080C, 0x00}, /* low period of XHS for ERS hi */ |
| {0x080D, 0x00}, /* low period of XHS for ERS lo */ |
| {0x3100, 0x01}, /* XHS output control, 1 - FSTROBE enabled */ |
| {0x3104, 0x00}, /* XHS driving capability, 0 - 2mA */ |
| {0x3108, 0x00}, /* for 'sync to XVS' mode */ |
| {0x3109, 0x00}, /* AE bracketing mode, 0 - normal */ |
| {0x080E, 0x01}, /* num of ERS flash pulse */ |
| {IMX135_TABLE_END, 0x00} |
| }; |
| |
| static inline void |
| msleep_range(unsigned int delay_base) |
| { |
| usleep_range(delay_base*1000, delay_base*1000+500); |
| } |
| |
| static inline void |
| imx135_get_frame_length_regs(struct imx135_reg *regs, u32 frame_length) |
| { |
| regs->addr = IMX135_FRAME_LENGTH_ADDR_MSB; |
| regs->val = (frame_length >> 8) & 0xff; |
| (regs + 1)->addr = IMX135_FRAME_LENGTH_ADDR_LSB; |
| (regs + 1)->val = (frame_length) & 0xff; |
| } |
| |
| static inline void |
| imx135_get_coarse_time_regs(struct imx135_reg *regs, u32 coarse_time) |
| { |
| regs->addr = IMX135_COARSE_TIME_ADDR_MSB; |
| regs->val = (coarse_time >> 8) & 0xff; |
| (regs + 1)->addr = IMX135_COARSE_TIME_ADDR_LSB; |
| (regs + 1)->val = (coarse_time) & 0xff; |
| } |
| |
| static inline void |
| imx135_get_coarse_time_short_regs(struct imx135_reg *regs, u32 coarse_time) |
| { |
| regs->addr = IMX135_COARSE_TIME_SHORT_ADDR_MSB; |
| regs->val = (coarse_time >> 8) & 0xff; |
| (regs + 1)->addr = IMX135_COARSE_TIME_SHORT_ADDR_LSB; |
| (regs + 1)->val = (coarse_time) & 0xff; |
| } |
| |
| static inline void |
| imx135_get_gain_reg(struct imx135_reg *regs, u16 gain) |
| { |
| regs->addr = IMX135_GAIN_ADDR; |
| regs->val = gain; |
| } |
| |
| static inline void |
| imx135_get_gain_short_reg(struct imx135_reg *regs, u16 gain) |
| { |
| regs->addr = IMX135_GAIN_SHORT_ADDR; |
| regs->val = gain; |
| } |
| |
| static int |
| imx135_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; |
| |
| /* high byte goes out first */ |
| 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 |
| imx135_write_reg(struct i2c_client *client, u16 addr, u8 val) |
| { |
| int err; |
| struct i2c_msg msg; |
| unsigned char data[3]; |
| |
| if (!client->adapter) |
| return -ENODEV; |
| |
| data[0] = (u8) (addr >> 8); |
| data[1] = (u8) (addr & 0xff); |
| data[2] = (u8) (val & 0xff); |
| |
| msg.addr = client->addr; |
| msg.flags = 0; |
| msg.len = 3; |
| msg.buf = data; |
| |
| err = i2c_transfer(client->adapter, &msg, 1); |
| if (err == 1) |
| return 0; |
| |
| pr_err("%s:i2c write failed, %x = %x\n", |
| __func__, addr, val); |
| |
| return err; |
| } |
| |
| static int |
| imx135_write_table(struct i2c_client *client, |
| const struct imx135_reg table[], |
| const struct imx135_reg override_list[], |
| int num_override_regs) |
| { |
| int err; |
| const struct imx135_reg *next; |
| int i; |
| u16 val; |
| |
| for (next = table; next->addr != IMX135_TABLE_END; next++) { |
| if (next->addr == IMX135_TABLE_WAIT_MS) { |
| msleep_range(next->val); |
| continue; |
| } |
| |
| val = next->val; |
| |
| /* When an override list is passed in, replace the reg */ |
| /* value to write if the reg is in the list */ |
| if (override_list) { |
| for (i = 0; i < num_override_regs; i++) { |
| if (next->addr == override_list[i].addr) { |
| val = override_list[i].val; |
| break; |
| } |
| } |
| } |
| |
| err = imx135_write_reg(client, next->addr, val); |
| if (err) { |
| pr_err("%s:imx135_write_table:%d", __func__, err); |
| return err; |
| } |
| } |
| return 0; |
| } |
| |
| static int imx135_set_flash_output(struct imx135_info *info) |
| { |
| struct imx135_flash_control *fctl; |
| |
| if (!info->pdata) |
| return 0; |
| |
| fctl = &info->pdata->flash_cap; |
| dev_dbg(&info->i2c_client->dev, "%s: %x\n", __func__, fctl->enable); |
| dev_dbg(&info->i2c_client->dev, "edg: %x, st: %x, rpt: %x, dly: %x\n", |
| fctl->edge_trig_en, fctl->start_edge, |
| fctl->repeat, fctl->delay_frm); |
| return imx135_write_table(info->i2c_client, flash_strobe_mod, NULL, 0); |
| } |
| |
| static int imx135_get_flash_cap(struct imx135_info *info) |
| { |
| struct imx135_flash_control *fctl; |
| |
| dev_dbg(&info->i2c_client->dev, "%s: %p\n", __func__, info->pdata); |
| if (info->pdata) { |
| fctl = &info->pdata->flash_cap; |
| dev_dbg(&info->i2c_client->dev, |
| "edg: %x, st: %x, rpt: %x, dl: %x\n", |
| fctl->edge_trig_en, |
| fctl->start_edge, |
| fctl->repeat, |
| fctl->delay_frm); |
| |
| if (fctl->enable) |
| return 0; |
| } |
| return -ENODEV; |
| } |
| |
| static inline int imx135_set_flash_control( |
| struct imx135_info *info, struct imx135_flash_control *fc) |
| { |
| dev_dbg(&info->i2c_client->dev, "%s\n", __func__); |
| return imx135_write_reg(info->i2c_client, 0x0802, 0x01); |
| } |
| |
| static int |
| imx135_set_mode(struct imx135_info *info, struct imx135_mode *mode) |
| { |
| int sensor_mode; |
| u8 quality_hdr; |
| int err; |
| struct imx135_reg reg_list[8]; |
| |
| pr_info("%s: xres %u yres %u framelength %u coarsetime %u gain %u, hdr %d\n", |
| __func__, mode->xres, mode->yres, mode->frame_length, |
| mode->coarse_time, mode->gain, mode->hdr_en); |
| |
| if (mode->xres == 4208 && mode->yres == 3120) { |
| sensor_mode = IMX135_MODE_4208X3120; |
| quality_hdr = 1; |
| } else if (mode->xres == 1920 && mode->yres == 1080) { |
| sensor_mode = IMX135_MODE_1920X1080; |
| quality_hdr = 0; |
| } else if (mode->xres == 1280 && mode->yres == 720) { |
| sensor_mode = IMX135_MODE_1280X720; |
| quality_hdr = 0; |
| } else if (mode->xres == 2616 && mode->yres == 1472) { |
| sensor_mode = IMX135_MODE_2616X1472; |
| quality_hdr = 1; |
| } else if (mode->xres == 3896 && mode->yres == 2192) { |
| sensor_mode = IMX135_MODE_3896X2192; |
| quality_hdr = 1; |
| } else { |
| pr_err("%s: invalid resolution supplied to set mode %d %d\n", |
| __func__, mode->xres, mode->yres); |
| return -EINVAL; |
| } |
| |
| /* get a list of override regs for the asking frame length, */ |
| /* coarse integration time, and gain. */ |
| imx135_get_frame_length_regs(reg_list, mode->frame_length); |
| imx135_get_coarse_time_regs(reg_list + 2, mode->coarse_time); |
| imx135_get_gain_reg(reg_list + 4, mode->gain); |
| /* if HDR is enabled */ |
| if (mode->hdr_en == 1) { |
| imx135_get_gain_short_reg(reg_list + 5, mode->gain); |
| imx135_get_coarse_time_short_regs( |
| reg_list + 6, mode->coarse_time_short); |
| } |
| |
| err = imx135_write_table(info->i2c_client, |
| mode_table[sensor_mode], |
| reg_list, mode->hdr_en ? 8 : 5); |
| if (err) |
| return err; |
| if (quality_hdr) |
| err = imx135_write_table(info->i2c_client, |
| mode_table[IMX135_MODE_QUALITY_HDR], |
| reg_list, 0); |
| else |
| err = imx135_write_table(info->i2c_client, |
| mode_table[IMX135_MODE_QUALITY], |
| reg_list, 0); |
| if (err) |
| return err; |
| |
| imx135_set_flash_output(info); |
| |
| info->mode = sensor_mode; |
| pr_info("[IMX135]: stream on.\n"); |
| return 0; |
| } |
| |
| static int |
| imx135_get_status(struct imx135_info *info, u8 *dev_status) |
| { |
| *dev_status = 0; |
| return 0; |
| } |
| |
| static int |
| imx135_set_frame_length(struct imx135_info *info, u32 frame_length, |
| bool group_hold) |
| { |
| struct imx135_reg reg_list[2]; |
| int i = 0; |
| int ret; |
| |
| imx135_get_frame_length_regs(reg_list, frame_length); |
| |
| if (group_hold) { |
| ret = imx135_write_reg(info->i2c_client, 0x0104, 0x01); |
| if (ret) |
| return ret; |
| } |
| |
| for (i = 0; i < 2; i++) { |
| ret = imx135_write_reg(info->i2c_client, reg_list[i].addr, |
| reg_list[i].val); |
| if (ret) |
| return ret; |
| } |
| |
| if (group_hold) { |
| ret = imx135_write_reg(info->i2c_client, 0x0104, 0x0); |
| if (ret) |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| imx135_set_coarse_time(struct imx135_info *info, u32 coarse_time, |
| bool group_hold) |
| { |
| int ret; |
| |
| struct imx135_reg reg_list[2]; |
| int i = 0; |
| |
| imx135_get_coarse_time_regs(reg_list, coarse_time); |
| |
| if (group_hold) { |
| ret = imx135_write_reg(info->i2c_client, 0x104, 0x01); |
| if (ret) |
| return ret; |
| } |
| |
| for (i = 0; i < 2; i++) { |
| ret = imx135_write_reg(info->i2c_client, reg_list[i].addr, |
| reg_list[i].val); |
| if (ret) |
| return ret; |
| } |
| |
| if (group_hold) { |
| ret = imx135_write_reg(info->i2c_client, 0x104, 0x0); |
| if (ret) |
| return ret; |
| } |
| return 0; |
| } |
| |
| static int |
| imx135_set_gain(struct imx135_info *info, u16 gain, bool group_hold) |
| { |
| int ret; |
| struct imx135_reg reg_list; |
| |
| imx135_get_gain_reg(®_list, gain); |
| |
| if (group_hold) { |
| ret = imx135_write_reg(info->i2c_client, 0x104, 0x1); |
| if (ret) |
| return ret; |
| } |
| |
| ret = imx135_write_reg(info->i2c_client, reg_list.addr, reg_list.val); |
| /* writing second gain register for HDR */ |
| ret = imx135_write_reg(info->i2c_client, 0x233, reg_list.val); |
| if (ret) |
| return ret; |
| |
| if (group_hold) { |
| ret = imx135_write_reg(info->i2c_client, 0x104, 0x0); |
| if (ret) |
| return ret; |
| } |
| return 0; |
| } |
| |
| static int |
| imx135_set_hdr_coarse_time(struct imx135_info *info, struct imx135_hdr *values) |
| { |
| struct imx135_reg reg_list[2]; |
| struct imx135_reg reg_list_short[2]; |
| int ret, i = 0; |
| |
| /* get long and short coarse time registers */ |
| imx135_get_coarse_time_regs(reg_list, values->coarse_time_long); |
| imx135_get_coarse_time_short_regs(reg_list_short, |
| values->coarse_time_short); |
| /* set to direct mode */ |
| ret = imx135_write_reg(info->i2c_client, 0x238, 0x1); |
| if (ret) |
| return ret; |
| /* set group hold */ |
| ret = imx135_write_reg(info->i2c_client, 0x104, 0x1); |
| if (ret) |
| return ret; |
| /* writing long exposure */ |
| for (i = 0; i < 2; i++) { |
| ret = imx135_write_reg(info->i2c_client, reg_list[i].addr, |
| reg_list[i].val); |
| if (ret) |
| return ret; |
| } |
| /* writing short exposure */ |
| for (i = 0; i < 2; i++) { |
| ret = imx135_write_reg(info->i2c_client, reg_list_short[i].addr, |
| reg_list_short[i].val); |
| if (ret) |
| return ret; |
| } |
| ret = imx135_write_reg(info->i2c_client, 0x104, 0x0); |
| if (ret) |
| return ret; |
| |
| return 0; |
| } |
| |
| static int |
| imx135_set_group_hold(struct imx135_info *info, struct imx135_ae *ae) |
| { |
| int ret; |
| int count = 0; |
| bool group_hold_enabled = false; |
| struct imx135_hdr values; |
| |
| values.coarse_time_long = ae->coarse_time; |
| values.coarse_time_short = ae->coarse_time_short; |
| |
| if (ae->gain_enable) |
| count++; |
| if (ae->coarse_time_enable) |
| count++; |
| if (ae->frame_length_enable) |
| count++; |
| if (count >= 2) |
| group_hold_enabled = true; |
| |
| if (group_hold_enabled) { |
| ret = imx135_write_reg(info->i2c_client, 0x104, 0x1); |
| if (ret) |
| return ret; |
| } |
| |
| if (ae->gain_enable) |
| imx135_set_gain(info, ae->gain, false); |
| if (ae->coarse_time_enable) |
| imx135_set_hdr_coarse_time(info, &values); |
| if (ae->frame_length_enable) |
| imx135_set_frame_length(info, ae->frame_length, false); |
| |
| if (group_hold_enabled) { |
| ret = imx135_write_reg(info->i2c_client, 0x104, 0x0); |
| if (ret) |
| return ret; |
| } |
| |
| return 0; |
| } |
| |
| static int imx135_get_sensor_id(struct imx135_info *info) |
| { |
| int ret = 0; |
| int i; |
| u8 bak = 0; |
| |
| pr_info("%s\n", __func__); |
| if (info->sensor_data.fuse_id_size) |
| return 0; |
| |
| /* Note 1: If the sensor does not have power at this point |
| Need to supply the power, e.g. by calling power on function */ |
| |
| ret |= imx135_write_reg(info->i2c_client, 0x3B02, 0x00); |
| ret |= imx135_write_reg(info->i2c_client, 0x3B00, 0x01); |
| for (i = 0; i < 9 ; i++) { |
| ret |= imx135_read_reg(info->i2c_client, 0x3B24 + i, &bak); |
| info->sensor_data.fuse_id[i] = bak; |
| } |
| |
| if (!ret) |
| info->sensor_data.fuse_id_size = i; |
| |
| /* Note 2: Need to clean up any action carried out in Note 1 */ |
| |
| return ret; |
| } |
| |
| static void imx135_mclk_disable(struct imx135_info *info) |
| { |
| dev_dbg(&info->i2c_client->dev, "%s: disable MCLK\n", __func__); |
| clk_disable_unprepare(info->mclk); |
| } |
| |
| static int imx135_mclk_enable(struct imx135_info *info) |
| { |
| int err; |
| unsigned long mclk_init_rate = 24000000; |
| |
| dev_dbg(&info->i2c_client->dev, "%s: enable MCLK with %lu Hz\n", |
| __func__, mclk_init_rate); |
| |
| err = clk_set_rate(info->mclk, mclk_init_rate); |
| if (!err) |
| err = clk_prepare_enable(info->mclk); |
| return err; |
| } |
| |
| static long |
| imx135_ioctl(struct file *file, |
| unsigned int cmd, unsigned long arg) |
| { |
| int err = 0; |
| struct imx135_info *info = file->private_data; |
| |
| switch (cmd) { |
| case IMX135_IOCTL_SET_POWER: |
| if (!info->pdata) |
| break; |
| if (arg && info->pdata->power_on) { |
| err = imx135_mclk_enable(info); |
| if (!err) |
| err = info->pdata->power_on(&info->power); |
| if (err < 0) |
| imx135_mclk_disable(info); |
| } |
| if (!arg && info->pdata->power_off) { |
| info->pdata->power_off(&info->power); |
| imx135_mclk_disable(info); |
| } |
| break; |
| case IMX135_IOCTL_SET_MODE: |
| { |
| struct imx135_mode mode; |
| if (copy_from_user(&mode, (const void __user *)arg, |
| sizeof(struct imx135_mode))) { |
| pr_err("%s:Failed to get mode from user.\n", __func__); |
| return -EFAULT; |
| } |
| return imx135_set_mode(info, &mode); |
| } |
| case IMX135_IOCTL_SET_FRAME_LENGTH: |
| return imx135_set_frame_length(info, (u32)arg, true); |
| case IMX135_IOCTL_SET_COARSE_TIME: |
| return imx135_set_coarse_time(info, (u32)arg, true); |
| case IMX135_IOCTL_SET_GAIN: |
| return imx135_set_gain(info, (u16)arg, true); |
| case IMX135_IOCTL_GET_STATUS: |
| { |
| u8 status; |
| |
| err = imx135_get_status(info, &status); |
| if (err) |
| return err; |
| if (copy_to_user((void __user *)arg, &status, 1)) { |
| pr_err("%s:Failed to copy status to user\n", __func__); |
| return -EFAULT; |
| } |
| return 0; |
| } |
| case IMX135_IOCTL_GET_SENSORDATA: |
| { |
| err = imx135_get_sensor_id(info); |
| |
| if (err) { |
| pr_err("%s:Failed to get fuse id info.\n", __func__); |
| return err; |
| } |
| if (copy_to_user((void __user *)arg, &info->sensor_data, |
| sizeof(struct imx135_sensordata))) { |
| pr_info("%s:Failed to copy fuse id to user space\n", |
| __func__); |
| return -EFAULT; |
| } |
| return 0; |
| } |
| case IMX135_IOCTL_SET_GROUP_HOLD: |
| { |
| struct imx135_ae ae; |
| if (copy_from_user(&ae, (const void __user *)arg, |
| sizeof(struct imx135_ae))) { |
| pr_info("%s:fail group hold\n", __func__); |
| return -EFAULT; |
| } |
| return imx135_set_group_hold(info, &ae); |
| } |
| case IMX135_IOCTL_SET_HDR_COARSE_TIME: |
| { |
| struct imx135_hdr values; |
| |
| dev_dbg(&info->i2c_client->dev, |
| "IMX135_IOCTL_SET_HDR_COARSE_TIME\n"); |
| if (copy_from_user(&values, |
| (const void __user *)arg, |
| sizeof(struct imx135_hdr))) { |
| err = -EFAULT; |
| break; |
| } |
| err = imx135_set_hdr_coarse_time(info, &values); |
| break; |
| } |
| case IMX135_IOCTL_SET_FLASH_MODE: |
| { |
| struct imx135_flash_control values; |
| |
| dev_dbg(&info->i2c_client->dev, |
| "IMX135_IOCTL_SET_FLASH_MODE\n"); |
| if (copy_from_user(&values, |
| (const void __user *)arg, |
| sizeof(struct imx135_flash_control))) { |
| err = -EFAULT; |
| break; |
| } |
| err = imx135_set_flash_control(info, &values); |
| break; |
| } |
| case IMX135_IOCTL_GET_FLASH_CAP: |
| err = imx135_get_flash_cap(info); |
| break; |
| default: |
| pr_err("%s:unknown cmd.\n", __func__); |
| err = -EINVAL; |
| } |
| |
| return err; |
| } |
| |
| static int imx135_debugfs_show(struct seq_file *s, void *unused) |
| { |
| struct imx135_info *dev = s->private; |
| |
| dev_dbg(&dev->i2c_client->dev, "%s: ++\n", __func__); |
| |
| mutex_lock(&dev->imx135_camera_lock); |
| mutex_unlock(&dev->imx135_camera_lock); |
| |
| return 0; |
| } |
| |
| static ssize_t imx135_debugfs_write( |
| struct file *file, |
| char const __user *buf, |
| size_t count, |
| loff_t *offset) |
| { |
| struct imx135_info *dev = |
| ((struct seq_file *)file->private_data)->private; |
| struct i2c_client *i2c_client = dev->i2c_client; |
| int ret = 0; |
| char buffer[MAX_BUFFER_SIZE]; |
| u32 address; |
| u32 data; |
| u8 readback; |
| |
| dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); |
| |
| if (copy_from_user(&buffer, buf, sizeof(buffer))) |
| goto debugfs_write_fail; |
| |
| if (sscanf(buf, "0x%x 0x%x", &address, &data) == 2) |
| goto set_attr; |
| if (sscanf(buf, "0X%x 0X%x", &address, &data) == 2) |
| goto set_attr; |
| if (sscanf(buf, "%d %d", &address, &data) == 2) |
| goto set_attr; |
| |
| if (sscanf(buf, "0x%x 0x%x", &address, &data) == 1) |
| goto read; |
| if (sscanf(buf, "0X%x 0X%x", &address, &data) == 1) |
| goto read; |
| if (sscanf(buf, "%d %d", &address, &data) == 1) |
| goto read; |
| |
| dev_err(&i2c_client->dev, "SYNTAX ERROR: %s\n", buf); |
| return -EFAULT; |
| |
| set_attr: |
| dev_info(&i2c_client->dev, |
| "new address = %x, data = %x\n", address, data); |
| ret |= imx135_write_reg(i2c_client, address, data); |
| read: |
| ret |= imx135_read_reg(i2c_client, address, &readback); |
| dev_dbg(&i2c_client->dev, |
| "wrote to address 0x%x with value 0x%x\n", |
| address, readback); |
| |
| if (ret) |
| goto debugfs_write_fail; |
| |
| return count; |
| |
| debugfs_write_fail: |
| dev_err(&i2c_client->dev, |
| "%s: test pattern write failed\n", __func__); |
| return -EFAULT; |
| } |
| |
| static int imx135_debugfs_open(struct inode *inode, struct file *file) |
| { |
| struct imx135_info *dev = inode->i_private; |
| struct i2c_client *i2c_client = dev->i2c_client; |
| |
| dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); |
| |
| return single_open(file, imx135_debugfs_show, inode->i_private); |
| } |
| |
| static const struct file_operations imx135_debugfs_fops = { |
| .open = imx135_debugfs_open, |
| .read = seq_read, |
| .write = imx135_debugfs_write, |
| .llseek = seq_lseek, |
| .release = single_release, |
| }; |
| |
| static void imx135_remove_debugfs(struct imx135_info *dev) |
| { |
| struct i2c_client *i2c_client = dev->i2c_client; |
| |
| dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); |
| |
| debugfs_remove_recursive(dev->debugdir); |
| dev->debugdir = NULL; |
| } |
| |
| static void imx135_create_debugfs(struct imx135_info *dev) |
| { |
| struct dentry *ret; |
| struct i2c_client *i2c_client = dev->i2c_client; |
| |
| dev_dbg(&i2c_client->dev, "%s\n", __func__); |
| |
| dev->debugdir = |
| debugfs_create_dir(dev->miscdev_info.this_device->kobj.name, |
| NULL); |
| if (!dev->debugdir) |
| goto remove_debugfs; |
| |
| ret = debugfs_create_file("d", |
| S_IWUSR | S_IRUGO, |
| dev->debugdir, dev, |
| &imx135_debugfs_fops); |
| if (!ret) |
| goto remove_debugfs; |
| |
| return; |
| remove_debugfs: |
| dev_err(&i2c_client->dev, "couldn't create debugfs\n"); |
| imx135_remove_debugfs(dev); |
| } |
| |
| static int imx135_get_extra_regulators(struct imx135_power_rail *pw) |
| { |
| if (!pw->ext_reg1) { |
| pw->ext_reg1 = regulator_get(NULL, "imx135_reg1"); |
| if (WARN_ON(IS_ERR(pw->ext_reg1))) { |
| pr_err("%s: can't get regulator imx135_reg1: %ld\n", |
| __func__, PTR_ERR(pw->ext_reg1)); |
| pw->ext_reg1 = NULL; |
| return -ENODEV; |
| } |
| } |
| |
| if (!pw->ext_reg2) { |
| pw->ext_reg2 = regulator_get(NULL, "imx135_reg2"); |
| if (WARN_ON(IS_ERR(pw->ext_reg2))) { |
| pr_err("%s: can't get regulator imx135_reg2: %ld\n", |
| __func__, PTR_ERR(pw->ext_reg2)); |
| pw->ext_reg2 = NULL; |
| return -ENODEV; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int imx135_power_on(struct imx135_power_rail *pw) |
| { |
| int err; |
| struct imx135_info *info = container_of(pw, struct imx135_info, power); |
| |
| if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd))) |
| return -EFAULT; |
| |
| if (info->pdata->ext_reg) { |
| if (imx135_get_extra_regulators(pw)) |
| goto imx135_poweron_fail; |
| |
| err = regulator_enable(pw->ext_reg1); |
| if (unlikely(err)) |
| goto imx135_ext_reg1_fail; |
| |
| err = regulator_enable(pw->ext_reg2); |
| if (unlikely(err)) |
| goto imx135_ext_reg2_fail; |
| |
| } |
| |
| gpio_set_value(info->pdata->reset_gpio, 0); |
| gpio_set_value(info->pdata->af_gpio, 1); |
| gpio_set_value(info->pdata->cam1_gpio, 0); |
| usleep_range(10, 20); |
| |
| err = regulator_enable(pw->avdd); |
| if (err) |
| goto imx135_avdd_fail; |
| |
| err = regulator_enable(pw->iovdd); |
| if (err) |
| goto imx135_iovdd_fail; |
| |
| usleep_range(1, 2); |
| gpio_set_value(info->pdata->reset_gpio, 1); |
| gpio_set_value(info->pdata->cam1_gpio, 1); |
| |
| usleep_range(300, 310); |
| |
| return 1; |
| |
| |
| imx135_iovdd_fail: |
| regulator_disable(pw->avdd); |
| |
| imx135_avdd_fail: |
| if (pw->ext_reg2) |
| regulator_disable(pw->ext_reg2); |
| |
| imx135_ext_reg2_fail: |
| if (pw->ext_reg1) |
| regulator_disable(pw->ext_reg1); |
| gpio_set_value(info->pdata->af_gpio, 0); |
| |
| imx135_ext_reg1_fail: |
| imx135_poweron_fail: |
| pr_err("%s failed.\n", __func__); |
| return -ENODEV; |
| } |
| |
| static int imx135_power_off(struct imx135_power_rail *pw) |
| { |
| struct imx135_info *info = container_of(pw, struct imx135_info, power); |
| |
| if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd))) |
| return -EFAULT; |
| |
| usleep_range(1, 2); |
| gpio_set_value(info->pdata->cam1_gpio, 0); |
| usleep_range(1, 2); |
| |
| regulator_disable(pw->iovdd); |
| regulator_disable(pw->avdd); |
| |
| if (info->pdata->ext_reg) { |
| regulator_disable(pw->ext_reg1); |
| regulator_disable(pw->ext_reg2); |
| } |
| |
| return 0; |
| } |
| |
| static int |
| imx135_open(struct inode *inode, struct file *file) |
| { |
| struct miscdevice *miscdev = file->private_data; |
| struct imx135_info *info; |
| |
| info = container_of(miscdev, struct imx135_info, miscdev_info); |
| /* check if the device is in use */ |
| if (atomic_xchg(&info->in_use, 1)) { |
| pr_info("%s:BUSY!\n", __func__); |
| return -EBUSY; |
| } |
| |
| file->private_data = info; |
| |
| return 0; |
| } |
| |
| static int |
| imx135_release(struct inode *inode, struct file *file) |
| { |
| struct imx135_info *info = file->private_data; |
| |
| file->private_data = NULL; |
| |
| /* warn if device is already released */ |
| WARN_ON(!atomic_xchg(&info->in_use, 0)); |
| return 0; |
| } |
| |
| static int imx135_power_put(struct imx135_power_rail *pw) |
| { |
| if (unlikely(!pw)) |
| return -EFAULT; |
| |
| if (likely(pw->avdd)) |
| regulator_put(pw->avdd); |
| |
| if (likely(pw->iovdd)) |
| regulator_put(pw->iovdd); |
| |
| if (likely(pw->dvdd)) |
| regulator_put(pw->dvdd); |
| |
| if (likely(pw->ext_reg1)) |
| regulator_put(pw->ext_reg1); |
| |
| if (likely(pw->ext_reg2)) |
| regulator_put(pw->ext_reg2); |
| |
| pw->avdd = NULL; |
| pw->iovdd = NULL; |
| pw->dvdd = NULL; |
| pw->ext_reg1 = NULL; |
| pw->ext_reg2 = NULL; |
| |
| return 0; |
| } |
| |
| static int imx135_regulator_get(struct imx135_info *info, |
| struct regulator **vreg, char vreg_name[]) |
| { |
| struct regulator *reg = NULL; |
| int err = 0; |
| |
| reg = regulator_get(&info->i2c_client->dev, vreg_name); |
| if (unlikely(IS_ERR_OR_NULL(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 imx135_power_get(struct imx135_info *info) |
| { |
| struct imx135_power_rail *pw = &info->power; |
| int err = 0; |
| |
| err |= imx135_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */ |
| err |= imx135_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */ |
| err |= imx135_regulator_get(info, &pw->iovdd, "vif"); /* IO 1.8v */ |
| |
| return err; |
| } |
| |
| static const struct file_operations imx135_fileops = { |
| .owner = THIS_MODULE, |
| .open = imx135_open, |
| .unlocked_ioctl = imx135_ioctl, |
| .release = imx135_release, |
| }; |
| |
| static struct miscdevice imx135_device = { |
| .minor = MISC_DYNAMIC_MINOR, |
| .name = "imx135", |
| .fops = &imx135_fileops, |
| }; |
| |
| static struct of_device_id imx135_of_match[] = { |
| { .compatible = "nvidia,imx135", }, |
| { }, |
| }; |
| |
| MODULE_DEVICE_TABLE(of, imx135_of_match); |
| |
| static struct imx135_platform_data *imx135_parse_dt(struct i2c_client *client) |
| { |
| struct device_node *np = client->dev.of_node; |
| struct imx135_platform_data *board_info_pdata; |
| const struct of_device_id *match; |
| |
| match = of_match_device(imx135_of_match, &client->dev); |
| if (!match) { |
| dev_err(&client->dev, "Failed to find matching dt id\n"); |
| return NULL; |
| } |
| |
| board_info_pdata = devm_kzalloc(&client->dev, sizeof(*board_info_pdata), |
| GFP_KERNEL); |
| if (!board_info_pdata) { |
| dev_err(&client->dev, "Failed to allocate pdata\n"); |
| return NULL; |
| } |
| |
| board_info_pdata->cam1_gpio = of_get_named_gpio(np, "cam1-gpios", 0); |
| board_info_pdata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); |
| board_info_pdata->af_gpio = of_get_named_gpio(np, "af-gpios", 0); |
| |
| board_info_pdata->ext_reg = of_property_read_bool(np, "nvidia,ext_reg"); |
| |
| board_info_pdata->power_on = imx135_power_on; |
| board_info_pdata->power_off = imx135_power_off; |
| |
| return board_info_pdata; |
| } |
| |
| static int |
| imx135_probe(struct i2c_client *client, |
| const struct i2c_device_id *id) |
| { |
| struct imx135_info *info; |
| int err; |
| const char *mclk_name; |
| |
| pr_info("[IMX135]: probing sensor.\n"); |
| |
| info = devm_kzalloc(&client->dev, |
| sizeof(struct imx135_info), GFP_KERNEL); |
| if (!info) { |
| pr_err("%s:Unable to allocate memory!\n", __func__); |
| return -ENOMEM; |
| } |
| |
| if (client->dev.of_node) |
| info->pdata = imx135_parse_dt(client); |
| else |
| info->pdata = client->dev.platform_data; |
| |
| if (!info->pdata) { |
| pr_err("[IMX135]:%s:Unable to get platform data\n", __func__); |
| return -EFAULT; |
| } |
| |
| info->i2c_client = client; |
| atomic_set(&info->in_use, 0); |
| info->mode = -1; |
| |
| mclk_name = info->pdata->mclk_name ? |
| info->pdata->mclk_name : "default_mclk"; |
| info->mclk = devm_clk_get(&client->dev, mclk_name); |
| if (IS_ERR(info->mclk)) { |
| dev_err(&client->dev, "%s: unable to get clock %s\n", |
| __func__, mclk_name); |
| return PTR_ERR(info->mclk); |
| } |
| |
| imx135_power_get(info); |
| |
| memcpy(&info->miscdev_info, |
| &imx135_device, |
| sizeof(struct miscdevice)); |
| |
| err = misc_register(&info->miscdev_info); |
| if (err) { |
| pr_err("%s:Unable to register misc device!\n", __func__); |
| goto imx135_probe_fail; |
| } |
| |
| i2c_set_clientdata(client, info); |
| /* create debugfs interface */ |
| imx135_create_debugfs(info); |
| return 0; |
| |
| imx135_probe_fail: |
| imx135_power_put(&info->power); |
| |
| return err; |
| } |
| |
| static int |
| imx135_remove(struct i2c_client *client) |
| { |
| struct imx135_info *info; |
| info = i2c_get_clientdata(client); |
| misc_deregister(&imx135_device); |
| |
| imx135_power_put(&info->power); |
| |
| imx135_remove_debugfs(info); |
| return 0; |
| } |
| |
| static const struct i2c_device_id imx135_id[] = { |
| { "imx135", 0 }, |
| { } |
| }; |
| |
| MODULE_DEVICE_TABLE(i2c, imx135_id); |
| |
| static struct i2c_driver imx135_i2c_driver = { |
| .driver = { |
| .name = "imx135", |
| .owner = THIS_MODULE, |
| }, |
| .probe = imx135_probe, |
| .remove = imx135_remove, |
| .id_table = imx135_id, |
| }; |
| |
| static int __init imx135_init(void) |
| { |
| pr_info("[IMX135] sensor driver loading\n"); |
| return i2c_add_driver(&imx135_i2c_driver); |
| } |
| |
| static void __exit imx135_exit(void) |
| { |
| i2c_del_driver(&imx135_i2c_driver); |
| } |
| |
| module_init(imx135_init); |
| module_exit(imx135_exit); |