blob: a2e75bc9178baaee69b1f85719d0dc9c91004599 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jean Delvare400c4552005-07-19 23:48:43 +02002 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 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
Jean Delvare400c4552005-07-19 23:48:43 +020023/* 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. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/init.h>
36#include <linux/module.h>
37#include <linux/kernel.h>
38#include <linux/errno.h>
39#include <linux/i2c.h>
Jean Delvare400c4552005-07-19 23:48:43 +020040#include <linux/i2c-isa.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010041#include <linux/platform_device.h>
Jean Delvareb8d6f452007-02-13 22:09:00 +010042#include <linux/completion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44static u32 isa_func(struct i2c_adapter *adapter);
45
46/* This is the actual algorithm we define */
Jean Delvare8f9082c2006-09-03 22:39:46 +020047static const struct i2c_algorithm isa_algorithm = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 .functionality = isa_func,
49};
50
51/* There can only be one... */
52static struct i2c_adapter isa_adapter = {
53 .owner = THIS_MODULE,
Jean Delvarec7a46532005-08-11 23:41:56 +020054 .id = I2C_HW_ISA,
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 .class = I2C_CLASS_HWMON,
56 .algo = &isa_algorithm,
57 .name = "ISA main adapter",
58};
59
60/* We can't do a thing... */
61static u32 isa_func(struct i2c_adapter *adapter)
62{
63 return 0;
64}
65
Jean Delvare400c4552005-07-19 23:48:43 +020066
67/* Copied from i2c-core */
68static ssize_t show_adapter_name(struct device *dev,
69 struct device_attribute *attr, char *buf)
70{
71 struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
72 return sprintf(buf, "%s\n", adap->name);
73}
74static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
75
Jean Delvare400c4552005-07-19 23:48:43 +020076
77/* We implement an interface which resembles i2c_{add,del}_driver,
78 but for i2c-isa drivers. We don't have to remember and handle lists
79 of drivers and adapters so this is much more simple, of course. */
80
81int i2c_isa_add_driver(struct i2c_driver *driver)
82{
83 int res;
84
85 /* Add the driver to the list of i2c drivers in the driver core */
Jean Delvare400c4552005-07-19 23:48:43 +020086 driver->driver.bus = &i2c_bus_type;
Jean Delvare400c4552005-07-19 23:48:43 +020087 res = driver_register(&driver->driver);
88 if (res)
89 return res;
Greg Kroah-Hartmane1c489b2005-11-30 16:35:09 -080090 dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
Jean Delvare400c4552005-07-19 23:48:43 +020091
92 /* Now look for clients */
David Hubbard82026322006-09-03 22:21:20 +020093 res = driver->attach_adapter(&isa_adapter);
94 if (res) {
Jean Delvaree6938102006-10-13 16:56:28 +020095 dev_dbg(&isa_adapter.dev,
David Hubbard82026322006-09-03 22:21:20 +020096 "Driver %s failed to attach adapter, unregistering\n",
97 driver->driver.name);
98 driver_unregister(&driver->driver);
99 }
100 return res;
Jean Delvare400c4552005-07-19 23:48:43 +0200101}
102
103int i2c_isa_del_driver(struct i2c_driver *driver)
104{
105 struct list_head *item, *_n;
106 struct i2c_client *client;
107 int res;
108
109 /* Detach all clients belonging to this one driver */
110 list_for_each_safe(item, _n, &isa_adapter.clients) {
111 client = list_entry(item, struct i2c_client, list);
112 if (client->driver != driver)
113 continue;
114 dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
115 client->name, client->addr);
116 if ((res = driver->detach_client(client))) {
117 dev_err(&isa_adapter.dev, "Failed, driver "
118 "%s not unregistered!\n",
Laurent Riffard35d8b2e2005-11-26 20:34:05 +0100119 driver->driver.name);
Jean Delvare400c4552005-07-19 23:48:43 +0200120 return res;
121 }
122 }
123
124 /* Get the driver off the core list */
125 driver_unregister(&driver->driver);
Greg Kroah-Hartmane1c489b2005-11-30 16:35:09 -0800126 dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->driver.name);
Jean Delvare400c4552005-07-19 23:48:43 +0200127
128 return 0;
129}
130
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static int __init i2c_isa_init(void)
133{
Jean Delvareb119c6c2006-08-15 18:26:30 +0200134 int err;
135
Ingo Molnar5c085d32006-01-18 23:16:04 +0100136 mutex_init(&isa_adapter.clist_lock);
Jean Delvare400c4552005-07-19 23:48:43 +0200137 INIT_LIST_HEAD(&isa_adapter.clients);
138
139 isa_adapter.nr = ANY_I2C_ISA_BUS;
140 isa_adapter.dev.parent = &platform_bus;
141 sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
142 isa_adapter.dev.driver = &i2c_adapter_driver;
143 isa_adapter.dev.release = &i2c_adapter_dev_release;
Jean Delvarefccb56e2007-05-01 23:26:27 +0200144 isa_adapter.dev.class = &i2c_adapter_class;
Jean Delvareb119c6c2006-08-15 18:26:30 +0200145 err = device_register(&isa_adapter.dev);
146 if (err) {
147 printk(KERN_ERR "i2c-isa: Failed to register device\n");
148 goto exit;
149 }
150 err = device_create_file(&isa_adapter.dev, &dev_attr_name);
151 if (err) {
152 printk(KERN_ERR "i2c-isa: Failed to create name file\n");
153 goto exit_unregister;
154 }
Jean Delvare400c4552005-07-19 23:48:43 +0200155
Jean Delvare400c4552005-07-19 23:48:43 +0200156 dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
157
158 return 0;
Jean Delvareb119c6c2006-08-15 18:26:30 +0200159
Jean Delvareb119c6c2006-08-15 18:26:30 +0200160exit_unregister:
161 init_completion(&isa_adapter.dev_released); /* Needed? */
162 device_unregister(&isa_adapter.dev);
163 wait_for_completion(&isa_adapter.dev_released);
164exit:
165 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166}
167
168static void __exit i2c_isa_exit(void)
169{
Jean Delvare400c4552005-07-19 23:48:43 +0200170#ifdef DEBUG
171 struct list_head *item, *_n;
172 struct i2c_client *client = NULL;
173#endif
174
175 /* There should be no more active client */
176#ifdef DEBUG
177 dev_dbg(&isa_adapter.dev, "Looking for clients\n");
178 list_for_each_safe(item, _n, &isa_adapter.clients) {
179 client = list_entry(item, struct i2c_client, list);
180 dev_err(&isa_adapter.dev, "Driver %s still has an active "
Greg Kroah-Hartmane1c489b2005-11-30 16:35:09 -0800181 "ISA client at 0x%x\n", client->driver->driver.name,
Jean Delvare400c4552005-07-19 23:48:43 +0200182 client->addr);
183 }
184 if (client != NULL)
185 return;
186#endif
187
188 /* Clean up the sysfs representation */
189 dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
190 init_completion(&isa_adapter.dev_released);
Jean Delvare400c4552005-07-19 23:48:43 +0200191 device_remove_file(&isa_adapter.dev, &dev_attr_name);
192 device_unregister(&isa_adapter.dev);
193
194 /* Wait for sysfs to drop all references */
195 dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
196 wait_for_completion(&isa_adapter.dev_released);
Jean Delvare400c4552005-07-19 23:48:43 +0200197
198 dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
Jean Delvare400c4552005-07-19 23:48:43 +0200201EXPORT_SYMBOL(i2c_isa_add_driver);
202EXPORT_SYMBOL(i2c_isa_del_driver);
203
204MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205MODULE_DESCRIPTION("ISA bus access through i2c");
206MODULE_LICENSE("GPL");
207
208module_init(i2c_isa_init);
209module_exit(i2c_isa_exit);