aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2007-05-01 17:26:30 -0400
committerJean Delvare <khali@hyperion.delvare>2007-05-01 17:26:30 -0400
commitc6e8bb2ca5e50547557650c9251d24f55a8f4cfb (patch)
treedb938575bff15cbda1c6e4f0b63e062a926fc7e2
parent3af07bd297b6ba3d77474fdb3b2656dd3f0404d5 (diff)
i2c-parport-light: Port to the new device driver model
Also fix a small race on driver unload: we need to unregister the i2c adapter before we power it off. Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c144
1 files changed, 117 insertions, 27 deletions
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 4bc42810b9aa..49a95e2887bc 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -1,7 +1,7 @@
1/* ------------------------------------------------------------------------ * 1/* ------------------------------------------------------------------------ *
2 * i2c-parport.c I2C bus over parallel port * 2 * i2c-parport-light.c I2C bus over parallel port *
3 * ------------------------------------------------------------------------ * 3 * ------------------------------------------------------------------------ *
4 Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org> 4 Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
5 5
6 Based on older i2c-velleman.c driver 6 Based on older i2c-velleman.c driver
7 Copyright (C) 1995-2000 Simon G. Vogl 7 Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,6 +27,7 @@
27#include <linux/kernel.h> 27#include <linux/kernel.h>
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/init.h> 29#include <linux/init.h>
30#include <linux/platform_device.h>
30#include <linux/ioport.h> 31#include <linux/ioport.h>
31#include <linux/i2c.h> 32#include <linux/i2c.h>
32#include <linux/i2c-algo-bit.h> 33#include <linux/i2c-algo-bit.h>
@@ -34,6 +35,9 @@
34#include "i2c-parport.h" 35#include "i2c-parport.h"
35 36
36#define DEFAULT_BASE 0x378 37#define DEFAULT_BASE 0x378
38#define DRVNAME "i2c-parport-light"
39
40static struct platform_device *pdev;
37 41
38static u16 base; 42static u16 base;
39module_param(base, ushort, 0); 43module_param(base, ushort, 0);
@@ -106,7 +110,7 @@ static struct i2c_algo_bit_data parport_algo_data = {
106 .timeout = HZ, 110 .timeout = HZ,
107}; 111};
108 112
109/* ----- I2c structure ---------------------------------------------------- */ 113/* ----- Driver registration ---------------------------------------------- */
110 114
111static struct i2c_adapter parport_adapter = { 115static struct i2c_adapter parport_adapter = {
112 .owner = THIS_MODULE, 116 .owner = THIS_MODULE,
@@ -116,55 +120,141 @@ static struct i2c_adapter parport_adapter = {
116 .name = "Parallel port adapter (light)", 120 .name = "Parallel port adapter (light)",
117}; 121};
118 122
119/* ----- Module loading, unloading and information ------------------------ */ 123static int __devinit i2c_parport_probe(struct platform_device *pdev)
124{
125 int err;
126 struct resource *res;
127
128 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
129 if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
130 return -EBUSY;
131
132 /* Reset hardware to a sane state (SCL and SDA high) */
133 parport_setsda(NULL, 1);
134 parport_setscl(NULL, 1);
135 /* Other init if needed (power on...) */
136 if (adapter_parm[type].init.val)
137 line_set(1, &adapter_parm[type].init);
138
139 parport_adapter.dev.parent = &pdev->dev;
140 err = i2c_bit_add_bus(&parport_adapter);
141 if (err) {
142 dev_err(&pdev->dev, "Unable to register with I2C\n");
143 goto exit_region;
144 }
145 return 0;
146
147exit_region:
148 release_region(res->start, res->end - res->start + 1);
149 return err;
150}
151
152static int __devexit i2c_parport_remove(struct platform_device *pdev)
153{
154 struct resource *res;
155
156 i2c_del_adapter(&parport_adapter);
157
158 /* Un-init if needed (power off...) */
159 if (adapter_parm[type].init.val)
160 line_set(0, &adapter_parm[type].init);
161
162 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
163 release_region(res->start, res->end - res->start + 1);
164 return 0;
165}
166
167static struct platform_driver i2c_parport_driver = {
168 .driver = {
169 .owner = THIS_MODULE,
170 .name = DRVNAME,
171 },
172 .probe = i2c_parport_probe,
173 .remove = __devexit_p(i2c_parport_remove),
174};
175
176static int __init i2c_parport_device_add(u16 address)
177{
178 struct resource res = {
179 .start = address,
180 .end = address + 2,
181 .name = DRVNAME,
182 .flags = IORESOURCE_IO,
183 };
184 int err;
185
186 pdev = platform_device_alloc(DRVNAME, -1);
187 if (!pdev) {
188 err = -ENOMEM;
189 printk(KERN_ERR DRVNAME ": Device allocation failed\n");
190 goto exit;
191 }
192
193 err = platform_device_add_resources(pdev, &res, 1);
194 if (err) {
195 printk(KERN_ERR DRVNAME ": Device resource addition failed "
196 "(%d)\n", err);
197 goto exit_device_put;
198 }
199
200 err = platform_device_add(pdev);
201 if (err) {
202 printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
203 err);
204 goto exit_device_put;
205 }
206
207 return 0;
208
209exit_device_put:
210 platform_device_put(pdev);
211exit:
212 return err;
213}
120 214
121static int __init i2c_parport_init(void) 215static int __init i2c_parport_init(void)
122{ 216{
217 int err;
218
123 if (type < 0) { 219 if (type < 0) {
124 printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); 220 printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
125 return -ENODEV; 221 return -ENODEV;
126 } 222 }
127 223
128 if (type >= ARRAY_SIZE(adapter_parm)) { 224 if (type >= ARRAY_SIZE(adapter_parm)) {
129 printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); 225 printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
130 return -ENODEV; 226 return -ENODEV;
131 } 227 }
132 228
133 if (base == 0) { 229 if (base == 0) {
134 printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE); 230 pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
135 base = DEFAULT_BASE; 231 base = DEFAULT_BASE;
136 } 232 }
137 233
138 if (!request_region(base, 3, "i2c-parport"))
139 return -ENODEV;
140
141 if (!adapter_parm[type].getscl.val) 234 if (!adapter_parm[type].getscl.val)
142 parport_algo_data.getscl = NULL; 235 parport_algo_data.getscl = NULL;
143 236
144 /* Reset hardware to a sane state (SCL and SDA high) */ 237 /* Sets global pdev as a side effect */
145 parport_setsda(NULL, 1); 238 err = i2c_parport_device_add(base);
146 parport_setscl(NULL, 1); 239 if (err)
147 /* Other init if needed (power on...) */ 240 goto exit;
148 if (adapter_parm[type].init.val)
149 line_set(1, &adapter_parm[type].init);
150 241
151 if (i2c_bit_add_bus(&parport_adapter) < 0) { 242 err = platform_driver_register(&i2c_parport_driver);
152 printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); 243 if (err)
153 release_region(base, 3); 244 goto exit_device;
154 return -ENODEV;
155 }
156 245
157 return 0; 246 return 0;
247
248exit_device:
249 platform_device_unregister(pdev);
250exit:
251 return err;
158} 252}
159 253
160static void __exit i2c_parport_exit(void) 254static void __exit i2c_parport_exit(void)
161{ 255{
162 /* Un-init if needed (power off...) */ 256 platform_driver_unregister(&i2c_parport_driver);
163 if (adapter_parm[type].init.val) 257 platform_device_unregister(pdev);
164 line_set(0, &adapter_parm[type].init);
165
166 i2c_del_adapter(&parport_adapter);
167 release_region(base, 3);
168} 258}
169 259
170MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); 260MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");