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