在车机显示 系统中,AIM915X和AIM916X作为车机和显示屏之间的传输芯片,车机的LVDS视频信号传到显示屏;控制信号如I2C、GPIO可实现双向透传;
一、设备树
开发平台:IMX6D
1、设备节点
2、timing参数
二、分辨率
1、修改为屏幕适配的分辨率
路径:drivers/video/fbdev/core/modedb.c
2、修改相关启动参数
烧录后会显示相关信息
cat /proc/cmdline
3、查看修改后的设备信息
cat /sys/class/graphics/fb0/mode
三、AIM915X AIM916X芯片调试
1、原理图
AIM915X:
AIM916X:
2、IIC地址
915:
Linux 7位地址为0x0C
916:
Linux 7位地址为0x2C
3、PDB
4、上电时序
5、配置步骤
#第 1 步:初始化 915X Rx/Tx 相关寄存器
i2cset -f -y 2 0x0c 0x6A 0x01 sleep 0.01i2cset -f -y 2 0x0c 0x66 0x02 sleep 0.01i2cset -f -y 2 0x0c 0xAD 0x02 sleep 0.01i2cset -f -y 2 0x0c 0x06 0x59 sleep 0.01i2cset -f -y 2 0x0c 0x2F 0x05 sleep 0.01i2cset -f -y 2 0x0c 0x2A 0x30 sleep 0.01i2cset -f -y 2 0x0c 0x2C 0x01 sleep 0.01i2cset -f -y 2 0x0c 0x33 0x35 sleep 0.01i2cset -f -y 2 0x0c 0x32 0xA2 sleep 0.01i2cset -f -y 2 0x0c 0x34 0x00 sleep 0.01i2cset -f -y 2 0x0c 0xA3 0x50 sleep 0.01i2cset -f -y 2 0x0c 0x03 0x3A
#第 2 步:选择 915X/916X 工作模式,根据需要选择一种模式,进行配置。第 2 步配置完成后,延时 30ms,再配置第 3 步。
40bit 模式i2cset -f -y 2 0x2c 0x42 0x12 i2cset -f -y 2 0x0c 0x6c 0x12 sleep 0.3
# 第 3 步:915X 外设 I2C 地址映射
# 此处是映射触摸的地址,GT9XX(0x14),此处可以不要,后续文章会更新调试触摸的过程
i2cset -f -y 2 0x0c 0x07 0x28 i2cset -f -y 2 0x0c 0x08 0x28
#第 4 步:916X Rx/Tx 相关寄存器
i2cset -f -y 2 0x0c 0x20 0x03 i2cset -f -y 2 0x0c 0x48 0xFF i2cset -f -y 2 0x2c 0x67 0x37 i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x0c 0x5A 0xF0 i2cset -f -y 2 0x0c 0x28 0x04 i2cset -f -y 2 0x2c 0x49 0x3A i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x49 0x3E i2cset -f -y 2 0x2c 0x49 0x3F i2cset -f -y 2 0x2c 0x5A 0xF4 i2cset -f -y 2 0x2c 0x40 0xF8 i2cset -f -y 2 0x2c 0x28 0x00 i2cset -f -y 2 0x2c 0x40 0xF0 i2cset -f -y 2 0x2c 0x67 0x33
#第 5 步:配置 915X 的 GPIO[3:0]GPIO[5:8]至 916X 相应 GPIO 的透传(透传指的是915端控制远端916的GPIO状态)
GPIO2 用作 PWM 915 in 916 outi2cget -y 2 0x0c 0x0B# 916端本地使能背光i2cset -y 2 0x2C 0x1D 0x99
#第 6 步:配置 915X 端接收 916X 端输入的中断
i2cset -f -y 2 0x0C 0x7F 0x21
#第 7 步:915X 完成初始化
i2cset -f -y 2 0x0c 0x03 0x1A i2cset -f -y 2 0x0c 0x44 0x16 i2cset -f -y 2 0x0c 0x6F 0x80 i2cset -f -y 2 0x0c 0x72 0x02 i2cset -f -y 2 0x0c 0x72 0x03 i2cset -f -y 2 0x0c 0x6F 0x00 i2cset -f -y 2 0x0c 0x25 0x07 i2cset -f -y 2 0x0c 0x26 0x00 i2cset -f -y 2 0x0c 0x6A 0xC9 i2cset -f -y 2 0x0c 0x72 0x02 i2cset -f -y 2 0x0c 0x72 0x03 i2cset -f -y 2 0x0c 0x73 0x02 i2cset -f -y 2 0x0c 0x73 0x03 i2cset -f -y 2 0x0c 0x26 0x04 i2cset -f -y 2 0x0c 0x6a 0x01 i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x23 0x37 i2cset -f -y 2 0x0c 0x25 0x0F i2cset -f -y 2 0x0c 0x26 0x00 i2cset -f -y 2 0x0c 0x6F 0x80 i2cset -f -y 2 0x0c 0x71 0xBF i2cset -f -y 2 0x0c 0x72 0xBE i2cset -f -y 2 0x0c 0x71 0xFF i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x72 0xFE i2cset -f -y 2 0x0c 0x72 0xFF i2cset -f -y 2 0x0c 0x26 0x04 i2cset -f -y 2 0x0c 0x6a 0x09 i2cset -f -y 2 0x0c 0x6f 0x00 i2cset -f -y 2 0x0c 0x6a 0x01 i2cset -f -y 2 0x0c 0x23 0x33
#第八步:驱动编写
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/unistd.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/semaphore.h>
#include <linux/kthread.h>
#include <linux/notifier.h>
#include <linux/fb.h>
#include <linux/reboot.h>#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include "aim915916.h"#define DYNAMIC_DETECT_AIM955956 1static struct i2c_client *aim955_client = NULL;
static struct i2c_client *aim956_client = NULL;
#ifdef DYNAMIC_DETECT_AIM955956
struct task_struct *glink_detect_kt = NULL;
static int link_detect_kernel_thread(void *data);
static void link_detect_kernel_thread_cleanup_module(void);
#endif
static int aim955_init_status = -1;
static int aim956_init_status = -1;
static int reconfig_aim955956_status = -1;int reset_915(void)
{int ret = 0;unsigned char value = 0;unsigned char addr = 0;addr = 0x01;value = 0x01;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_RESET\n");return ret;}msleep(100);
}int remote_mode(void)
{int ret = 0;unsigned char value = 0;unsigned char addr = 0;addr = 0x0a;value = 0x05;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM956 error: 0x%x 0x%x\n", addr, value);return ret;}addr = 0x1c;value = 0x03;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM956 error: 0x%x 0x%x\n", addr, value);return ret;}}int reset_mode(int mode)
{int ret = 0;unsigned char value = 0;unsigned char addr = 0;if (aim956_client == NULL) {printk("aim956_client is NULL\n");return -EINVAL;}
//gpio1 RESETif (mode == resetin) {addr = 0x1D;value = 0x53;printk("reset set input\n");} else if (mode == resetoutlow) {addr = 0x1D;value = 0x01;printk("reset set ouput\n");}else if (mode == resetouthigh) {addr = 0x1D;value = 0x09;printk("reset set ouput\n");} else if(mode == intin){//INT input gpio0addr = 0x1c;value = 0x03;printk("INT set input\n");}else if(mode == intouthigh){// INT outputaddr = 0x1c;value = 0x09;printk("INT set input1\n");}else if(mode == intoutlow){// INT outputaddr = 0x1c;value = 0x01;printk("INT set input1\n");}ret = i2c_smbus_write_byte_data(aim956_client, addr, value);if (ret < 0) {printk("I2C_AIM956 error: addr=0x%x value=0x%x ret=%d\n", addr, value, ret);return ret;}return 0;
}EXPORT_SYMBOL(reset_mode);
EXPORT_SYMBOL(remote_mode);//#define TIME_DELAY 100int configure_aim956955(void)
{int ret = 0;unsigned char value = 0;unsigned char addr = 0;//第二步 40bitaddr = 0x42;value = 0x12;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM956 error: 0x%x 0x%x\n", addr, value);return ret;}addr = 0x6c;value = 0x12;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM956 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(30);//#第 3 步:955 外设 I2C 地址映射//TP i2caddr,0x14 * 2 = 0x28addr = 0x07;value = 0x28;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}addr = 0x08;value = 0x28;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}//lightaddr = 0x51;value = 0x52;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}addr = 0x58;value = 0x52;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}//#ifdef TIME_DELAYmsleep(TIME_DELAY);#endif//printk("step3\n");//第四步 916X Rx/Tx 相关寄存器addr = 0x20;value = 0x03;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x48;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x67;value = 0x37;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x49;value = 0x3F;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x5A;value = 0xF0;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x28;value = 0x04;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x49;value = 0x3A;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x49;value = 0x3E;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x49;value = 0x3F;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x5A;value = 0xF4;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x40;value = 0xF8;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x28;value = 0x00;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x40;value = 0xF0;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x67;value = 0x33;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endif//printk ("step 4\n");//第 5 步:配置 915 的 GPIO[3:0]、D_GPIO[3:0]、GPIO[8:5]_reg 至 956 相应 GPIO 的透传//GPIO2 PWM addr = 0x0B;value = 0x30;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}addr = 0x1D;value = 0x50;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}//printk ("step 5\n");//#第 6 步:配置 915 端接收 916 端输入的中断addr = 0x7F;value = 0x21;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endif//#第 7 步:955 完成初始化addr = 0x03;value = 0x1A;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x44;value = 0x16;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM956 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x6F;value = 0x80;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0x02;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0x03;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x6F;value = 0x00;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x25;value = 0x07;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x26;value = 0x00;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x6A;value = 0xC9;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0x02;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0x03;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0x02;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0x03;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x26;value = 0x04;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x6A;value = 0x01;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x23;value = 0x37;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x25;value = 0x0F;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x26;value = 0x00;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x6F;value = 0x80;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x71;value = 0xBF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xBF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x71;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endif//addr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x72;value = 0xFE;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);
#endifaddr = 0x72;value = 0xFF;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endif//addr = 0x26;value = 0x04;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x6A;value = 0x09;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x6F;value = 0x00;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x6A;value = 0x01;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endifaddr = 0x23;value = 0x33;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}#ifdef TIME_DELAYmsleep(TIME_DELAY);#endif//iic直通模式
/* addr = 0x03;value = 0x08;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}//addr = 0x0d;//value = 0x9e;//if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){// printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);// return ret;// }
//add 916X addr = 0x03;value = 0x09;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}addr = 0x04;value = 0x80;if((ret = i2c_smbus_write_byte_data(aim956_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}
*/printk("AIM955 AIM956 single lvds 20221018 Setup success.\n");return ret;
}int configure_aim955(void)
{int ret = 0;unsigned char value = 0;unsigned char addr = 0;reset_915();//初始化失败,resetmsleep(100);#if 0//第 0 步骤: 初始化 955 之前,先重启设备addr = 0x01;value = 0x02;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 reset before kernel driver init: 0x%x 0x%x, ret: %d\n", addr, value, ret);//return ret;}//955 重启过后, 延迟100ms.msleep(100);
#endif//第 1 步:初始化 915 Rx/Tx 相关寄存器addr = 0x6A;value = 0x01;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x66;value = 0x02;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);/*DES ID*/addr = 0xAD;value = 0x02;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x06;value = 0x59;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x2F;value = 0x05;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x2A;value = 0x30;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x2C;value = 0x01;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x33;value = 0x35;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x32;value = 0xA2;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x34;value = 0x00;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0xA3;value = 0x50;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);addr = 0x03;value = 0x3A;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 error: 0x%x 0x%x\n", addr, value);return ret;}msleep(1);return ret;
}static unsigned long is_cabled = 0;static ssize_t aim955956_is_link_show(struct device *dev,struct device_attribute *attr, char *buf)
{printk("aim955956_is_link_show ...\n");u8 detect_reg = 0x07;//u8 detect_reg_data = 0;int data = i2c_smbus_read_byte_data(aim956_client, detect_reg);printk("aim - 955 - 956 is_cabled: 0x%x, invert: 0x%x\n", data, (data & 0xff));if((data & 0xff) == 0x19){is_cabled = 1;}else{is_cabled = 0;}return sprintf(buf, "%d\n", is_cabled);
}static ssize_t aim955_probe_status_show(struct device *dev,struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", aim955_init_status);
}static ssize_t aim956_probe_status_show(struct device *dev,struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", aim956_init_status);
}#ifdef DYNAMIC_DETECT_AIM955956
static ssize_t aim956_reconfig_num_show(struct device *dev,struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", reconfig_aim955956_status);
}
#endifstatic DEVICE_ATTR(is_linked, 0664, aim955956_is_link_show,NULL);
static DEVICE_ATTR(955_probe, 0664, aim955_probe_status_show,NULL);
static DEVICE_ATTR(956_probe, 0664, aim956_probe_status_show,NULL);#ifdef DYNAMIC_DETECT_AIM955956
static DEVICE_ATTR(aim955956_reconfig_num, 0664, aim956_reconfig_num_show,NULL);
#endifstatic struct attribute *aim955956_attributes[] = {&dev_attr_is_linked.attr,&dev_attr_955_probe.attr,&dev_attr_956_probe.attr,
#ifdef DYNAMIC_DETECT_AIM955956 &dev_attr_aim955956_reconfig_num.attr,
#endif NULL
};static const struct attribute_group aim955956_attr_group = {.attrs = aim955956_attributes,
};static int __init aim956_probe(struct i2c_client *client, const struct i2c_device_id *id)
{int ret = 0;aim956_client = client;printk("aim956_probe ... \n");ret = configure_aim956955();aim956_init_status = ret;printk("aim956_probe ... ..., ret = %d\n", ret);#ifdef DYNAMIC_DETECT_AIM955956glink_detect_kt = kthread_create(link_detect_kernel_thread, (void*)aim956_client , "glink_detect_kt");if(!IS_ERR(glink_detect_kt))wake_up_process(glink_detect_kt);else {printk("create glink_detect_kt watchdog thread failed!!\n");glink_detect_kt = 0;}
#endifreturn ret;
}static int aim956_remove(struct i2c_client *client)
{
#ifdef DYNAMIC_DETECT_AIM955956link_detect_kernel_thread_cleanup_module();
#endifreturn 0;
}static const struct i2c_device_id aim956_id[] = {{ "aim956", 0 },{ }
};static const struct of_device_id aim956_match_table[] = {{.compatible = "aimx916",},{ },};static struct i2c_driver aim956_driver = {.driver = {.name = "aim956",.owner = THIS_MODULE,.of_match_table = aim956_match_table,},.probe = aim956_probe,.remove = aim956_remove,.id_table = aim956_id,
};#ifdef DYNAMIC_DETECT_AIM955956int reconfigure_aim955956(void)
{int ret = 0;unsigned char value = 0;unsigned char addr = 0;
#if 1//第 0 步骤: 初始化 955 之前,先重启设备addr = 0x01;value = 0x01;if((ret = i2c_smbus_write_byte_data(aim955_client, addr, value)) < 0){printk("I2C_AIM955 reset before kernel driver init: 0x%x 0x%x, ret: %d\n", addr, value, ret);//return ret;}//955 重启过后, 延迟100ms.msleep(100);
#endifreconfig_aim955956_status++;ret = configure_aim955();msleep(10);if (ret < 0)return ret;elseret = configure_aim956955();return ret;
}bool isLinkDetected(struct i2c_client *client)
{u8 detect_reg = 0x67;int data = i2c_smbus_read_byte_data(aim956_client, detect_reg);//printk("isLinkDetected aim - 955 - 956 is_cabled: 0x%x, invert: 0x%x\n", data, (data & 0xff));if((data & 0xff) == 0x33){return true;}else{return false;}
}static void link_detect_kernel_thread_cleanup_module(void)
{ if(glink_detect_kt){ kthread_stop(glink_detect_kt); glink_detect_kt = NULL; }
} static int link_detect_kernel_thread(void *data)
{struct i2c_client *client = (struct i2c_client *)data;while(!kthread_should_stop()){if(isLinkDetected(client) == true) {// do nothing.} else {printk("----------------link_detect_kernel_thread call reconfigure_aim955956()-------------- \n");reconfig:if(reconfigure_aim955956() < 0){schedule_timeout_interruptible(msecs_to_jiffies(500));goto reconfig;}}schedule_timeout_interruptible(msecs_to_jiffies(1000));}}
#endifstatic int __init aim955_probe(struct i2c_client *client, const struct i2c_device_id *id)
{int ret = 0;aim955_client = client;printk("aim955_probe ... \n");ret = configure_aim955();aim955_init_status = ret;printk("aim955_probe ... ..., ret = %d\n", ret);sysfs_create_group(&aim955_client->dev.kobj,&aim955956_attr_group);return ret;
}static int aim955_remove(struct i2c_client *client)
{sysfs_remove_group(&aim955_client->dev.kobj,&aim955956_attr_group);return 0;
}static const struct i2c_device_id aim955_id[] = {{ "aim955", 0 },{ }
};static const struct of_device_id aim955_match_table[] = {{.compatible = "aimx915",},{ },
};static struct i2c_driver aim955_driver = {.driver = {.name = "aim955",.owner = THIS_MODULE,.of_match_table = aim955_match_table,},.probe = aim955_probe,.remove = aim955_remove,.id_table = aim955_id,};static int __init aim955956_init(void)
{int ret = 0;printk("aim955956_init\n");ret = i2c_add_driver(&aim955_driver);ret = i2c_add_driver(&aim956_driver);return ret;}static void __exit aim955956_exit(void)
{printk("aim955956_exit\n");i2c_del_driver(&aim955_driver);i2c_del_driver(&aim956_driver);
}MODULE_AUTHOR("xth");
MODULE_DESCRIPTION("aim955-956-xxx Driver");
MODULE_LICENSE("GPL");module_init(aim955956_init);
//subsys_initcall(aim955956_init);module_exit(aim955956_exit);
驱动写的比较简单,大家可自行完善
四、测试
问题1:
写入寄存器测试后,出现图像偏移的情况
原因: 屏配置了 SYNC 模式, RGB芯片输出 DE 模式
解决方案:拆掉R103电阻,使DE悬空后显示正常
问题2:驱动寄存器初始化会失败的情况
915有对应的复位寄存器,在每次初始化915X寄存器之前进行复位,重新写入
添加915复位代码:
I2C重试机制:
修改后反复测试20次未出现I2C初始化失败的情况
热插拔检测:
-
isLinkDetected
函数:通过I2C读取设备的特定寄存器(0x67
),检查返回的数据是否为0x33
。如果是,返回true
,表示检测到连接;否则返回false
。 -
link_detect_kernel_thread_cleanup_module
函数:如果全局线程glink_detect_kt
存在,则停止该线程并将其指针置为NULL
,用于清理工作。 -
link_detect_kernel_thread
函数:这是一个内核线程,循环检查链接状态。如果检测到链接,则什么都不做;如果未检测到链接,则调用reconfigure_aim955956
函数进行重新配置。