aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c/busses/i2c-isa.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-isa.c')
-rw-r--r--drivers/i2c/busses/i2c-isa.c161
1 files changed, 149 insertions, 12 deletions
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index 00e7f7157b75..bdc6806dafae 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -1,6 +1,8 @@
1/* 1/*
2 i2c-isa.c - Part of lm_sensors, Linux kernel modules for hardware 2 i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
3 monitoring 3 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
4
5 Based on the i2c-isa pseudo-adapter from the lm_sensors project
4 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> 6 Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
5 7
6 This program is free software; you can redistribute it and/or modify 8 This program is free software; you can redistribute it and/or modify
@@ -18,30 +20,36 @@
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/ 21*/
20 22
21/* This implements an i2c algorithm/adapter for ISA bus. Not that this is 23/* This implements an i2c-core-like thing for ISA hardware monitoring
22 on first sight very useful; almost no functionality is preserved. 24 chips. Such chips are linked to the i2c subsystem for historical
23 Except that it makes writing drivers for chips which can be on both 25 reasons (because the early ISA hardware monitoring chips such as the
24 the SMBus and the ISA bus very much easier. See lm78.c for an example 26 LM78 had both an I2C and an ISA interface). They used to be
25 of this. */ 27 registered with the main i2c-core, but as a first step in the
28 direction of a clean separation between I2C and ISA chip drivers,
29 we now have this separate core for ISA ones. It is significantly
30 more simple than the real one, of course, because we don't have to
31 handle multiple busses: there is only one (fake) ISA adapter.
32 It is worth noting that we still rely on i2c-core for some things
33 at the moment - but hopefully this won't last. */
26 34
27#include <linux/init.h> 35#include <linux/init.h>
28#include <linux/module.h> 36#include <linux/module.h>
29#include <linux/kernel.h> 37#include <linux/kernel.h>
30#include <linux/errno.h> 38#include <linux/errno.h>
31#include <linux/i2c.h> 39#include <linux/i2c.h>
40#include <linux/i2c-isa.h>
32 41
33static u32 isa_func(struct i2c_adapter *adapter); 42static u32 isa_func(struct i2c_adapter *adapter);
34 43
35/* This is the actual algorithm we define */ 44/* This is the actual algorithm we define */
36static struct i2c_algorithm isa_algorithm = { 45static struct i2c_algorithm isa_algorithm = {
37 .name = "ISA bus algorithm",
38 .id = I2C_ALGO_ISA,
39 .functionality = isa_func, 46 .functionality = isa_func,
40}; 47};
41 48
42/* There can only be one... */ 49/* There can only be one... */
43static struct i2c_adapter isa_adapter = { 50static struct i2c_adapter isa_adapter = {
44 .owner = THIS_MODULE, 51 .owner = THIS_MODULE,
52 .id = I2C_HW_ISA,
45 .class = I2C_CLASS_HWMON, 53 .class = I2C_CLASS_HWMON,
46 .algo = &isa_algorithm, 54 .algo = &isa_algorithm,
47 .name = "ISA main adapter", 55 .name = "ISA main adapter",
@@ -53,17 +61,146 @@ static u32 isa_func(struct i2c_adapter *adapter)
53 return 0; 61 return 0;
54} 62}
55 63
64
65/* Copied from i2c-core */
66static ssize_t show_adapter_name(struct device *dev,
67 struct device_attribute *attr, char *buf)
68{
69 struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
70 return sprintf(buf, "%s\n", adap->name);
71}
72static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
73
74static int i2c_isa_device_probe(struct device *dev)
75{
76 return -ENODEV;
77}
78
79static int i2c_isa_device_remove(struct device *dev)
80{
81 return 0;
82}
83
84
85/* We implement an interface which resembles i2c_{add,del}_driver,
86 but for i2c-isa drivers. We don't have to remember and handle lists
87 of drivers and adapters so this is much more simple, of course. */
88
89int i2c_isa_add_driver(struct i2c_driver *driver)
90{
91 int res;
92
93 /* Add the driver to the list of i2c drivers in the driver core */
94 driver->driver.name = driver->name;
95 driver->driver.bus = &i2c_bus_type;
96 driver->driver.probe = i2c_isa_device_probe;
97 driver->driver.remove = i2c_isa_device_remove;
98 res = driver_register(&driver->driver);
99 if (res)
100 return res;
101 dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->name);
102
103 /* Now look for clients */
104 driver->attach_adapter(&isa_adapter);
105
106 return 0;
107}
108
109int i2c_isa_del_driver(struct i2c_driver *driver)
110{
111 struct list_head *item, *_n;
112 struct i2c_client *client;
113 int res;
114
115 /* Detach all clients belonging to this one driver */
116 list_for_each_safe(item, _n, &isa_adapter.clients) {
117 client = list_entry(item, struct i2c_client, list);
118 if (client->driver != driver)
119 continue;
120 dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
121 client->name, client->addr);
122 if ((res = driver->detach_client(client))) {
123 dev_err(&isa_adapter.dev, "Failed, driver "
124 "%s not unregistered!\n",
125 driver->name);
126 return res;
127 }
128 }
129
130 /* Get the driver off the core list */
131 driver_unregister(&driver->driver);
132 dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->name);
133
134 return 0;
135}
136
137
56static int __init i2c_isa_init(void) 138static int __init i2c_isa_init(void)
57{ 139{
58 return i2c_add_adapter(&isa_adapter); 140 init_MUTEX(&isa_adapter.clist_lock);
141 INIT_LIST_HEAD(&isa_adapter.clients);
142
143 isa_adapter.nr = ANY_I2C_ISA_BUS;
144 isa_adapter.dev.parent = &platform_bus;
145 sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
146 isa_adapter.dev.driver = &i2c_adapter_driver;
147 isa_adapter.dev.release = &i2c_adapter_dev_release;
148 device_register(&isa_adapter.dev);
149 device_create_file(&isa_adapter.dev, &dev_attr_name);
150
151 /* Add this adapter to the i2c_adapter class */
152 memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
153 isa_adapter.class_dev.dev = &isa_adapter.dev;
154 isa_adapter.class_dev.class = &i2c_adapter_class;
155 strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
156 BUS_ID_SIZE);
157 class_device_register(&isa_adapter.class_dev);
158
159 dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
160
161 return 0;
59} 162}
60 163
61static void __exit i2c_isa_exit(void) 164static void __exit i2c_isa_exit(void)
62{ 165{
63 i2c_del_adapter(&isa_adapter); 166#ifdef DEBUG
167 struct list_head *item, *_n;
168 struct i2c_client *client = NULL;
169#endif
170
171 /* There should be no more active client */
172#ifdef DEBUG
173 dev_dbg(&isa_adapter.dev, "Looking for clients\n");
174 list_for_each_safe(item, _n, &isa_adapter.clients) {
175 client = list_entry(item, struct i2c_client, list);
176 dev_err(&isa_adapter.dev, "Driver %s still has an active "
177 "ISA client at 0x%x\n", client->driver->name,
178 client->addr);
179 }
180 if (client != NULL)
181 return;
182#endif
183
184 /* Clean up the sysfs representation */
185 dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
186 init_completion(&isa_adapter.dev_released);
187 init_completion(&isa_adapter.class_dev_released);
188 class_device_unregister(&isa_adapter.class_dev);
189 device_remove_file(&isa_adapter.dev, &dev_attr_name);
190 device_unregister(&isa_adapter.dev);
191
192 /* Wait for sysfs to drop all references */
193 dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
194 wait_for_completion(&isa_adapter.dev_released);
195 wait_for_completion(&isa_adapter.class_dev_released);
196
197 dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
64} 198}
65 199
66MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); 200EXPORT_SYMBOL(i2c_isa_add_driver);
201EXPORT_SYMBOL(i2c_isa_del_driver);
202
203MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
67MODULE_DESCRIPTION("ISA bus access through i2c"); 204MODULE_DESCRIPTION("ISA bus access through i2c");
68MODULE_LICENSE("GPL"); 205MODULE_LICENSE("GPL");
69 206