完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
首先设备树文件 i2c4: i2c@ff160000 { compatible = "rockchip,rk30-i2c"; reg = <0xff160000 0x1000>; interrupts = #address-cells = <1>; #size-cells = <0>; pinctrl-names = "default", "gpio"; pinctrl-0 = <&i2c4_sda &i2c4_scl>; pinctrl-1 = <&i2c4_gpio>; gpios = <&gpio7 GPIO_C1 GPIO_ACTIVE_LOW>, <&gpio7 GPIO_C2 GPIO_ACTIVE_LOW>; clocks = <&clk_gates6 15>; rockchip,check-idle = <1>; status = "disabled"; }; &i2c4 { status = "okay"; i2c_oled@3c { compatible = "rk3288,i2c-oled"; reg = <0x3c>; }; }; //i2c控制器注册 static const struct of_device_id rockchip_i2c_of_match[] = { { .compatible = "rockchip,rk30-i2c", .data = NULL, }, {}, }; MODULE_DEVICE_TABLE(of, rockchip_i2c_of_match); static struct platform_driver rockchip_i2c_driver = { .probe = rockchip_i2c_probe, .remove = rockchip_i2c_remove, .shutdown = rockchip_i2c_shutdown, .driver = { .owner = THIS_MODULE, .name = "rockchip_i2c", .pm = ROCKCHIP_I2C_PM_OPS, .of_match_table = of_match_ptr(rockchip_i2c_of_match), }, }; static int rockchip_i2c_probe(struct platform_device *pdev) struct rockchip_i2c *i2c = NULL; i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; i2c->adap.algo = &rockchip_i2c_algorithm; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取内存资源 i2c->regs = devm_ioremap_resource(&pdev->dev, res); of_property_read_u32(np, "rockchip,check-idle", &i2c->check_idle); if (i2c->check_idle) { i2c->sda_gpio = of_get_gpio(np, 0); if (!gpio_is_valid(i2c->sda_gpio)) { dev_err(&pdev->dev, "sda gpio is invalidn"); return -EINVAL; } ret = devm_gpio_request(&pdev->dev, i2c->sda_gpio, dev_name(&i2c->adap.dev)); if (ret) { dev_err(&pdev->dev, "failed to request sda gpion"); return ret; } i2c->scl_gpio = of_get_gpio(np, 1); if (!gpio_is_valid(i2c->scl_gpio)) { dev_err(&pdev->dev, "scl gpio is invalidn"); return -EINVAL; } ret = devm_gpio_request(&pdev->dev, i2c->scl_gpio, dev_name(&i2c->adap.dev)); if (ret) { dev_err(&pdev->dev, "failed to request scl gpion"); return ret; } i2c->gpio_state = pinctrl_lookup_state(i2c->dev->pins->p, "gpio"); if (IS_ERR(i2c->gpio_state)) { dev_err(&pdev->dev, "no gpio pinctrl staten"); return PTR_ERR(i2c->gpio_state); } pinctrl_select_state(i2c->dev->pins->p, i2c->gpio_state); gpio_direction_input(i2c->sda_gpio); //设置为输入 gpio_direction_input(i2c->scl_gpio); //设置为输入 pinctrl_select_state(i2c->dev->pins->p, i2c->dev->pins->default_state); //选择默认状态 } ret = i2c_add_adapter(&i2c->adap);//i2c核心注册adapt /* i2c_register_adapter(adapter); --> adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); --> internal_of_i2c_register_devices(adap); --> for_each_available_child_of_node(adap->dev.of_node, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue; of_i2c_register_device(adap, node);--> //i2c-core.c //分配、设置、注册i2c_board_info结构体,最后通过i2c_new_device注册进内核 struct i2c_board_info info = {}; addr = of_get_property(node, "reg", &len); info.irq = irq_of_parse_and_map(node, 0); if (of_get_property(node, "wakeup-source", NULL)) info.flags |= I2C_CLIENT_WAKE; result = i2c_new_device(adap, &info); bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); } */ i2c->clk = devm_clk_get(&pdev->dev, NULL);//获取时钟 i2c->irq = ret = platform_get_irq(pdev, 0);//得到中断号 ret = devm_request_irq(&pdev->dev, i2c->irq, rockchip_i2c_irq, 0, dev_name(&i2c->adap.dev), i2c);//申请中断 ret = clk_prepare(i2c->clk); i2c->i2c_rate = clk_get_rate(i2c->clk); rockchip_i2c_init_hw(i2c, 100 * 1000); of_i2c_register_devices(&i2c->adap); i2c_driver注册: i2c_add_driver(&oled_driver); i2c_register_driver(THIS_MODULE, driver) driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; //当注册返回时,驱动核心层已经调用了probe来匹配那些符合但是为绑定的设备 /* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); if (res) return res; //对于每一个适配器,都调用__process_new_driver //对于每一个适配器,调用它的函数确定address_list里的设备是否存在,如果存在,再调用detect进一步确定、设置,然后i2c_new_device /* Walk the adapters that are already present */ i2c_for_each_dev(driver, __process_new_driver); i2c_do_add_adapter(data, to_i2c_adapter(dev)); i2c_detect(adap, driver); for (i = 0; address_list != I2C_CLIENT_END; i += 1) { dev_dbg(&adapter->dev, "found normal entry for adapter %d, ""addr 0x%02xn", adap_id, address_list); temp_client->addr = address_list; i2c_detect_address(temp_client, driver); err = i2c_check_addr_validity(addr);//检查地址 //简单的确认i2c总线上是否有这个设备 /* Make sure there is something at this address */ if (!i2c_default_probe(adapter, addr)) return 0; //回调传进来的detect函数 err = driver->detect(temp_client, &info); client = i2c_new_device(adapter, &info); } oled驱动程序: #include #include #include #include #include #include #include #include #include #include #include #include static int major; static struct class *class; static struct i2c_client *i2c_oled_client; static unsigned char *ker_buf; #define OLED_CMD_INIT 0x100001 #define OLED_CMD_CLEAR_ALL 0x100002 #define OLED_CMD_SHOW_STR 0x100003 #define OLED_CMD_SHOW_CN 0x100004 #define OLED_CMD_SHOW_BMP 0x100005 #define OLED_CMD_SET_POS 0X100006 #define OLED_CMD_FILL 0x100007 static int posX, posY; void I2C_WriteByte(uint8_t addr,uint8_t data) { int ret=-1; char buf[2]; buf[0]=addr; buf[1]=data; ret = i2c_master_send(i2c_oled_client, buf, 2); if (ret <0) printk("i2c_master_send err:%dn", ret); } void WriteCmd(unsigned char I2C_Command)//写命令 { I2C_WriteByte(0x00, I2C_Command); } void WriteDat(unsigned char I2C_Data)//写数据 { I2C_WriteByte(0x40, I2C_Data); } void OLED_Init(void) { //DelayMs(100); //这里的延时很重要 msleep(100); WriteCmd(0xAE); //display off WriteCmd(0x20); //Set Memory Addressing Mode WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7 WriteCmd(0xc8); //Set COM Output Scan Direction WriteCmd(0x00); //---set low column address WriteCmd(0x10); //---set high column address WriteCmd(0x40); //--set start line address WriteCmd(0x81); //--set contrast control register WriteCmd(0xff); //亮度调节 0x00~0xff WriteCmd(0xa1); //--set segment re-map 0 to 127 WriteCmd(0xa6); //--set normal display WriteCmd(0xa8); //--set multiplex ratio(1 to 64) WriteCmd(0x3F); // WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content WriteCmd(0xd3); //-set display offset WriteCmd(0x00); //-not offset WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency WriteCmd(0xf0); //--set divide ratio WriteCmd(0xd9); //--set pre-charge period WriteCmd(0x22); // WriteCmd(0xda); //--set com pins hardware configuration WriteCmd(0x12); WriteCmd(0xdb); //--set vcomh WriteCmd(0x20); //0x20,0.77xVcc WriteCmd(0x8d); //--set DC-DC enable WriteCmd(0x14); // WriteCmd(0xaf); //--turn on oled panel } void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标 { WriteCmd(0xb0+y); WriteCmd(((x&0xf0)>>4)|0x10); WriteCmd((x&0x0f)|0x01); } void OLED_Fill(unsigned char fill_Data)//全屏填充 { unsigned char m,n; for(m=0;m<8;m++) { WriteCmd(0xb0+m); //page0-page1 WriteCmd(0x00); //low column start address WriteCmd(0x10); //high column start address for(n=0;n<128;n++) { WriteDat(fill_Data); } } } void OLED_CLS(void)//清屏 { OLED_Fill(0x00); } void OLED_ON(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X14); //开启电荷泵 WriteCmd(0XAF); //OLED唤醒 } void OLED_OFF(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X10); //关闭电荷泵 WriteCmd(0XAE); //OLED休眠 } static long oled_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case OLED_CMD_INIT: OLED_Init(); break; case OLED_CMD_CLEAR_ALL: OLED_CLS(); break; case OLED_CMD_SET_POS: posX=arg & 0xff; posY=(arg>>8) & 0xff; printk("oled pos x:%d, pos y: %dn", posX, posY); OLED_SetPos(posX, posY); break; case OLED_CMD_FILL: OLED_Fill(0xff); break; } return 0; } static ssize_t oled_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int ret; if (count > 4096) return -EINVAL; ret = copy_from_user(ker_buf, buf, count); if (ret >0) printk("get user disp data err %dn",ret); WriteDat(buf[0]);//写数据 return 0; } static struct file_operations oled_fops = { .owner = THIS_MODULE, .unlocked_ioctl = oled_ioctl, .write = oled_write, }; static int oled_probe(struct i2c_client *client, const struct i2c_device_id *id) { printk("%s, %s, %dn", __FILE__, __FUNCTION__, __LINE__); ker_buf = kmalloc(4096, GFP_KERNEL); i2c_oled_client = client; printk("i2c_oled addr is 0x%xn", client->addr); major = register_chrdev(0, "i2c-oled", &oled_fops); class = class_create(THIS_MODULE, "i2c-oled"); device_create(class, NULL, MKDEV(major, 0), NULL, "i2c-oled"); return 0; } static int oled_remove(struct i2c_client *client) { device_destroy(class, MKDEV(major, 0)); class_destroy(class); unregister_chrdev(major, "i2c-oled"); kfree(ker_buf); return 0; } static const struct i2c_device_id oled_id[] = { { "oled", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, oled_id); static struct of_device_id oled_dt_ids[] = { { .compatible = "rk3288,i2c-oled" }, {}, }; struct i2c_driver oled_driver = { .driver = { .name = "i2c_oled", .owner = THIS_MODULE, .of_match_table = of_match_ptr(oled_dt_ids), }, .probe = oled_probe, .remove = oled_remove, .id_table = oled_id, }; static int __init i2c_oled_init(void) { return i2c_add_driver(&oled_driver); } static void __exit i2c_oled_exit(void) { i2c_del_driver(&oled_driver); } late_initcall(i2c_oled_init); module_exit(i2c_oled_exit); MODULE_AUTHOR("teefirefly@gmail.com"); MODULE_DESCRIPTION("Firefly vga edid driver"); MODULE_LICENSE("GPL"); 测试程序 #include #include #include #include #include #include #include #include #include "oledfont.h" /* oled_test init * oled_test clear * oled_test clear * oled_test */ #define OLED_CMD_INIT 0x100001 #define OLED_CMD_CLEAR_ALL 0x100002 #define OLED_CMD_SHOW_STR 0x100003 #define OLED_CMD_SHOW_CN 0x100004 #define OLED_CMD_SHOW_BMP 0x100005 #define OLED_CMD_SET_POS 0X100006 #define OLED_CMD_FILL 0x100007 int fd; inline static void OLED_SetPos(unsigned char x, unsigned char y) { ioctl(fd,OLED_CMD_SET_POS,((y&0xff)<<8)|(x&0xff)); } inline static void WriteDat(unsigned char data) { //ioctl(fd, OLED_CMD_SHOW_STR,data); write(fd, &data, 1); } void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) { unsigned char c = 0,i = 0,j = 0; switch(TextSize) { case 1: { while(ch[j] != ' |