简介:面向联发科MTK6582平台安卓驱动开发者的IMX135摄像头驱动源码与数据手册整合包,覆盖传感器移植与调试所需的关键资料。包内共24个文件,以C/C++头文件与源文件为主(12个h、6个cpp、1个c),另含2份PDF手册(索尼官方IMX135规格书与打印预览版)和3个文本说明,压缩包仅2.43MB,轻量便于快速学习。已有273人学习下载,适合正在从事MTK平台Camera移植、图像质量调优或驱动学习的开发者。从内容看,驱动源码遵循V4L2框架,涵盖模块注册、I2C通信、传感器与PLL初始化、MIPI CSI-2接口及DMA数据通路;文本说明针对驱动移植、闪光灯移植和相机性能优化,配合PDF中的电气特性、像素格式、电源时序等参数,可帮助定位适配问题,是理解MTK Camera驱动架构与IMX135传感器特性的实用参考。
1. 从 imx135 datasheet 到 MTK6582 驱动:这个组合到底要解决什么问题
MTK6582 平台加 imx135 sensor,是 Android 4.4 时代千元机最典型的 camera 方案。imx135 是索尼的 1300 万像素 Exmor RS 背照式 CMOS,走 MIPI 接口,而 MTK6582 内置的 ISP 需要一套完整的 sensor 驱动源码才能把数据流从 sensor 拉到屏幕预览。标题里同时给了「驱动源码」和「datasheet」,说明你不只是要跑通一个摄像头,而是要从寄存器手册一路读到驱动代码的每个分支,最后让预览、拍照、录像三条链路都稳定工作。这篇文章适合三类人:需要在旧平台上移植 sensor 的 BSP 工程师、维护古董项目但还没摸清 imx135 细节的底层开发,以及想搞明白 MTK camera 架构里 sensor 层到底做了什么的学生。我会按 datasheet 精读、驱动结构拆解、联调排错的顺序,把这条路完整走一遍。
2. imx135 datasheet 精读:先抓住 4 个关键寄存器再碰代码
2.1 为什么 datasheet 比源码更先决定成败
很多新手拿到 imx135 驱动源码,第一反应是直接搜 preview 函数、找初始化序列,然后迫不及待地编进内核。这个顺序在 MTK6582 平台上大概率会让你多花两天排一个本来可以避免的错。
原因在于:MTK6582 的 camera 驱动架构里,sensor 驱动只是中间的一层,它依赖两个外部输入——I2C 地址和 chip id 寄存器定义来自 datasheet,MIPI lane 数和时钟频率来自硬件原理图与 sensor mode 表。如果这些参数和硬件不匹配,驱动在 probe 阶段就会直接失败,连 log 都不太容易看懂。
我一般的做法是:动代码之前在 datasheet 里先确认四件事——sensor 的 I2C 从机地址、chip id 寄存器地址与期望值、MIPI 接口的 lane 分配、以及 sensor 输出格式(RAW10 还是 RAW8)。其中 chip id 是最重要的。imx135 的 datasheet 里,chip id 寄存器通常在 0x0016/0x0017 两个字节上,期望值对应型号 ID。驱动源码里的 imx135_SensorInit 函数第一件事就是读这个寄存器,读不到或者值不对,后面的 init sequence 根本不会执行。
2.2 从 datasheet 抄下 I2C 地址和 chip id:驱动 probe 的第一道关卡
打开 imx135 的 datasheet(Sony 的 sensor 手册一般是几十页的 PDF,前面是电气特性,中间是寄存器描述),先找两个东西:I2C 从机地址表,以及 chip id 寄存器描述。
常见配置下 imx135 走 8-bit I2C 地址 0x20(7-bit 地址 0x10),但具体是主地址还是副地址,取决于 sensor 的 ADO 引脚电平。MTK6582 平台上,这个值写在 sensor list 里:
/* 在 kernel-3.10/arch/arm/mach-mt6582/camera/sensorlist.c 附近 */ static struct imgsensor_list_t sensor_list[] = { /* sensor 名字要对应 imx135mipiraw_Sensor.c */ { "imx135mipiraw", 0x20 }, // I2C 地址,来自 imx135 datasheet };参数说明:这里的 0x20 是 8-bit 写地址,驱动内部 i2c 读写函数会自动处理 7-bit/8-bit 转换,不用你在代码里再移位。I2C 地址如果和 datasheet 不一致,probe 读 chip id 时所有寄存器都会返回 0xFF,log 里会看到[imgsensor] imx135_sensor_id_read fail之类的报错。
chip id 的检查函数在驱动里长这样:
static kal_uint32 imx135_get_id(void) { kal_uint32 id = 0; /* 读 0x0016/0x0017 两个字节,拼成 16-bit id */ id = ((read_cmos_sensor(0x0016) << 8) | read_cmos_sensor(0x0017)); /* 期望值与 datasheet 中 imx135 的 chip id 一致 */ if (id == 0x0135) return ERROR_NONE; return ERROR_SENSOR_CONNECT_FAIL; }这段代码是调试时最常用的一个函数。如果你改完驱动发现 sensor 一直没有 probe 成功,第一步就是在这函数里加一条 printk 把实际读到的 id 打出来。如果实际 id 是 0xFF 或者 0x0135 都不对,那先别查驱动,回头量 I2C 波形、确认 sensor 供电和 MCLK 是否到位,顺序不能反。
2.3 imx135 的 mode 表:每一个分辨率都是一组寄存器组合
datasheet 里最值钱的部分其实是 mode 表。imx135 支持最大 4208x3120 的输出,也支持 1080p、720p 等裁剪模式,而每一种分辨率对应一组完全不同的寄存器配置——包括水平/垂直消隐、增益、曝光、输出尺寸。
在 MTK6582 的 imx135 驱动里,这些 mode 会被组织成imgsensor_mode_struct数组:
static struct imgsensor_mode_struct imsensor_mode_data[] = { /* IMGSENSOR_MODE_PREVIEW / CAPTURE / VIDEO 都需要 */ { .pclk = 420000000, /* 像素时钟,需要从 datasheet 的时序参数换算 */ .linelength = 2100, /* 一行包含消隐的总长度 */ .framelength = 2016, /* 一帧包含消隐的总行数 */ .startx = 0, .starty = 0, .grabwindow_width = 1280, .grabwindow_height = 960, .mipi_pixel_rate = 420000000, }, };参数说明:pclk是 sensor 输出的像素时钟,由 datasheet 推荐设置和主控 MCLK 决定;linelength和framelength直接决定帧率——帧率 = pclk / (linelength * framelength)。这三个参数如果和 datasheet 算出来的不一致,预览会花屏或者帧率不对。MTK6582 平台的常见坑是 pclk 设得过高导致 ISP 带宽不够,画面出现横纹,后面联调章节里会专门讲。
3. 驱动源码结构拆解:把 imx135 驱动从 probe 到 preview 串起来
3.1 一段最小可用的 imx135 sensor 驱动骨架
拿到 imx135 驱动源码后,先别急着编译,按文件功能把它分成三层:控制层(SensorInit / GetInfo / Preview 函数)、I2C 读写层(read_cmos_sensor / write_cmos_sensor)、配置层(camera_para 和 mode 表)。MTK6582 的 imx135 驱动一般叫imx135mipiraw_Sensor.c,放在kernel-3.10/drivers/misc/mediatek/imgsensor/src/下。整个文件的核心入口是sensor_init和sensor_control,上层通过 ioctl 调用下来。
最精简的驱动骨架长这样:
static struct imgsensor_ctrl_t imx135_ctrl = { .sensor_init = imx135_init, /* 上电后初始化寄存器序列 */ .sensor_control = imx135_control, /* 处理 preview/capture/etc 命令 */ .sensor_id = IMX135_SENSOR_ID, /* 内部用于匹配 sensor list */ }; static int imx135_control(enum IMGSENSOR_IOCTL_CMD cmd, void *arg) { switch (cmd) { case IMGSENSOR_CTL_INIT: imx135_init(); break; case IMGSENSOR_CTL_SET_READ_GAIN: /* 设置模拟增益,对应 datasheet 的 gain 寄存器组 */ imx135_set_gain(arg); break; } return 0; }这段代码精妙的地方在于:它把 sensor 和主控解耦了。上层 camera HAL 不会知道 imx135 的存在,只通过imgsensor_ctrl_t这个接口下发命令。你改仿真的 sensor 驱动时,只要保证这些回调都存在,上层代码一行不用动。逻辑说明:sensor_control是每个命令的入口,你收到什么命令就执行什么函数;参数说明:arg在 SET_READ_GAIN 时是一个整型指针,值代表增益倍数,这个倍数怎么换算成寄存器值,需要查 datasheet 的 gain 表格。
3.2 配置 camera_para:EEPROM、lane 数、时钟在哪个文件里改
MTK6582 平台的 sensor 驱动并不是一个孤立的文件。除了imx135mipiraw_Sensor.c,你还需要处理 camera_para 里的 EEPROM 配置、工程模式参数、以及 MTK 特有的camera_para.c文件。
camera_para 文件里保存的是每个分辨率下的微调参数,包括 AWB、AE 的初始收敛范围、以及 sensor 模组厂商写入的校准数据映射。实际开发中你会改动的文件一般有三个:
| 文件 | 作用 | 常见改动点 |
|---|---|---|
imx135mipiraw_Sensor.c | sensor 寄存器操作 | 初始化序列、增益映射、mode 表 |
camera_para.c | 预览/拍照的初始参数 | EEPROM 偏移地址、校准数据读取方式 |
kd_camera_hw.c或camera_clock.c | 上电时序和时钟配置 | MCLK 频率、DVDD/AVDD 上电顺序 |
这里有一个 MTK6582 特有的参数值得注意:sensor 的 MIPI lane 数量和 data rate。imx135 是 4-lane MIPI 接口,如果你模组实际只拉出 2 条 lane(省钱方案),那么驱动里的mipi_data_rate和imx135_SensorSetup里的 lane 配置必须同步改,否则画面只能出一半或者完全黑屏。改法是在 sensor 初始化函数里找到 lane 设置的地方:
/* imx135 SensorInit 尾部,设置 MIPI 相关寄存器 */ write_cmos_sensor(0x0114, 0x03); /* 0x03 = 4-lane, 0x01 = 2-lane */ write_cmos_sensor(0x0115, 0x02); /* 差分输出设置,由 datasheet 表给出 */参数说明:0x0114 是 MIPI lane number 配置寄存器,bit[1:0] 表示 lane 数减一,4-lane 写 3,2-lane 写 1。0x0115 是连续时钟模式设置,建议直接抄 datasheet 推荐值,不要自己发明。
3.3 三个最常改的小函数:preview、capture、night mode
源码里你会经常跟三个函数打交道。第一个是 preview 的实现,一般叫imx135_preview,它会把 sensor 切到预览分辨率、设置合理的曝光和增益初始值;第二个是 capture,imx135_capture,拍照瞬间要把 sensor 切成全尺寸输出;第三个是imx135_night或者低光模式,本质是同一套初始化序列加长曝光时间。
这三个函数的共同点是:开头都是一长串write_cmos_sensor(0xXXXX, 0xYY)。随便截一段预览初始化如下:
static void imx135_preview(kal_uint32 dumb) { /* 先把 sensor 切成 preview 模式 */ write_cmos_sensor(0x0100, 0x00); /* 关闭 sensor stream */ /* 设置 preview 尺寸相关寄存器 */ write_cmos_sensor(0x0340, 0x07); /* framelength 高位 */ write_cmos_sensor(0x0341, 0xE0); /* framelength 低位 */ write_cmos_sensor(0x0342, 0x08); /* linelength 高位 */ write_cmos_sensor(0x0343, 0x34); /* linelength 低位 */ /* 打开 sensor stream */ write_cmos_sensor(0x0100, 0x01); }这些寄存器的含义在 datasheet 的 register map 里都有明确描述——0x0340/0x0341 是帧长,0x0342/0x0343 是行长,0x0100 是 stream on/off。注意0x0100的时机:改任何尺寸相关参数前必须先把 stream 关掉,否则 sensor 内部状态机可能不同步。这条经验在 MTK6582 平台尤其重要,因为 ISP 侧的同步信号以 sensor 的 vsync 为准,你关闭 stream 的瞬间如果再等一帧 vsync,能避免大量的花屏问题。
4. mtk6582 平台联调避坑:5 个一定会遇到的现场与处理顺序
4.1 现象一:preview 黑屏但 log 无 error
现象:预览界面是黑的,但 dmesg 里没有任何 camera error,logcat 里只有Camera HAL open正常。原因有三个方向:sensor 没在出图、ISP 没收到数据、LCD 图层错误。
排查顺序是固定的。先看 dmesg 里有没有[imgsensor] imx135 preview ok,如果有,说明 sensor 侧已经出图,问题在 ISP 或者显示层;如果没有,说明 preview 函数没执行或者执行失败。这时在imx135_preview函数入口加一个 printk,确认确实被调到了。如果被调到但仍黑屏,用示波器量 sensor 的 MIPI 时钟脚,确认有没有波形——没有波形就去查上电时序,最常见的问题是 DVDD/AVDD 上电间隔太短,sensor 处于半复位状态,I2C 能通但 MIPI 不工作。
解决:把上电时序的延时从 1ms 拉到 10ms,MTK6582 的kd_camera_hw.c里camera_power_on函数每步之间加延迟。这种「I2C 通但 MIPI 不出」的现场是最折磨人的,因为驱动看起来一切正常。
4.2 现象二:启动 camera 直接 abort,logcat 里有 NULL sensor
现象:点击相机 icon 后 app 立刻退出,logcat 里能看到CameraService: getCameraInfo failed或者NULL sensor。
原因:sensor list 里没匹配到 imx135。不是驱动没编译进去,就是 sensor list 的名字和驱动文件里的名字不一致。MTK6582 平台的 sensor list 匹配是字符串精确比对,imx135mipiraw少一个字母都不行。
解决:打开sensorlist.c,确认 sensor 名字和imx135mipiraw_Sensor.c里struct imgsensor_ctrl_t的.sensor_name完全一致,注意大小写。这条坑的隐蔽之处在于:编译不会报错,只是运行时匹配失败,你可能会在 HAL 层浪费很多时间。
4.3 现象三:画面偏绿/偏紫,AWB 实效
现象:预览画面整体偏绿或偏紫,自动白平衡不收敛,手动调 AWB 也不对。原因可能是两个:一个是 sensor 的 color matrix 配得不对,另一个是 lens 的 shading 校准数据没正确加载。在 MTK6582 平台,偏紫通常是 ISP 的 color correction 矩阵在等 EEPROM 里的校准数据,而 imx135 模组如果没有 EEPROM 会在初始化后写一段默认参数,这段默认参数如果和 sensor 的实际色彩响应偏差大,就会出现偏紫。
解决:先确认 camera_para 里是否配置了 EEPROM。如果模组有 EEPROM 但驱动没读,修改 camera_para 里 EEPROM 的 slave addr 和偏移地址。如果模组没有 EEPROM,就得在 imx135 驱动里把一套可靠的 color matrix 作为默认值写死。这里值得用掉半天时间找一个同平台其他项目的 imx135 camera_para 作为参考,往往比对着色卡调更快。
4.4 现象四:录像卡顿,预览帧率只有 15fps
现象:录像时画面明显不流畅,用adb shell dumpsys media.camera看帧率只有 15fps 左右。
原因:pclk 和 sensor mode 不匹配。MTK6582 的最大 ISP 输入带宽有限,如果 imx135 的 mode 里 mipi_pixel_rate 设得太高,ISP 会丢掉部分帧;设得太低,帧率也起不来。另一个常见原因是 sensor 初始化时 framelength 没配够,导致 sensor 的实际帧率预算不够。
解决:按公式重新算一遍这一行。比如目标是 30fps,pclk 设为 420MHz,framelength = 420M / (30 * linelength)。如果算出来小于 datasheet 推荐的最小值,就说明 pclk 不够,得把 pclk 调大。假设 linelength 是 2100,那么 framelength = 420000000 / (30 * 2100) ≈ 6666。如果 imx135 的最大 framelength 只有 6000,那 pclk 至少要提到 378MHz 以上。这种换算是在联调现场最常做的计算,别偷懒。
4.5 现象五:EEPROM 读出来全 0xFF
现象:打开 camera 能看到画面但画质差,把 EEPROM dump 出来看全是 0xFF。
原因:EEPROM 挂在和 sensor 同一条 I2C 总线上,但地址可能不同。imx135 模组的 EEPROM 常见地址是 0xA0(8-bit),MTK6582 的 camera_para 里默认可能写的是 0x50(7-bit),两者差一位导致读写失败。
解决:把 EEPROM 的地址换算统一。camera_para 里填的是 8-bit 还是 7-bit,要看你的 I2C 读写函数怎么处理。MTK6582 的i2c_write_datas函数用 8-bit 地址,所以直接填 0xA0。如果换了一颗 EEPROM,先量的它的地址引脚电平,再对照 datasheet 确认地址,别默认所有模组都是同一颗 EEPROM。这个坑我在不同项目的 sensor 调试里遇到不止一次,每次都浪费了半天时间。
5. 收在验证与进阶:用 log 和一张图确认驱动「真交了差」
5.1 一路查到底:logcat + dmesg 双通道验证流程
驱动编译完,不要直接打开相机测功能。先把命令通道搭好,让你能看到 sensor 层发生了什么。我习惯一次性开三个终端:一个adb logcat | grep -i imx135,一个adb shell dmesg | grep -i imgsensor,一个adb shell cat /proc/driver/camera检查 sensor list 是否加载成功。
验证顺序也有讲究:先确认 probe 成功,再测 preview,最后测 capture。每个环节看不同的 log 关键词——probe 看sensor_id,preview 看preview ok,capture 看capture done。如果你在 logcat 里看到[imgsensor] imx135(0x0135) sensor_id read ok这样的信息,说明驱动和硬件之间的匹配已经打通了,后续的坑大概率在 ISP 配置而不是 sensor 本身。
5.2 进阶:用一张灰阶卡验证 sensor 输出没有暗角与坏点
功能通了不代表能交货。我最后总会做一件事:拍一张均匀光照下的灰阶卡照片,然后用 ImageJ 或者 Python 脚本检查四角亮度差和坏点数量。
# 抓一张 raw 图检查四角亮度 (需要先进入工程模式) adb shell "echo capture > /sys/devices/platform/camera/capture" adb pull /sdcard/DCIM/test_raw.raw . python3 check_shading.py test_raw.raw --width 4208 --height 3120脚本的逻辑很简单:把图像分成 3x3 九宫格,比较中心格和四角格的平均亮度。如果四角亮度比中心低 20% 以上,说明 lens shading 校准没生效;如果出现单个像素点亮度异常,说明 sensor 有坏点,需要做坏点校正或换模组。这个验证做完,imx135 的驱动工作才算真正收尾。
回头看我自己的调试经历,卡得最久的一次就是 4.1 的黑屏问题,查了两天最后发现是上电时序里 AVDD 和 DVDD 之间缺了 10ms 延时,而驱动代码本身一行没动。从那以后我给自己定了一个规矩:任何 sensor 驱动问题的排查顺序永远是硬件时序 → I2C 通信 → sensor 寄存器 → ISP 配置 → 上层 HAL,而不是反过来从 log 往下猜。这个顺序救了我不止一次,希望也能帮到你。
本文还有配套的精品资源,点击获取