I2C子系统之驱动SSD1306 OLED(2)

1 i2c_probe_address() 2 i2c_smbus_xfer() 3 i2c_smbus_xfer_emulated(); 4 i2c_transfer(); 5 adap->algo->master_xfer(adap,msgs,num);

adap->algo->master_xfer(adap,msgs,num);实际调用的是bit_xfer()

探测到ssd1306后,其实也就说明了探测到的I2C地址有效, 还需要注册一个描述SSD1306的i2c_client。

static int ssd1306_detect(struct i2c_adapter *adapter, int address, int kind)

    printk("ssd1306_detect\n");

ssd1306_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
    ssd1306_client->addr    = address;
    ssd1306_client->adapter = adapter;
    ssd1306_client->driver  = &ssd1306_driver;
    strcpy(ssd1306_client->name, "ssd1306");
   
    i2c_attach_client(ssd1306_client);
   
    ... ...
}

先转下话题。

在i2c-gpio.c中,

1 static int __init i2c_gpio_init(void) 2 { 3 ... ... 4 ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe); 5 ... ... 6 }

这里实际上是注册了一个platform_driver,我们还要对应的为他注册一个platform_device,

这个platform_device提供了硬件相关的设置,如指定那两个io口为SCL和SDA。

I2c_gpio_dev.c中

static struct i2c_gpio_platform_data i2c_dev = {
    .sda_pin = S3C2410_GPG6,
    .scl_pin = S3C2410_GPG5,
    .udelay = 0,
    .timeout = 0,
    .sda_is_open_drain = 1,
    .scl_is_open_drain = 1,
    .scl_is_output_only = 1
};

static struct platform_device i2c_platform_dev = {
    .name        = "i2c-gpio",
    .id          = -1,
    .dev = {
        .release = i2c_dev_release,
        .platform_data = (void *)&i2c_dev,
    },
};

static int i2c_dev_init(void)
{
    platform_device_register(&i2c_platform_dev);
    return 0;
}

如果platform_device和platform_driver匹配,就会调用i2c_gpio_probe()

static int __init i2c_gpio_probe(struct platform_device *pdev)
{
    struct i2c_gpio_platform_data *pdata;
    struct i2c_algo_bit_data *bit_data;
    struct i2c_adapter *adap;
    ... ...
    pdata = pdev->dev.platform_data;
    ... ...
    i2c_bit_add_bus(adap);
    ... ...
}

只有platform_device和platform_driver匹配才能注册i2c_adapter。

到这里,就可以操作ssd1306了。ssd1306写一个字节的操作:

static void ssd1306_write_byte(uint8_t chData, uint8_t chCmd)
{
    uint8_t cmd = 0x00;
   
    if (chCmd) {
        cmd = 0x40;
    } else {
        cmd = 0x00;
    }

i2c_smbus_write_byte_data(ssd1306_client, cmd, chData);
}

实际上调用了i2c_smbus_write_byte_data() 

I2c_core.c提供了几个I2C的读写函数:

1 s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value); 2 s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command); 3 ... ... 4 s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values); 5 s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, 6 u8 length, const u8 *values)

运行代码

注:由于源码的i2c-gpio-bit.c只支持具有开漏输入输出功能的IO模拟I2C, 而我的开发板已经没有具有开漏输入输出功能的IO了,只能使用普通的上啦输入输出IO,对SDA的读写操作,需要切换输入输出方向。因此我把i2c-gpio-bit.c改成普通IO操作SDA,命名为my-i2c-gpio-bit.c,同时i2c-gpio-bit.h和i2c-gpio.c也要做相应改动,分别改为my-i2c-gpio-bit.h和my-i2c-gpio.c。如果使用具有开漏输入输出功能的IO,可以直接使用i2c-gpio-bit.c,i2c-gpio-bit.h,i2c-gpio.c。

I2C子系统之驱动SSD1306 OLED

I2C子系统之驱动SSD1306 OLED

代码

i2c_gpio_dev.c

#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/7523527a0e17da2d479d416348ae0566.html