[PATCH] Add i2c_bus_type probe and remove methods
[linux-2.6] / drivers / i2c / busses / i2c-isa.c
1 /*
2     i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
3     Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
4
5     Based on the i2c-isa pseudo-adapter from the lm_sensors project
6     Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> 
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /* This implements an i2c-core-like thing for ISA hardware monitoring
24    chips. Such chips are linked to the i2c subsystem for historical
25    reasons (because the early ISA hardware monitoring chips such as the
26    LM78 had both an I2C and an ISA interface). They used to be
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. */
34
35 #include <linux/init.h>
36 #include <linux/module.h>
37 #include <linux/kernel.h>
38 #include <linux/errno.h>
39 #include <linux/i2c.h>
40 #include <linux/i2c-isa.h>
41 #include <linux/platform_device.h>
42
43 static u32 isa_func(struct i2c_adapter *adapter);
44
45 /* This is the actual algorithm we define */
46 static struct i2c_algorithm isa_algorithm = {
47         .functionality  = isa_func,
48 };
49
50 /* There can only be one... */
51 static struct i2c_adapter isa_adapter = {
52         .owner          = THIS_MODULE,
53         .id             = I2C_HW_ISA,
54         .class          = I2C_CLASS_HWMON,
55         .algo           = &isa_algorithm,
56         .name           = "ISA main adapter",
57 };
58
59 /* We can't do a thing... */
60 static u32 isa_func(struct i2c_adapter *adapter)
61 {
62         return 0;
63 }
64
65
66 /* Copied from i2c-core */
67 static ssize_t show_adapter_name(struct device *dev,
68                 struct device_attribute *attr, char *buf)
69 {
70         struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
71         return sprintf(buf, "%s\n", adap->name);
72 }
73 static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
74
75 static int i2c_isa_device_probe(struct device *dev)
76 {
77         return -ENODEV;
78 }
79
80 static int i2c_isa_device_remove(struct device *dev)
81 {
82         return 0;
83 }
84
85
86 /* We implement an interface which resembles i2c_{add,del}_driver,
87    but for i2c-isa drivers. We don't have to remember and handle lists
88    of drivers and adapters so this is much more simple, of course. */
89
90 int i2c_isa_add_driver(struct i2c_driver *driver)
91 {
92         int res;
93
94         /* Add the driver to the list of i2c drivers in the driver core */
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->driver.name);
102
103         /* Now look for clients */
104         driver->attach_adapter(&isa_adapter);
105
106         return 0;
107 }
108
109 int 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->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->driver.name);
133
134         return 0;
135 }
136
137
138 static int __init i2c_isa_init(void)
139 {
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;
162 }
163
164 static void __exit i2c_isa_exit(void)
165 {
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->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);
198 }
199
200 EXPORT_SYMBOL(i2c_isa_add_driver);
201 EXPORT_SYMBOL(i2c_isa_del_driver);
202
203 MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
204 MODULE_DESCRIPTION("ISA bus access through i2c");
205 MODULE_LICENSE("GPL");
206
207 module_init(i2c_isa_init);
208 module_exit(i2c_isa_exit);