/* i2c-core.c - a device driver for the iic-bus interface */
/* ------------------------------------------------------------------------- */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/idr.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include "i2c-algo-GM.h"
static LIST_HEAD(adapters);
static LIST_HEAD(drivers);
static DECLARE_MUTEX(core_lists);
static DEFINE_IDR(i2c_adapter_idr);
/* match always succeeds, as we want the probe() to tell if we really accept this match */
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
static int i2c_bus_suspend(struct device * dev, pm_message_t state)
{
int rc = 0;
if (dev->driver && dev->driver->suspend)
rc = dev->driver->suspend(dev,state,0);
return rc;
}
static int i2c_bus_resume(struct device * dev)
{
int rc = 0;
if (dev->driver && dev->driver->resume)
rc = dev->driver->resume(dev,0);
return rc;
}
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.suspend = i2c_bus_suspend,
.resume = i2c_bus_resume,
};
static int i2c_device_probe(struct device *dev)
{
return -ENODEV;
}
static int i2c_device_remove(struct device *dev)
{
return 0;
}
void i2c_adapter_dev_release(struct device *dev)
{
struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
complete(&adap->dev_released);
}
struct device_driver i2c_adapter_driver = {
.name = "i2c_adapter",
.bus = &i2c_bus_type,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
};
static void i2c_adapter_class_dev_release(struct class_device *dev)
{
struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev);
complete(&adap->class_dev_released);
}
struct class i2c_adapter_class = {
.name = "i2c-adapter",
.release = &i2c_adapter_class_dev_release,
};
static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
return sprintf(buf, "%s\n", adap->name);
}
static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
static void i2c_client_release(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
complete(&client->released);
}
static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
return sprintf(buf, "%s\n", client->name);
}
/*
* We can't use the DEVICE_ATTR() macro here as we want the same filename for a
* different type of a device. So beware if the DEVICE_ATTR() macro ever
* changes, this definition will also have to change.
*/
static struct device_attribute dev_attr_client_name = {
.attr = {.name = "name", .mode = S_IRUGO, .owner = THIS_MODULE },
.show = &show_client_name,
};
/* ---------------------------------------------------
* registering functions
* ---------------------------------------------------
*/
/* -----
* i2c_add_adapter is called from within the algorithm layer,
* when a new hw adapter registers. A new device is register to be
* available for clients.
*/
int i2c_add_adapter(struct i2c_adapter *adap)
{
int id, res = 0;
struct list_head *item;
struct i2c_driver *driver;
down(&core_lists);
if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
res = -ENOMEM;
goto out_unlock;
}
res = idr_get_new(&i2c_adapter_idr, adap, &id);
if (res < 0) {
if (res == -EAGAIN)
res = -ENOMEM;
goto out_unlock;
}
adap->nr = id & MAX_ID_MASK;
init_MUTEX(&adap->bus_lock);
init_MUTEX(&adap->clist_lock);
list_add_tail(&adap->list,&adapters);
INIT_LIST_HEAD(&adap->clients);
/* Add the adapter to the driver core.
* If the parent pointer is not set up,
* we add this adapter to the host bus.
*/
if (adap->dev.parent == NULL)
adap->dev.parent = &platform_bus;
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
adap->dev.driver = &i2c_adapter_driver;
adap->dev.release = &i2c_adapter_dev_release;
device_register(&adap->dev);
device_create_file(&adap->dev, &dev_attr_name);
/* Add this adapter to the i2c_adapter class */
memset(&adap->class_dev, 0x00, sizeof(struct class_device));
adap->class_dev.dev = &adap->dev;
adap->class_dev.class = &i2c_adapter_class;
strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
class_device_register(&adap->class_dev);
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
/* inform drivers of new adapters */
list_for_each(item,&drivers) {
driver = list_entry(item, struct i2c_driver, list);
if (driver->flags & I2C_DF_NOTIFY)
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
out_unlock:
up(&core_lists);
printk("i2c-core.o: adapter %s registered\n", adap->name);
return res;
}
int i2c_del_adapter(struct i2c_adapter *adap)
{
struct list_head *item, *_n;
struct i2c_adapter *adap_from_list;
struct i2c_driver *driver;
struct i2c_client *client;
int res = 0;
down(&core_lists);
/* First make sure that this adapter was ever added */
list_for_each_entry(adap_from_list, &adapters, list) {
if (adap_from_list == adap)
break;
}
if (adap_from_list != adap) {
pr_debug("i2c-core: attempting to delete unregistered "
"adapter [%s]\n", adap->name);
res = -EINVAL;
goto out_unlock;
}
list_for_each(item,&drivers) {
driver = list_entry(item, struct i2c_driver, list);
if (driver->detach_adapter)
if ((res = driver->detach_adapter(adap))) {
dev_err(&adap->dev, "detach_adapter failed "
"for driver [%s]\n", driver->name);
goto out_unlock;
}
}
/* detach any active clients. This must be done first, because
* it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) {
client = list_entry(item, struct i2c_client, list);
/* detaching devices is unconditional of the set notify
* flag, as _all_ clients that reside on the adapter
* must be deleted, as this would cause invalid states.
*/
if ((res=client->driver->detach_client(client))) {
dev_err(&adap->dev, "detach_client failed for client "
"[%s] at address 0x%02x\n", client->name,
client->addr);
goto out_unlock;
}
}
/* clean up the sysfs representation */
init_completion(&adap->dev_released);
init_completion(&adap->class_dev_released);
class_device_unregister(&adap->class_dev);
device_remove_file(&adap->dev, &dev_attr_name);
device_unregister(&adap->dev);
list_del(&adap->list);
/* wait for sysfs to drop all references */
wait_for_completion(&adap->dev_released);
wait_for_completion(&adap->class_dev_released);
/* free dynamically allocated bus id */
idr_remove(&i2c_adapter_idr, adap->nr);
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
out_unlock:
up(&core_lists);
return res;
}
/* -----
* What follows is the "upwards" interface: commands for talking to clients,
* which implement the functions to access the physical information of the
* chips.
*/
int i2c_add_driver(struct i2c_driver *driver)
{
struct list_head *item;
struct i2c_adapter *adapter;
int res = 0;
down(&core_lists);
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.name = driver->name;
driver->driver.bus = &i2c_bus_type;
driver->driver.probe = i2c_device_probe;
driver->driver.remove = i2c_device_remove;
res = driver_register(&driver->driver);
if (res)
goto out_unlock;
list_add_tail(&driver->list,&drivers);
pr_debug("i2c-core: driver [%s] registered\n", driver->name);
/* now look for instances of driver on our adapters */
if (driver->flags & I2C_DF_NOTIFY) {
list_for_each(item,&adapters) {
adapter = list_entry(item, struct i2c_adapter, list);
driver->attach_adapter(adapter);
}
}
out_unlock:
up(&core_lists);
return res;
}
int i2c_del_driver(struct i2c_driver *driver)
{
struct list_head *item1, *item2, *_n;
struct i2c_client *client;
struct i2c_adapter *adap;
int re
I2C.rar_i2c
版权申诉
85 浏览量
2022-09-21
06:30:57
上传
评论
收藏 23KB RAR 举报
小贝德罗
- 粉丝: 70
- 资源: 1万+
最新资源
- Pytorch-pytorch深度学习教程之深度残差网络.zip
- Pytorch-pytorch深度学习教程之循环神经网络.zip
- Pytorch-pytorch深度学习教程之逻辑回归.zip
- Pytorch-pytorch深度学习教程之双向循环网络.zip
- Pytorch-pytorch深度学习教程之卷积神经网络.zip
- Pytorch-pytorch深度学习教程之前馈神经网络.zip
- Pytorch-pytorch深度学习教程之线性回归.zip
- Pytorch-pytorch深度学习教程之基本操作.zip
- 基于QT的地图可视化桌面系统后台数据库为MySQL5.7源码.zip
- 基于simulink的PLL锁相环系统仿真【包括模型,文档,参考文献,操作步骤】
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈