[RK3399][Android7.1] 基于regmap的I2C实现方法

驱动代码的实现如下:

/*
 * Copyright (c) 2016, Sun Mi Electronics Co., Ltd
 * Author: Yong Zhu <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * Some ideas are from chrome ec and fairchild GPL fusb302 driver.
 */

#include <linux/delay.h>
#include <linux/extcon.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/power_supply.h>
#include <linux/i2c.h>

#define MIPI2LVDS_I2C_DRIVER_NAME       "TC358774XBG_75XBG"
#define MIPI2LVDS_I2C_DEVICETREE_NAME   "TC358774XBG_75XBG"

#define ENDMARKER { 0xffff, 0xffffffff}

struct mipi2lvds_chip {
    struct i2c_client *client;
    struct device *dev;
    struct regmap *regmap;
};
struct mipi2lvds_reg {
    unsigned int reg;
    unsigned int val;
    unsigned int dly;
};

struct i2c_client *this_client;

struct regmap_config dsi2lvds_regmap_config = {
    .reg_bits = 16,
    .val_bits = 32,
    .cache_type = REGCACHE_RBTREE,
    //数据位,先发送低位,再发送高位
    .val_format_endian = REGMAP_ENDIAN_LITTLE, 
};

struct mipi2lvds_reg mipi2lvds_init_table[]=
{
    {0x013C,0x000A000C,0},
    {0x0114,0x00000008,0},
    {0x0164,0x0000000D,0},
    {0x0168,0x0000000D,0},
    {0x016C,0x0000000D,0},
    {0x0170,0x0000000D,0},
    {0x0134,0x0000001F,0},
    {0x0210,0x0000001F,0},
    {0x0104,0x00000001,0},
    {0x0204,0x00000001,0},
    {0x0450,0x03F00120,0},
    {0x0454,0x003C0014,0},
    {0x0458,0x00C80780,0},
    {0x045C,0x000C0008,0},
    {0x0460,0x001A0438,0},
    {0x0464,0x00000001,0},
    {0x04A0,0x00448006,100},
    {0x04A0,0x00048006,0},
    {0x0504,0x00000004,0},
    {0x0480,0x03020100,0},
    {0x0484,0x08050704,0},
    {0x0488,0x0F0E0A09,0},
    {0x048C,0x100D0C0B,0},
    {0x0490,0x12111716,0},
    {0x0494,0x1B151413,0},
    {0x0498,0x061A1918,0x14},
    {0x049C,0x00000263,0x78},
    ENDMARKER,  
};

void dsi2lvds_init(void)
{
    struct mipi2lvds_chip *chip;
    int i = 0;
    int ret = 0;
    chip = i2c_get_clientdata(this_client);

    while (mipi2lvds_init_table[i].reg != 0xffff) {
        ret = regmap_write(chip->regmap, mipi2lvds_init_table[i].reg, mipi2lvds_init_table[i].val);
        if(ret < 0)
        {
            printk("%s failed index = %d\n",__func__,i);
        }
        if(mipi2lvds_init_table[i].dly != 0x0)
            udelay(mipi2lvds_init_table[i].dly);
        i++;
    }
}
static int dsi2lvds_probe(struct i2c_client *client,
             const struct i2c_device_id *id)
{
    struct mipi2lvds_chip *chip;

    chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
    if (!chip)
        return -ENOMEM;

    chip->dev = &client->dev;
    chip->regmap = devm_regmap_init_i2c(client, &dsi2lvds_regmap_config);
    if (IS_ERR(chip->regmap)) {
        dev_err(&client->dev, "Failed to allocate regmap!\n");
        return PTR_ERR(chip->regmap);
    }

    this_client = client;
    i2c_set_clientdata(client, chip);

    dsi2lvds_init();

    dev_info(chip->dev,"%s success\n",__func__);

    return 0;

}

static const struct of_device_id dsi2lvds_dt_match[] = {
    { .compatible = MIPI2LVDS_I2C_DEVICETREE_NAME },
    {},
};
MODULE_DEVICE_TABLE(of, dsi2lvds_dt_match);

static const struct i2c_device_id dsi2lvds_i2c_device_id[] = {
    { MIPI2LVDS_I2C_DRIVER_NAME, 0 },
    {}
};
MODULE_DEVICE_TABLE(i2c, dsi2lvds_i2c_device_id);

static struct i2c_driver dsi2lvds_driver = {
    .driver = {
        .name = MIPI2LVDS_I2C_DRIVER_NAME,
        .of_match_table = of_match_ptr(dsi2lvds_dt_match),
    },
    .probe = dsi2lvds_probe,
    .id_table = dsi2lvds_i2c_device_id,
};

module_i2c_driver(dsi2lvds_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("yong zhu <[email protected]>");
MODULE_DESCRIPTION("mipi2lvds driver");

DTS的配置如下:

&i2c4 {
    status = "okay";
    i2c-scl-rising-time-ns = <475>;
    i2c-scl-falling-time-ns = <26>;
    //这里的0xf是对应的7位I2C地址
    lvds_bridge: tc358774X@f {
        compatible = "TC358774XBG_75XBG";
        reg = <0x0f>;

        status = "okay";
    };  
};

这里面特别要留意下面:

struct regmap_config dsi2lvds_regmap_config = {
    .reg_bits = 16,
    .val_bits = 32,
    .cache_type = REGCACHE_RBTREE,
    //数据位,先发送低位,再发送高位
    .val_format_endian = REGMAP_ENDIAN_LITTLE, 
};

如果REGMAP_ENDIAN_LITTLE被配置意味着,寄存器的地址或者数据是先发送低位再发送高位。这个的配置需要查看芯片的Datasheet,如下:
这里写图片描述
从上面可以得知:
寄存器的地址发送保持默认,即先发送高位再发送低位; —–REGMAP_ENDIAN_BIG
寄存器的数据则是先发送低位再发送高位; ——REGMAP_ENDIAN_LITTLE

-

猜你喜欢

转载自blog.csdn.net/zhuyong006/article/details/81224292