当前位置: 首页 > article >正文

gm8775转换ic

uboot.c 部分内容:

#include <common.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <errno.h>
#include <i2c.h>
#include <video_bridge.h>
#include <linux/media-bus-format.h>

#include "rockchip_display.h"
#include "rockchip_bridge.h"
#include "rockchip_panel.h"

#include "gm8775_lvds.h"

GM8775C_dsi_reg_struct gm8775c_dsi_data_table[] =
{
    {0x00,0xAA},
    {0x48,0x02},
    {0xB6,0x20},
    {0x01,0x80},
    {0x02,0x38},
    {0x03,0x47},
    {0x04,0x58},
    {0x05,0x2C},
    {0x06,0x94},
    {0x07,0x00},
    {0x08,0x04},
    {0x09,0x05},
    {0x0A,0x24},
    {0x0B,0x82},
    {0x0C,0x13},
    {0x0D,0x01},
    {0x0E,0x80},
    {0x0F,0x20},
    {0x10,0x20},
    {0x11,0x03},
    {0x12,0x1B},
    {0x13,0x53},
    {0x14,0x01},
    {0x15,0x23},
    {0x16,0x40},
    {0x17,0x00},
    {0x18,0x01},
    {0x19,0x23},
    {0x1A,0x40},
    {0x1B,0x00},
    {0x1E,0x46},
    {0x51,0x30},
    {0x1F,0x10},
    {0x2A,0x01},
};

int gm8775c_write(struct udevice *dev, uint reg, const uint8_t *buff,int len)
{
	return  dm_i2c_write(dev, reg, buff, len);
}

#if DEBUG_GM8775_REG 
static int gm8775c_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
{
	return dm_i2c_read(dev, reg, buff, len);
}

int Debug_gm8775_reg(struct udevice *dev)
{
	int ret;
    int i,value;
    printf("u-boot read gm8775c reg value:\n");
    for(i=0; i< GM8775C_REG_NUM; i++)
    {
		ret = gm8775c_read(dev,gm8775c_dsi_data_table[i].reg_addr, (u8 *)&value, 1);
		if (ret != 0) {
			printf("GM877C i2c read error!!!\n");
        } else {
            printf("{0x%02x, 0x%02x},\n",gm8775c_dsi_data_table[i].reg_addr,value);
        }
    }
    return ret;
}

#endif

int GM877C_i2c_write(struct udevice *udev)
{
	int ret;
	int i;
	int data_lenth = sizeof(gm8775c_dsi_data_table)/sizeof(gm8775c_dsi_data_table[0]);
    for(i=0; i< data_lenth; i++) {
		ret = gm8775c_write(udev,gm8775c_dsi_data_table[i].reg_addr, (u8 *)&gm8775c_dsi_data_table[i].reg_value, 1);
		if (ret != 0)
			printf("GM877C i2c write error!!!\n");
    }

	return ret;
}

static int gm8775c_probe(struct udevice *dev)
{
	struct rockchip_bridge *bridge =
		(struct rockchip_bridge *)dev_get_driver_data(dev);
	int ret;

    printf(" test gm8775c_probe \n");

	ret = device_probe(dev->parent);
	if (ret)
		return ret;

	bridge->dev = dev;

	return 0;
}

static const struct udevice_id gm8775c_of_match[] = {
	{ .compatible = "gm8775c" },
	{},
};

U_BOOT_DRIVER(gm8775c) = {
	.name		= "gm8775c",
	.id		    = UCLASS_I2C_GENERIC,
	.of_match	= gm8775c_of_match,
	.probe      =  gm8775c_probe,
	.bind       = dm_scan_fdt_dev,
};


Kernel部分内容

#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#ifdef CONFIG_OF_GPIO
#include <linux/of_platform.h>
#endif
#include <linux/of_gpio.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/miscdevice.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <asm/param.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/gm8775c.h>

#define GM8775C_chip_ID  0x2c //IIC 地址,芯片第7脚高为0x5A,低为0x58
#define DRIVER_NAME     "gm8775c"

#define GM8775C_GET_DATA 0x10
#define GM8775C_SET_DATA 0x11
#define GPIO4_D2_D  154     //lcd backlight gpio

struct gm8775c_chip {
    struct mutex i2c_lock;
    struct i2c_client *client;
    const char *names;
};

struct GM8775C_R_DATA{
    uint16_t reg;
    uint16_t size;
    uint16_t buff[1664];
};

struct GM8775C_W_DATA{
    uint16_t reg;
    uint16_t size;
    uint16_t data;
};

struct gm8775c_chip *gchip = NULL;

///video format/
uint16_t 	hactive	= 	1920;//行有效像素点,12bit
uint16_t 	vactive	= 	1080;//列有效像素点,12bit
uint16_t	hfp		=	70;//行前肩,10bit
uint16_t	hsync	=	20;//行同步,10bit
uint16_t	hbp		=	70;//行后肩,10bit
uint8_t     vfp		=	3;//场前肩,8bit
uint8_t 	vsync	=	5;//场同步,8bit
uint8_t	    vbp		=	3;//场后肩,8bit
uint32_t   	lvds_clk  =	74.25;//lvds时钟频率,单位MHz
uint32_t   	ref_clk   =	26;//外部参考时钟频率,单位MHz
bool    	dual_lvds_output	=  1;//双通道LVDS使能,0:单通LVDS输出,1:双通道LVDS输出

///dual_lvds output sel
bool    	outA_8bit	     	=  1; //outA选择8bit  
#define     outA_6bit	     	~outA_8bit&0x01  //outA选择6bit
bool        outA_jeida			=  0;//outA选择jeida或VESA格式:0:VESA,1:JEIDA
#define 	outA_vesa   		~outA_jeida&0x01//outA选择vesa
bool    	outB_8bit	     	=  1;//outB选择8bit 
#define     outB_6bit	     	~outB_8bit&0x01//outB选择6bit
bool        outB_jeida			=  0;//outB选择jeida
#define 	outB_vesa   		~outB_jeida&0x01//outB选择vesa
bool    	outA_odd			=  1;//双通道时outA选择偶场输出
#define 	outA_even 	  		~outA_odd&0x01//双通道时outA选择奇场输出
#define 	outB_odd  	 		~outA_odd&0x01//双通道时outB选择偶场输出
#define 	outB_even 	  		outA_odd&0x01//双通道时outB选择奇场输出

///link p/n swap 0:PN不交换,1:PN交换/
bool		outA_pn_exchage_enable  = 1;  //outA的p/n交换使能,0:不使能,1:使能
bool		outA_line0	=	1;//outA_line0的p/n交换使能
bool		outA_line1	=	0;//outA_line1的p/n交换使能
bool		outA_line2	=	1;//outA_line2的p/n交换使能
bool		outA_line3	=	0;//outA_line3的p/n交换使能
bool		outA_clk  	=	0;//outA_clk的p/n交换使能

bool		outB_pn_exchage_enable  = 1;  //outB的p/n交换使能,0:不使能,1:使能
bool		outB_line0	=	0;//outB_line0的p/n交换使能
bool		outB_line1	=	1;//outB_line1的p/n交换使能
bool		outB_line2	=	0;//outB_line2的p/n交换使能
bool		outB_line3	=	0;//outB_line3的p/n交换使能
bool		outB_clk  	=	1;//outB_clk的p/n交换使能

///link lane swap/
bool		outA_lane_enable = 1;  //outA的通道选择使能,0:不使能,1:使能
uint8_t		outA_line0_link	=	3;	//outA_line0选择line0通道
uint8_t		outA_line1_link	= 2;	//outA_line1选择line1通道	
uint8_t		outA_line2_link	=	4;	//outA_line2选择line2通道
uint8_t		outA_line3_link	=	1;	//outA_line3选择line3通道
uint8_t		outA_clk_link  	=	0;	//outA_clk选择clk通道

bool		outB_lane_enable = 1;  //outB的通道选择使能
uint8_t		outB_line0_link	=	3;  //outB_line0选择line0通道
uint8_t		outB_line1_link	=	2;  //outB_line1选择line1通道	
uint8_t		outB_line2_link	=	4;  //outB_line2选择line2通道
uint8_t		outB_line3_link	=	1;  //outB_line3选择line3通道
uint8_t		outB_clk_link  	=	0;  //outB_clk选择clk通道

///mipi config/
uint8_t		mipi_line_choose  = 2;  //mipi通道数量选择
uint32_t   	mipi_clk  =	468;	//mipi时钟频率设置
bool		mipi_pn_exchage_enable = 1;  //mipi的p/n交换使能,0:不使能,1:使能
bool		mipi_line0	=	0;             //mipi_line0的p/n交换使能0:PN不交换,1:PN交换
bool		mipi_line1	=	1;             //mipi_line1的p/n交换使能0:PN不交换,1:PN交换
bool		mipi_line2	=	1;             //mipi_line2的p/n交换使能0:PN不交换,1:PN交换
bool		mipi_line3	=	0;             //mipi_line3的p/n交换使能0:PN不交换,1:PN交换
bool		mipi_clk_change	=	1;         //mipi_clk的p/n交换使能0:PN不交换,1:PN交换

///clock select/
bool		external_clk_enable	=	1;		//外部时钟使能
#define 	mipi_clk_enable 	  ~external_clk_enable&0x01	//mipi时钟使能,与外部时钟互斥

///system config/
bool		iic_enable	=	1;	//通信接口选择IIC
#define 	mipi_command	  ~iic_enable&0x01	//通信接口选择mipi接口

///bist test/
bool		bist_test_enable	=	0;	//bist_tset测试功能开关0:关闭自测模式,1:开启自测模式
uint8_t		bist_test_choose	=	4;	//测试功能选择:1、白色;2、边框线;3、棋盘格;4、彩条;5、红绿蓝循环

reg config
uint8_t 	reg_data[100];				//芯片寄存器数据存放数组,地址与数组一一对应
uint8_t 	reg_data_read_back[100];				//芯片寄存器回读数据存放数组,地址与数组一一对应
#define		chip_password   0xAA	//器件的password
#define		vs_pol   				0			//场同步极性
#define		hs_pol   				0			//行同步极性
#define		pll_refdiv      2			//pll参考频率分频系数
#define		min_hsw					0x20	//最小行同步,默认值32(0x20)
#define		min_hfp					0x20	//最小行前肩,默认值32(0x20)

int GM8775_REG_NUM = 34;

uint8_t reg_0C_function(void)  //地址0x0C寄存器值计算
{
	uint8_t	reg_data_buff=0;
	uint32_t pll_int=0;
	uint32_t lvds_clk_tmp = 0;
	uint32_t ref_clk_tmp = 0;
	uint32_t mipi_clk_tmp = 0;
	if(external_clk_enable) //采用外部时钟
	{
		lvds_clk_tmp = (uint32_t)lvds_clk*1000000*2*2;
		ref_clk_tmp = (uint32_t)(ref_clk*1000000)*7; 
		pll_int=lvds_clk_tmp/ref_clk_tmp; 
		pll_int+=2;//计算值+2
	}
	else//采用mipi时钟
	{
		lvds_clk_tmp = (uint32_t)lvds_clk*1000000*2*2;
		mipi_clk_tmp = (uint32_t)(mipi_clk*1000000)*7; 
		pll_int=lvds_clk_tmp/mipi_clk_tmp;
	}
	reg_data_buff = (uint8_t)pll_int;//pll_int的低8位
	return reg_data_buff;
}

uint8_t reg_0D_function(void) //地址0x0D寄存器值计算
{
	uint8_t	reg_data_buff=0;
	uint32_t pll_int=0;
	uint32_t lvds_clk_tmp = 0;
	uint32_t ref_clk_tmp = 0;
	uint32_t mipi_clk_tmp = 0;
	if(external_clk_enable)//采用外部时钟
	{
		lvds_clk_tmp = (uint32_t)lvds_clk*1000000*2*2;
		ref_clk_tmp = (uint32_t)(ref_clk*1000000)*7; 
		pll_int=lvds_clk_tmp/ref_clk_tmp; 
		pll_int+=2;//计算值+2
	}
	else//采用mipi时钟
	{
		lvds_clk_tmp = (uint32_t)lvds_clk*1000000*2*2;
		mipi_clk_tmp = (uint32_t)(mipi_clk*1000000)*7; 
		pll_int=lvds_clk_tmp/mipi_clk_tmp;
	}
	reg_data_buff = (((uint8_t)pll_int&0x300)>>8)|0x01;//pll_int的高2位,pll_post_div选择2
	return reg_data_buff;
}

uint8_t reg_11_function(void) //地址0x11寄存器值计算
{
	uint8_t	reg_data_buff=0;
	if(mipi_pn_exchage_enable)//mipi的pn交换使能
	{
		reg_data_buff=mipi_line3<<7;//mipi_line3的pn交换使能
		reg_data_buff|=(mipi_line2<<6);//mipi_line2的pn交换使能
		reg_data_buff|=(mipi_line1<<5);//mipi_line1的pn交换使能
		reg_data_buff|=(mipi_line0<<4);//mipi_line0的pn交换使能
		reg_data_buff|=(mipi_clk_change<<3);//mipi_clk的pn交换使能
	}
		reg_data_buff=reg_data_buff+mipi_line_choose-1;
	return reg_data_buff;
}

uint8_t reg_13_function(void) //地址0x13寄存器值计算
{
	uint8_t	reg_data_buff=0;
	uint8_t	outB_odd_buff;
	outB_odd_buff = (~outA_odd)&0x01;
	if(dual_lvds_output)//选择lvds双通道输出
	{
		reg_data_buff=dual_lvds_output<<6;//选择lvds通道输出
		reg_data_buff|=(outB_odd_buff<<5);//outB为偶场
		reg_data_buff|=(outA_odd<<4);//outA为偶场
		reg_data_buff|=(outA_jeida<<3);//双通道时跟随outA_jeida使能
		reg_data_buff|=(outA_jeida<<2);//双通道时outA_jeida使能
		reg_data_buff|=(outB_8bit<<1);//outB选择8bit输出
		reg_data_buff|= outA_8bit;//outA选择8bit输出
	}
	else//选择lvds单通道输出
	{
		reg_data_buff=dual_lvds_output<<6;//选择lvds通道输出
		reg_data_buff|=(outB_odd_buff<<5);//outB为偶场
		reg_data_buff|=(outA_odd<<4);//outA为偶场
		reg_data_buff|=(outB_jeida<<3);//单通道时outB_jeida使能
		reg_data_buff|=(outA_jeida<<2);//单通道时outA_jeida使能
		reg_data_buff|=(outB_8bit<<1);//outB选择8bit输出
		reg_data_buff|= outA_8bit;//outA选择8bit输出
		reg_data_buff&=0x0F;
	}
	return reg_data_buff;
}

GM8775C_reg_struct init_reg_data[] =
{
	{0x00,0xAA},
	{0x48,0x02},
	{0xB6,0x20},
	{0x01,0x80},
	{0x02,0x38},
	{0x03,0x47},
	{0x04,0x58},
	{0x05,0x2C},
	{0x06,0x94},
	{0x07,0x00},
	{0x08,0x04},
	{0x09,0x05},
	{0x0A,0x24},
	{0x0B,0x82},
	{0x0C,0x13},
	{0x0D,0x01},
	{0x0E,0x80},
	{0x0F,0x20},
	{0x10,0x20},
	{0x11,0x03},
	{0x12,0x1B},
	{0x13,0x53},
	{0x14,0x01},
	{0x15,0x23},
	{0x16,0x40},
	{0x17,0x00},
	{0x18,0x01},
	{0x19,0x23},
	{0x1A,0x40},
	{0x1B,0x00},
	{0x1E,0x46},
	{0x51,0x30},
	{0x1F,0x10},
	{0x2A,0x01},
};

GM8775C_reg_struct *p_data_table;

extern void get_gm8775c_data_table(GM8775C_reg_struct *data_table);
void get_gm8775c_data_from_dts(void){
	p_data_table = init_reg_data;
	get_gm8775c_data_table(init_reg_data);
}

void  reg_data_config(void)	//芯片寄存器值计算
{
	reg_data[0x00] = chip_password;//器件的password
	reg_data[0x01] = hactive;//行有效像素点,低8位
	reg_data[0x02] = vactive;//列有效像素点,低8位
	reg_data[0x03] = ((vactive>>8)<<4)|((hactive>>8)&0x0F);//列高4位M,行高4位L
	reg_data[0x04] = hfp;//行前肩低8位
	reg_data[0x05] = hsync;//行同步低8位
	reg_data[0x06] = hbp;//行后肩低8位
	reg_data[0x07] = (vs_pol<<7)|(hs_pol<<6)|((hfp&0x300)>>4)|((hsync&0x300)>>6)|((hbp&0x300)>>8);//场、行极性;行前肩、行同步、行后肩高2位;
	reg_data[0x08] = vfp;//场前肩
	reg_data[0x09] = vsync;//场同步
	reg_data[0x0A] = vbp;//场后肩
	reg_data[0x0B] = external_clk_enable ? pll_refdiv : 0x80|pll_refdiv;//时钟选择
	reg_data[0x0C] = (uint8_t)reg_0C_function();//pll_int低8位,选择外部晶振是pll_int=pll_int+2;
	reg_data[0x0D] = (uint8_t)reg_0D_function();//pll_int高2位,pll_post_div;
	reg_data[0x0E] = 0x80;//保持默认值0x80;
	reg_data[0x0F] = min_hsw;//最小行同步,默认值32(0x20)
	reg_data[0x10] = min_hfp;//最小行前肩,默认值32(0x20)
	reg_data[0x11] = (uint8_t)reg_11_function();//mipi数据p/n交换
	reg_data[0x12] = (0<<6)|(1<<4)|(2<<2)|(3<<0);//mipi通道选择
	reg_data[0x13] = (uint8_t)reg_13_function();//lvds单双通道选择,奇偶选择
	reg_data[0x14] = outA_lane_enable ? outA_line1_link|outA_line0_link<<4 : 0x01;//outA_lane0、1选择某条数据输出
	reg_data[0x15] = outA_lane_enable ? outA_line3_link|outA_line2_link<<4 : 0x23;//outA_lane2、3选择某条数据输出
	reg_data[0x16] = outA_lane_enable ? outA_clk_link<<4 : 0x40;//outA_clk选择某条数据输出
	reg_data[0x17] = outA_pn_exchage_enable ? outA_clk<<4|outA_line3<<3|outA_line2<<2|outA_line1<<1|outA_line0 : 0x00;//lvds0组,p/n交换
	reg_data[0x18] = outB_lane_enable ? outB_line1_link|outB_line0_link<<4 : 0x01;//outB_lane0、1选择某条数据输出
	reg_data[0x19] = outB_lane_enable ? outB_line3_link|outB_line2_link<<4 : 0x23;//outB_lane2、3选择某条数据输出
	reg_data[0x1A] = outB_lane_enable ? outB_clk_link<<4 : 0x40;//outB_clk选择某条数据输出
	reg_data[0x1B] = outB_pn_exchage_enable ? outB_clk<<4|outB_line3<<3|outB_line2<<2|outB_line1<<1|outB_line0 : 0x00;//lvds1组,p/n交换
	reg_data[0x1E] = 0x46;//推荐值0x46
	reg_data[0x51] = 0x30;//VCO frequency control 推荐值0x30;
	reg_data[0x1F] = 0x11;//软复位,更新寄存器值
	reg_data[0x2A] = bist_test_enable ? bist_test_choose<<4|0x0D  : 0x01;//测试模式
}



static ssize_t gm8775c_write(u8 chip_addr, u8 reg_address, u8 reg_value)
{
	union i2c_smbus_data data;
	int ret;
	data.byte = reg_value;
	
	ret = i2c_smbus_xfer(gchip->client->adapter, chip_addr, 0,
			      I2C_SMBUS_WRITE, reg_address,
			      I2C_SMBUS_BYTE_DATA, &data);	
	if(ret)
		printk("gm8775c_write error: sending 0x%02x = 0x%02x\n",reg_address,reg_value);	
	else{
		printk("gm8775c_write success: sending 0x%02x = 0x%02x\n",reg_address,reg_value);
	};
		
	return ret;		      
}

u8 gm8775c_read(u8 chip_addr,u8 reg_address)
{
	union i2c_smbus_data data;
	int ret;
	u8 reg_value;
	
	
	ret = i2c_smbus_xfer(gchip->client->adapter, chip_addr, 0,
			      I2C_SMBUS_READ, reg_address,
			      I2C_SMBUS_BYTE_DATA, &data);	
	reg_value = data.byte;
	if(ret){
		printk("gm8775c_read error: read 0x%02x = 0x%02x\n",reg_address,reg_value);
	}else{
		printk("gm8775c_read success: read 0x%02x = 0x%02x\n",reg_address,reg_value);
	}	
	return reg_value;
}




void IIC0_Write_Byte(uint8_t chip_addr, uint8_t reg_addr, uint8_t reg_data)//IIC底层写函数
{
	//gm8775c_write_data(gchip->client, reg_addr, reg_data);
	gm8775c_write(chip_addr, reg_addr, reg_data);
}



uint8_t	IIC0_Read_Byte(uint8_t chip_addr, uint8_t reg_addr)//IIC底层回读函数
{
	union i2c_smbus_data data;
	int ret;
	u8 reg_value;
	
	ret = i2c_smbus_xfer(gchip->client->adapter, chip_addr, 0,
			      I2C_SMBUS_READ, reg_addr,
			      I2C_SMBUS_BYTE_DATA, &data);	
	reg_value = data.byte;

	return reg_value;
}



void reg_data_send(void)//发送reg_data[100]数组中对应地址的寄存器值
{
	uint8_t i=0;

	int data_lenth = sizeof(init_reg_data)/sizeof(init_reg_data[0]);
    for(i=0; i< data_lenth; i++)
    {
        IIC0_Write_Byte(GM8775C_chip_ID, init_reg_data[i].reg_addr, init_reg_data[i].reg_value);
    }
	
#if 0
	for(i=0; i< data_lenth; i++){
		gm8775c_read(GM8775C_chip_ID, init_reg_data[i].reg_addr);
	}
#endif
	

}

EXPORT_SYMBOL_GPL(reg_data_send);

void user_reg_data_send(uint8_t* user_reg_data)//用户直接发送寄存器值,发送user_reg_data[100]数组中对应地址的寄存器值
{
	uint8_t i=0;
	for(i=0;i<0x1C;i++)//发送0x00到0x1B寄存器值
	{
		IIC0_Write_Byte(GM8775C_chip_ID, i, user_reg_data[i]);
	}
	IIC0_Write_Byte(GM8775C_chip_ID, 0x1E, user_reg_data[0x1E]);//推荐值0x46
	IIC0_Write_Byte(GM8775C_chip_ID, 0x51, user_reg_data[0x51]);//VCO frequency control 推荐值0x30;
	IIC0_Write_Byte(GM8775C_chip_ID, 0x1F, user_reg_data[0x1F]);//软复位,更新寄存器值
	IIC0_Write_Byte(GM8775C_chip_ID, 0x2A, user_reg_data[0x2A]);//测试模式
}


void reg_data_read_back_function(void)//回读对应地址的寄存器值,存放于reg_data_read_back[100]中
{
	uint8_t i=0;
	for(i=0;i<0x1C;i++)//发送0x00到0x1B寄存器值
	{
		reg_data_read_back[i]=IIC0_Read_Byte(GM8775C_chip_ID, i);
	}
	reg_data_read_back[0x1E]=IIC0_Read_Byte(GM8775C_chip_ID, 0x1E);//推荐值0x46
	reg_data_read_back[0x51]=IIC0_Read_Byte(GM8775C_chip_ID, 0x51);//VCO frequency control 推荐值0x30;
	reg_data_read_back[0x1F]=IIC0_Read_Byte(GM8775C_chip_ID, 0x1F);//软复位,更新寄存器值
	reg_data_read_back[0x2A]=IIC0_Read_Byte(GM8775C_chip_ID, 0x2A);//测试模式
}

static ssize_t gm8775c_store(struct device *dev, struct device_attribute *attr,
			   const char *buf, size_t count)
{
	int val = 0, flag = 0;
	u8 i = 0, reg, num, value_w, value_r;

	//struct gm8775c_priv *gm8775c = dev_get_drvdata(dev);
	val = simple_strtol(buf, NULL, 16);
	flag = (val >> 16) & 0xFF;

	if (flag) {
		reg = (val >> 8) & 0xFF;
		value_w = val & 0xFF;
		printk("\nWrite: start REG:0x%02x,val:0x%02x,count:0x%02x\n",
		       reg, value_w, flag);
		while (flag--) {
			IIC0_Write_Byte(GM8775C_chip_ID, reg, value_w);
			printk("Write 0x%02x to REG:0x%02x\n", value_w, reg);
			reg++;
		}
	} else {
		reg = (val >> 8) & 0xFF;
		num = val & 0xff;
		printk("\nRead: start REG:0x%02x,count:0x%02x\n", reg, num);

		do {
			value_r = 0;
			value_r = IIC0_Read_Byte(GM8775C_chip_ID, reg);
			printk("REG[0x%02x]: 0x%02x;  ", reg, value_r);
			reg++;
			i++;
			if ((i == num) || (i % 4 == 0))
				printk("\n");
		} while (i < num);
	}

	return count;
}

static ssize_t gm8775c_show(struct device *dev, struct device_attribute *attr,
			  char *buf)
{
	printk("/*** GM8775C driver version: V1.0 ***/\n");
	printk("echo flag|reg|val > gm8775c\n");
	printk("eg->read start addres=0x00,count=0xff: echo 00ff >gm8775c\n");
	printk
	    ("eg->write start addres=0x70,value=0xa0,count=0x2: echo 270a0 >gm8775c\n");
	//printk("eg write value:0xfe to address:0x06 :echo 106fe > gm8775c\n");
	return 0;
}

static DEVICE_ATTR(gm8775c, 0644, gm8775c_show, gm8775c_store);

static struct attribute *gm8775c_debug_attrs[] = {
	&dev_attr_gm8775c.attr,
	NULL,
};

static struct attribute_group gm8775c_debug_attr_group = {
	.name = "gm8775c_debug",
	.attrs = gm8775c_debug_attrs,
};

static int gm8775c_open(struct inode *inode, struct file *filp)
{
    return 0;
}

int gm8775c_release(struct inode *inode, struct file *filp)
{
    return 0;
}

static long gm8775c_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
{
    mutex_lock(&gchip->i2c_lock);
    switch(cmd){
        case GM8775C_GET_DATA:
            break;
        case GM8775C_SET_DATA:
            break;
        default:
            printk("GM8775C_ioctl cmd:0x%x error\n",cmd);
            break;    
    }
    mutex_unlock(&gchip->i2c_lock);
    return 0;
}

static struct file_operations gm8775c_fops =
{
    .owner = THIS_MODULE,
    .open = gm8775c_open,
    .release = gm8775c_release,
    .unlocked_ioctl = gm8775c_ioctl,
};

static struct miscdevice gm8775c_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "gm8775c",
    .fops = &gm8775c_fops,
};

static int gm8775c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
    struct gm8775c_chip *chip;
    struct i2c_adapter *adapter = client->adapter;
    int ret;
	//struct GM8775C_R_DATA data;
	
	printk("====%s\n",__func__);
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)){
		printk("====i2c_check_functionality failed!\n");
		return -ENODEV;
	}
        
    chip = devm_kzalloc(&client->dev,sizeof(struct gm8775c_chip), GFP_KERNEL);
    if (chip == NULL)
        return -ENOMEM;

    chip->names = DRIVER_NAME;
    chip->client = client;
    mutex_init(&chip->i2c_lock);

    gchip = chip;
	
    get_gm8775c_data_from_dts();
    reg_data_send();

    ret = misc_register(&gm8775c_dev);
	printk("====%s succed!\n",__func__);
	
	ret = sysfs_create_group(&client->dev.kobj, &gm8775c_debug_attr_group);
	if (ret) {
		pr_err("gm8775c_probe failed to create attr group\n");
	}
	
	gpio_set_value(GPIO4_D2_D,1); //enable backlight
	
    return 0;
}

static int gm8775c_remove(struct i2c_client *client)
{
    return 0;
}

static const struct i2c_device_id gm8775c_dt_id[] = {
    {"gm8775c", 0},
    { }
};
MODULE_DEVICE_TABLE(i2c, gm8775c_dt_id);

static const struct of_device_id gm8775c_dt_ids[] = {
    { .compatible = "gm8775c", },
    { }
};
MODULE_DEVICE_TABLE(i2c, gm8775c_dt_ids);

static struct i2c_driver gm8775c_driver = {
    .probe        = gm8775c_probe,
    .remove        = gm8775c_remove,
    .driver = {
        .name    = DRIVER_NAME,
        .owner = THIS_MODULE,    
        .of_match_table = of_match_ptr(gm8775c_dt_ids),
    },
    .id_table = gm8775c_dt_id,
};

static int __init gm8775c_init(void)
{
	printk("====%s\n",__func__);
    return i2c_add_driver(&gm8775c_driver);
}

static void __exit gm8775c_exit(void)
{
    i2c_del_driver(&gm8775c_driver);
}

subsys_initcall(gm8775c_init);
module_exit(gm8775c_exit);

MODULE_AUTHOR("cf@customer.com");
MODULE_DESCRIPTION("i2c driver for gm8775c");
MODULE_LICENSE("GPL");

DTS:

&i2c2 {
	status = "okay";
	pinctrl-0 = <&i2c2m0_xfer>;
    
    gm8775c: gm8775c@2d {
        status = "okay";
        compatible = "gm8775c";
        reg = <0x2d>;
    };
};

gm8775 ic


http://www.kler.cn/a/282072.html

相关文章:

  • PyTorch——从入门到精通:PyTorch基础知识(张量)【PyTorch系统学习】
  • 第二十一周学习周报
  • vueRouter路由切换时实现页面子元素动画效果, 左右两侧滑入滑出效果
  • 【MQTT.fx 客户端接入 阿里云平台信息配置】
  • RTSP播放器EasyPlayer.js播放器UniApp或者内嵌其他App里面webview需要截图下载
  • STL序列式容器之stack
  • CSS基础 什么是盒模型
  • Vue3源码调试-第三篇
  • 打印样式的艺术:用CSS @media 规则优化页面输出
  • #C++ 笔记二
  • leetcode518:零钱兑换II
  • 读取FTP中不同文件格式的文件流后导出到浏览器
  • 前端环境配置
  • 性能测试面试题汇总
  • 企业选择raksmart大带宽服务器的原因
  • 信息检索与事实核查(1):Search-Adaptor: Embedding Customization for Information Retrieval
  • 李宏毅 机器学习与深度学习【2022版】 03
  • 软考攻略/超详细/系统集成项目管理工程师/基础知识分享05
  • llama-cpp-python编译失败,解决方案安装wheel文件
  • 小米14的射频芯片高通SDR753全景图
  • 【练习】哈希表的使用
  • macOS 设置 vm.max_map_count [RAGFlow]
  • 刘文超行测笔记
  • Dopamine(多巴胺)越狱工具一键越狱教程:支持 iOS 15-iOS 16.6.1 设备
  • 5G NR HARQ操作机制
  • MySQL索引(三)