diff options
author | Jean Delvare <khali@linux-fr.org> | 2007-05-01 17:26:30 -0400 |
---|---|---|
committer | Jean Delvare <khali@hyperion.delvare> | 2007-05-01 17:26:30 -0400 |
commit | c6e8bb2ca5e50547557650c9251d24f55a8f4cfb (patch) | |
tree | db938575bff15cbda1c6e4f0b63e062a926fc7e2 | |
parent | 3af07bd297b6ba3d77474fdb3b2656dd3f0404d5 (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.c | 144 |
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 | |||
40 | static struct platform_device *pdev; | ||
37 | 41 | ||
38 | static u16 base; | 42 | static u16 base; |
39 | module_param(base, ushort, 0); | 43 | module_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 | ||
111 | static struct i2c_adapter parport_adapter = { | 115 | static 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 ------------------------ */ | 123 | static 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 | |||
147 | exit_region: | ||
148 | release_region(res->start, res->end - res->start + 1); | ||
149 | return err; | ||
150 | } | ||
151 | |||
152 | static 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 | |||
167 | static 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 | |||
176 | static 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 | |||
209 | exit_device_put: | ||
210 | platform_device_put(pdev); | ||
211 | exit: | ||
212 | return err; | ||
213 | } | ||
120 | 214 | ||
121 | static int __init i2c_parport_init(void) | 215 | static 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 | |||
248 | exit_device: | ||
249 | platform_device_unregister(pdev); | ||
250 | exit: | ||
251 | return err; | ||
158 | } | 252 | } |
159 | 253 | ||
160 | static void __exit i2c_parport_exit(void) | 254 | static 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 | ||
170 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); | 260 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); |