前期说明
- 什么是I2C?
``
如何设计
-
Linux i2c 内核框架(kernel\drivers\i2c)
-
通用
基于 i2c 设备驱动
框架
/*
* Copyright 2019 by
* Finelio Tower <luorongwei@sunchip-tech.com>
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.q
*
*/
#include "general_i2c_driver.h"
#define I2C_SPEED (200 * 1000)
#define I2C_READ_REG(x) (x->addr | 0x01)
#define I2C_WRITE_REG(x) (x->addr)
struct general_i2c_driver {
const char *version;
spinlock_t spin;
struct device *dev;
};
static struct general_i2c_driver *m_general_i2c_driver;
static int general_i2c_driver_i2c_write(struct i2c_adapter *i2c_adapter,
unsigned char address,
unsigned int len, unsigned char const *data)
{
struct i2c_msg msgs[1];
int ret;
if (!data || !i2c_adapter) {
printk("%s: line=%d, error\n", __func__, __LINE__);
return -EINVAL;
}
msgs[0].addr = address >> 1;
msgs[0].flags = 0; /* write */
msgs[0].buf = (unsigned char *)data;
msgs[0].len = len;
msgs[0].scl_rate = general_i2c_driver_I2C_SPEED;
ret = i2c_transfer(i2c_adapter, msgs, 1);
return (ret == 1) ? len : ret;
}
static int general_i2c_driver_i2c_read(struct i2c_adapter *i2c_adap,
unsigned char address, unsigned char reg,
unsigned int len, unsigned char *data)
{
struct i2c_msg msgs[2];
int res;
if (!data || !i2c_adap) {
printk("%s: line=%d, error\n", __func__, __LINE__);
return -EINVAL;
}
msgs[0].addr = address >> 1;
msgs[0].flags = 0; /* write */
msgs[0].buf = ®
msgs[0].len = 1;
msgs[0].scl_rate = general_i2c_driver_I2C_SPEED;
msgs[1].addr = address >> 1;
msgs[1].flags = I2C_M_RD;
msgs[1].buf = data;
msgs[1].len = len;
msgs[1].scl_rate = general_i2c_driver_I2C_SPEED;
res = i2c_transfer(i2c_adap, msgs, 2);
return (res == 1) ? len : res;
}
#ifdef CONFIG_OF
static int platdata_parse_dt(struct device *dev, struct general_i2c_driver *mcu)
{
struct device_node *node = dev->of_node;
int ret = 0;
if (!node) {
printk("=====node error!=====\n");
return -ENODEV;
}
return 0;
}
#else
static int general_i2c_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct general_i2c_driver *mcu = NULL;
int ret = 0;
mcu = devm_kzalloc(dev, sizeof(struct general_i2c_driver), GFP_KERNEL);
if (!mcu) {
dev_err(dev, "%s error \n", __func__);
return -ENOMEM;
}
m_general_i2c_driver = mcu;
mcu->client = client;
mcu->device_id = id->driver_data;
#ifdef CONFIG_OF
ret = platdata_parse_dt(&client->dev, mcu);
#else
i2c_set_clientdata(client, mcu);
return 0;
}
static int general_i2c_driver_remove(struct i2c_client *client)
{
struct general_i2c_driver *mcu = i2c_get_clientdata(client);
if (!mcu) {
return -EFAULT;
}
devm_kfree(mcu->dev, mcu);
return 0;
}
static void general_i2c_driver_shutdown(struct i2c_client *client)
{
struct general_i2c_driver *mcu = i2c_get_clientdata(client);
if (!mcu) {
return;
}
devm_kfree(mcu->dev, mcu);
}
static const struct i2c_device_id general_i2c_driver_i2c_id[] = {
{ MODULE_NAME, 0 },
{},
};
MODULE_DEVICE_TABLE(i2c, general_i2c_driver_i2c_id);
static struct of_device_id general_i2c_driver_dt_ids[] = {
{ .compatible = "general" },
};
static struct i2c_driver general_i2c_driver_driver = {
.driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(general_i2c_driver_dt_ids),
},
.probe = general_i2c_driver_probe,
.remove = general_i2c_driver_remove,
.shutdown = general_i2c_driver_shutdown,
.id_table = general_i2c_driver_i2c_id,
};
module_i2c_driver(general_i2c_driver_driver);
MODULE_DESCRIPTION("General I2C Driver");
MODULE_AUTHOR("iFinelio Tower <luorongwei@308662170.com>");
MODULE_LICENSE("GPL v2");
[补充]: 有问题可以邮件沟通 iFinelio Tower <308662170@qq.com>