diff options
author | Ben Dooks <ben-linux@fluff.org> | 2011-01-12 17:24:51 -0500 |
---|---|---|
committer | Ben Dooks <ben-linux@fluff.org> | 2011-01-12 17:24:51 -0500 |
commit | c5ba47ba7f3810adf4974ed4fe7134327333130d (patch) | |
tree | 59866b36bfbfc1a763b3c0e1354ed0119a711e91 /drivers/i2c | |
parent | 084b7c83830fab95bd686e2b0b5321dec0300a96 (diff) | |
parent | d9240e612ba79287e29f2eac52f94a2016fb0914 (diff) |
Merge branch 'for-2638/i2c/ocores' into for-linus/i2c-2638
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-ocores.c | 145 |
1 files changed, 102 insertions, 43 deletions
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 0070371b29f3..ef3bcb1ce864 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c | |||
@@ -9,6 +9,41 @@ | |||
9 | * kind, whether express or implied. | 9 | * kind, whether express or implied. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | ||
13 | * Device tree configuration: | ||
14 | * | ||
15 | * Required properties: | ||
16 | * - compatible : "opencores,i2c-ocores" | ||
17 | * - reg : bus address start and address range size of device | ||
18 | * - interrupts : interrupt number | ||
19 | * - regstep : size of device registers in bytes | ||
20 | * - clock-frequency : frequency of bus clock in Hz | ||
21 | * | ||
22 | * Example: | ||
23 | * | ||
24 | * i2c0: ocores@a0000000 { | ||
25 | * compatible = "opencores,i2c-ocores"; | ||
26 | * reg = <0xa0000000 0x8>; | ||
27 | * interrupts = <10>; | ||
28 | * | ||
29 | * regstep = <1>; | ||
30 | * clock-frequency = <20000000>; | ||
31 | * | ||
32 | * -- Devices connected on this I2C bus get | ||
33 | * -- defined here; address- and size-cells | ||
34 | * -- apply to these child devices | ||
35 | * | ||
36 | * #address-cells = <1>; | ||
37 | * #size-cells = <0>; | ||
38 | * | ||
39 | * dummy@60 { | ||
40 | * compatible = "dummy"; | ||
41 | * reg = <60>; | ||
42 | * }; | ||
43 | * }; | ||
44 | * | ||
45 | */ | ||
46 | |||
12 | #include <linux/kernel.h> | 47 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 48 | #include <linux/module.h> |
14 | #include <linux/init.h> | 49 | #include <linux/init.h> |
@@ -210,6 +245,32 @@ static struct i2c_adapter ocores_adapter = { | |||
210 | .algo = &ocores_algorithm, | 245 | .algo = &ocores_algorithm, |
211 | }; | 246 | }; |
212 | 247 | ||
248 | #ifdef CONFIG_OF | ||
249 | static int ocores_i2c_of_probe(struct platform_device* pdev, | ||
250 | struct ocores_i2c* i2c) | ||
251 | { | ||
252 | __be32* val; | ||
253 | |||
254 | val = of_get_property(pdev->dev.of_node, "regstep", NULL); | ||
255 | if (!val) { | ||
256 | dev_err(&pdev->dev, "Missing required parameter 'regstep'"); | ||
257 | return -ENODEV; | ||
258 | } | ||
259 | i2c->regstep = be32_to_cpup(val); | ||
260 | |||
261 | val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL); | ||
262 | if (!val) { | ||
263 | dev_err(&pdev->dev, | ||
264 | "Missing required parameter 'clock-frequency'"); | ||
265 | return -ENODEV; | ||
266 | } | ||
267 | i2c->clock_khz = be32_to_cpup(val) / 1000; | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | #else | ||
272 | #define ocores_i2c_of_probe(pdev,i2c) -ENODEV | ||
273 | #endif | ||
213 | 274 | ||
214 | static int __devinit ocores_i2c_probe(struct platform_device *pdev) | 275 | static int __devinit ocores_i2c_probe(struct platform_device *pdev) |
215 | { | 276 | { |
@@ -227,37 +288,41 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) | |||
227 | if (!res2) | 288 | if (!res2) |
228 | return -ENODEV; | 289 | return -ENODEV; |
229 | 290 | ||
230 | pdata = (struct ocores_i2c_platform_data*) pdev->dev.platform_data; | 291 | i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); |
231 | if (!pdata) | ||
232 | return -ENODEV; | ||
233 | |||
234 | i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); | ||
235 | if (!i2c) | 292 | if (!i2c) |
236 | return -ENOMEM; | 293 | return -ENOMEM; |
237 | 294 | ||
238 | if (!request_mem_region(res->start, resource_size(res), | 295 | if (!devm_request_mem_region(&pdev->dev, res->start, |
239 | pdev->name)) { | 296 | resource_size(res), pdev->name)) { |
240 | dev_err(&pdev->dev, "Memory region busy\n"); | 297 | dev_err(&pdev->dev, "Memory region busy\n"); |
241 | ret = -EBUSY; | 298 | return -EBUSY; |
242 | goto request_mem_failed; | ||
243 | } | 299 | } |
244 | 300 | ||
245 | i2c->base = ioremap(res->start, resource_size(res)); | 301 | i2c->base = devm_ioremap_nocache(&pdev->dev, res->start, |
302 | resource_size(res)); | ||
246 | if (!i2c->base) { | 303 | if (!i2c->base) { |
247 | dev_err(&pdev->dev, "Unable to map registers\n"); | 304 | dev_err(&pdev->dev, "Unable to map registers\n"); |
248 | ret = -EIO; | 305 | return -EIO; |
249 | goto map_failed; | 306 | } |
307 | |||
308 | pdata = pdev->dev.platform_data; | ||
309 | if (pdata) { | ||
310 | i2c->regstep = pdata->regstep; | ||
311 | i2c->clock_khz = pdata->clock_khz; | ||
312 | } else { | ||
313 | ret = ocores_i2c_of_probe(pdev, i2c); | ||
314 | if (ret) | ||
315 | return ret; | ||
250 | } | 316 | } |
251 | 317 | ||
252 | i2c->regstep = pdata->regstep; | ||
253 | i2c->clock_khz = pdata->clock_khz; | ||
254 | ocores_init(i2c); | 318 | ocores_init(i2c); |
255 | 319 | ||
256 | init_waitqueue_head(&i2c->wait); | 320 | init_waitqueue_head(&i2c->wait); |
257 | ret = request_irq(res2->start, ocores_isr, 0, pdev->name, i2c); | 321 | ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0, |
322 | pdev->name, i2c); | ||
258 | if (ret) { | 323 | if (ret) { |
259 | dev_err(&pdev->dev, "Cannot claim IRQ\n"); | 324 | dev_err(&pdev->dev, "Cannot claim IRQ\n"); |
260 | goto request_irq_failed; | 325 | return ret; |
261 | } | 326 | } |
262 | 327 | ||
263 | /* hook up driver to tree */ | 328 | /* hook up driver to tree */ |
@@ -265,36 +330,29 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) | |||
265 | i2c->adap = ocores_adapter; | 330 | i2c->adap = ocores_adapter; |
266 | i2c_set_adapdata(&i2c->adap, i2c); | 331 | i2c_set_adapdata(&i2c->adap, i2c); |
267 | i2c->adap.dev.parent = &pdev->dev; | 332 | i2c->adap.dev.parent = &pdev->dev; |
333 | #ifdef CONFIG_OF | ||
334 | i2c->adap.dev.of_node = pdev->dev.of_node; | ||
335 | #endif | ||
268 | 336 | ||
269 | /* add i2c adapter to i2c tree */ | 337 | /* add i2c adapter to i2c tree */ |
270 | ret = i2c_add_adapter(&i2c->adap); | 338 | ret = i2c_add_adapter(&i2c->adap); |
271 | if (ret) { | 339 | if (ret) { |
272 | dev_err(&pdev->dev, "Failed to add adapter\n"); | 340 | dev_err(&pdev->dev, "Failed to add adapter\n"); |
273 | goto add_adapter_failed; | 341 | return ret; |
274 | } | 342 | } |
275 | 343 | ||
276 | /* add in known devices to the bus */ | 344 | /* add in known devices to the bus */ |
277 | for (i = 0; i < pdata->num_devices; i++) | 345 | if (pdata) { |
278 | i2c_new_device(&i2c->adap, pdata->devices + i); | 346 | for (i = 0; i < pdata->num_devices; i++) |
347 | i2c_new_device(&i2c->adap, pdata->devices + i); | ||
348 | } | ||
279 | 349 | ||
280 | return 0; | 350 | return 0; |
281 | |||
282 | add_adapter_failed: | ||
283 | free_irq(res2->start, i2c); | ||
284 | request_irq_failed: | ||
285 | iounmap(i2c->base); | ||
286 | map_failed: | ||
287 | release_mem_region(res->start, resource_size(res)); | ||
288 | request_mem_failed: | ||
289 | kfree(i2c); | ||
290 | |||
291 | return ret; | ||
292 | } | 351 | } |
293 | 352 | ||
294 | static int __devexit ocores_i2c_remove(struct platform_device* pdev) | 353 | static int __devexit ocores_i2c_remove(struct platform_device* pdev) |
295 | { | 354 | { |
296 | struct ocores_i2c *i2c = platform_get_drvdata(pdev); | 355 | struct ocores_i2c *i2c = platform_get_drvdata(pdev); |
297 | struct resource *res; | ||
298 | 356 | ||
299 | /* disable i2c logic */ | 357 | /* disable i2c logic */ |
300 | oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL) | 358 | oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL) |
@@ -304,18 +362,6 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev) | |||
304 | i2c_del_adapter(&i2c->adap); | 362 | i2c_del_adapter(&i2c->adap); |
305 | platform_set_drvdata(pdev, NULL); | 363 | platform_set_drvdata(pdev, NULL); |
306 | 364 | ||
307 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
308 | if (res) | ||
309 | free_irq(res->start, i2c); | ||
310 | |||
311 | iounmap(i2c->base); | ||
312 | |||
313 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
314 | if (res) | ||
315 | release_mem_region(res->start, resource_size(res)); | ||
316 | |||
317 | kfree(i2c); | ||
318 | |||
319 | return 0; | 365 | return 0; |
320 | } | 366 | } |
321 | 367 | ||
@@ -344,6 +390,16 @@ static int ocores_i2c_resume(struct platform_device *pdev) | |||
344 | #define ocores_i2c_resume NULL | 390 | #define ocores_i2c_resume NULL |
345 | #endif | 391 | #endif |
346 | 392 | ||
393 | #ifdef CONFIG_OF | ||
394 | static struct of_device_id ocores_i2c_match[] = { | ||
395 | { | ||
396 | .compatible = "opencores,i2c-ocores", | ||
397 | }, | ||
398 | {}, | ||
399 | }; | ||
400 | MODULE_DEVICE_TABLE(of, ocores_i2c_match); | ||
401 | #endif | ||
402 | |||
347 | /* work with hotplug and coldplug */ | 403 | /* work with hotplug and coldplug */ |
348 | MODULE_ALIAS("platform:ocores-i2c"); | 404 | MODULE_ALIAS("platform:ocores-i2c"); |
349 | 405 | ||
@@ -355,6 +411,9 @@ static struct platform_driver ocores_i2c_driver = { | |||
355 | .driver = { | 411 | .driver = { |
356 | .owner = THIS_MODULE, | 412 | .owner = THIS_MODULE, |
357 | .name = "ocores-i2c", | 413 | .name = "ocores-i2c", |
414 | #ifdef CONFIG_OF | ||
415 | .of_match_table = ocores_i2c_match, | ||
416 | #endif | ||
358 | }, | 417 | }, |
359 | }; | 418 | }; |
360 | 419 | ||