diff options
author | Marco Aurelio da Costa <costa@gamic.com> | 2009-03-28 16:34:44 -0400 |
---|---|---|
committer | Jean Delvare <khali@linux-fr.org> | 2009-03-28 16:34:44 -0400 |
commit | eff9ec95efaaf6b12d230f0ea7d3c295d3bc9d57 (patch) | |
tree | 741c1ec65283018583bc2a8d5577e3ce8c201994 /drivers | |
parent | bac3e7c2aa2575a1c71f6fa643499676ca7c12c3 (diff) |
i2c-algo-pca: Add PCA9665 support
Add support for the PCA9665 I2C controller.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/algos/i2c-algo-pca.c | 180 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 8 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pca-isa.c | 14 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pca-platform.c | 9 |
4 files changed, 185 insertions, 26 deletions
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 943d70ee5d59..a8e51bd1a4f5 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c | |||
@@ -46,6 +46,14 @@ static int i2c_debug; | |||
46 | #define pca_wait(adap) adap->wait_for_completion(adap->data) | 46 | #define pca_wait(adap) adap->wait_for_completion(adap->data) |
47 | #define pca_reset(adap) adap->reset_chip(adap->data) | 47 | #define pca_reset(adap) adap->reset_chip(adap->data) |
48 | 48 | ||
49 | static void pca9665_reset(void *pd) | ||
50 | { | ||
51 | struct i2c_algo_pca_data *adap = pd; | ||
52 | pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); | ||
53 | pca_outw(adap, I2C_PCA_IND, 0xA5); | ||
54 | pca_outw(adap, I2C_PCA_IND, 0x5A); | ||
55 | } | ||
56 | |||
49 | /* | 57 | /* |
50 | * Generate a start condition on the i2c bus. | 58 | * Generate a start condition on the i2c bus. |
51 | * | 59 | * |
@@ -333,27 +341,171 @@ static const struct i2c_algorithm pca_algo = { | |||
333 | .functionality = pca_func, | 341 | .functionality = pca_func, |
334 | }; | 342 | }; |
335 | 343 | ||
336 | static int pca_init(struct i2c_adapter *adap) | 344 | static unsigned int pca_probe_chip(struct i2c_adapter *adap) |
337 | { | 345 | { |
338 | static int freqs[] = {330,288,217,146,88,59,44,36}; | ||
339 | int clock; | ||
340 | struct i2c_algo_pca_data *pca_data = adap->algo_data; | 346 | struct i2c_algo_pca_data *pca_data = adap->algo_data; |
341 | 347 | /* The trick here is to check if there is an indirect register | |
342 | if (pca_data->i2c_clock > 7) { | 348 | * available. If there is one, we will read the value we first |
343 | printk(KERN_WARNING "%s: Invalid I2C clock speed selected. Trying default.\n", | 349 | * wrote on I2C_PCA_IADR. Otherwise, we will read the last value |
344 | adap->name); | 350 | * we wrote on I2C_PCA_ADR |
345 | pca_data->i2c_clock = I2C_PCA_CON_59kHz; | 351 | */ |
352 | pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); | ||
353 | pca_outw(pca_data, I2C_PCA_IND, 0xAA); | ||
354 | pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ITO); | ||
355 | pca_outw(pca_data, I2C_PCA_IND, 0x00); | ||
356 | pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR); | ||
357 | if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) { | ||
358 | printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); | ||
359 | return I2C_PCA_CHIP_9665; | ||
360 | } else { | ||
361 | printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); | ||
362 | return I2C_PCA_CHIP_9564; | ||
346 | } | 363 | } |
364 | } | ||
365 | |||
366 | static int pca_init(struct i2c_adapter *adap) | ||
367 | { | ||
368 | struct i2c_algo_pca_data *pca_data = adap->algo_data; | ||
347 | 369 | ||
348 | adap->algo = &pca_algo; | 370 | adap->algo = &pca_algo; |
349 | 371 | ||
350 | pca_reset(pca_data); | 372 | if (pca_probe_chip(adap) == I2C_PCA_CHIP_9564) { |
373 | static int freqs[] = {330, 288, 217, 146, 88, 59, 44, 36}; | ||
374 | int clock; | ||
375 | |||
376 | if (pca_data->i2c_clock > 7) { | ||
377 | switch (pca_data->i2c_clock) { | ||
378 | case 330000: | ||
379 | pca_data->i2c_clock = I2C_PCA_CON_330kHz; | ||
380 | break; | ||
381 | case 288000: | ||
382 | pca_data->i2c_clock = I2C_PCA_CON_288kHz; | ||
383 | break; | ||
384 | case 217000: | ||
385 | pca_data->i2c_clock = I2C_PCA_CON_217kHz; | ||
386 | break; | ||
387 | case 146000: | ||
388 | pca_data->i2c_clock = I2C_PCA_CON_146kHz; | ||
389 | break; | ||
390 | case 88000: | ||
391 | pca_data->i2c_clock = I2C_PCA_CON_88kHz; | ||
392 | break; | ||
393 | case 59000: | ||
394 | pca_data->i2c_clock = I2C_PCA_CON_59kHz; | ||
395 | break; | ||
396 | case 44000: | ||
397 | pca_data->i2c_clock = I2C_PCA_CON_44kHz; | ||
398 | break; | ||
399 | case 36000: | ||
400 | pca_data->i2c_clock = I2C_PCA_CON_36kHz; | ||
401 | break; | ||
402 | default: | ||
403 | printk(KERN_WARNING | ||
404 | "%s: Invalid I2C clock speed selected." | ||
405 | " Using default 59kHz.\n", adap->name); | ||
406 | pca_data->i2c_clock = I2C_PCA_CON_59kHz; | ||
407 | } | ||
408 | } else { | ||
409 | printk(KERN_WARNING "%s: " | ||
410 | "Choosing the clock frequency based on " | ||
411 | "index is deprecated." | ||
412 | " Use the nominal frequency.\n", adap->name); | ||
413 | } | ||
414 | |||
415 | pca_reset(pca_data); | ||
416 | |||
417 | clock = pca_clock(pca_data); | ||
418 | printk(KERN_INFO "%s: Clock frequency is %dkHz\n", | ||
419 | adap->name, freqs[clock]); | ||
420 | |||
421 | pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock); | ||
422 | } else { | ||
423 | int clock; | ||
424 | int mode; | ||
425 | int tlow, thi; | ||
426 | /* Values can be found on PCA9665 datasheet section 7.3.2.6 */ | ||
427 | int min_tlow, min_thi; | ||
428 | /* These values are the maximum raise and fall values allowed | ||
429 | * by the I2C operation mode (Standard, Fast or Fast+) | ||
430 | * They are used (added) below to calculate the clock dividers | ||
431 | * of PCA9665. Note that they are slightly different of the | ||
432 | * real maximum, to allow the change on mode exactly on the | ||
433 | * maximum clock rate for each mode | ||
434 | */ | ||
435 | int raise_fall_time; | ||
436 | |||
437 | struct i2c_algo_pca_data *pca_data = adap->algo_data; | ||
438 | |||
439 | /* Ignore the reset function from the module, | ||
440 | * we can use the parallel bus reset | ||
441 | */ | ||
442 | pca_data->reset_chip = pca9665_reset; | ||
443 | |||
444 | if (pca_data->i2c_clock > 1265800) { | ||
445 | printk(KERN_WARNING "%s: I2C clock speed too high." | ||
446 | " Using 1265.8kHz.\n", adap->name); | ||
447 | pca_data->i2c_clock = 1265800; | ||
448 | } | ||
449 | |||
450 | if (pca_data->i2c_clock < 60300) { | ||
451 | printk(KERN_WARNING "%s: I2C clock speed too low." | ||
452 | " Using 60.3kHz.\n", adap->name); | ||
453 | pca_data->i2c_clock = 60300; | ||
454 | } | ||
455 | |||
456 | /* To avoid integer overflow, use clock/100 for calculations */ | ||
457 | clock = pca_clock(pca_data) / 100; | ||
458 | |||
459 | if (pca_data->i2c_clock > 10000) { | ||
460 | mode = I2C_PCA_MODE_TURBO; | ||
461 | min_tlow = 14; | ||
462 | min_thi = 5; | ||
463 | raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ | ||
464 | } else if (pca_data->i2c_clock > 4000) { | ||
465 | mode = I2C_PCA_MODE_FASTP; | ||
466 | min_tlow = 17; | ||
467 | min_thi = 9; | ||
468 | raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */ | ||
469 | } else if (pca_data->i2c_clock > 1000) { | ||
470 | mode = I2C_PCA_MODE_FAST; | ||
471 | min_tlow = 44; | ||
472 | min_thi = 20; | ||
473 | raise_fall_time = 58; /* Raise 29e-8s, Fall 29e-8s */ | ||
474 | } else { | ||
475 | mode = I2C_PCA_MODE_STD; | ||
476 | min_tlow = 157; | ||
477 | min_thi = 134; | ||
478 | raise_fall_time = 127; /* Raise 29e-8s, Fall 98e-8s */ | ||
479 | } | ||
480 | |||
481 | /* The minimum clock that respects the thi/tlow = 134/157 is | ||
482 | * 64800 Hz. Below that, we have to fix the tlow to 255 and | ||
483 | * calculate the thi factor. | ||
484 | */ | ||
485 | if (clock < 648) { | ||
486 | tlow = 255; | ||
487 | thi = 1000000 - clock * raise_fall_time; | ||
488 | thi /= (I2C_PCA_OSC_PER * clock) - tlow; | ||
489 | } else { | ||
490 | tlow = (1000000 - clock * raise_fall_time) * min_tlow; | ||
491 | tlow /= I2C_PCA_OSC_PER * clock * (min_thi + min_tlow); | ||
492 | thi = tlow * min_thi / min_tlow; | ||
493 | } | ||
494 | |||
495 | pca_reset(pca_data); | ||
351 | 496 | ||
352 | clock = pca_clock(pca_data); | 497 | printk(KERN_INFO |
353 | printk(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, | 498 | "%s: Clock frequency is %dHz\n", adap->name, clock * 100); |
354 | freqs[clock]); | ||
355 | 499 | ||
356 | pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock); | 500 | pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IMODE); |
501 | pca_outw(pca_data, I2C_PCA_IND, mode); | ||
502 | pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLL); | ||
503 | pca_outw(pca_data, I2C_PCA_IND, tlow); | ||
504 | pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLH); | ||
505 | pca_outw(pca_data, I2C_PCA_IND, thi); | ||
506 | |||
507 | pca_set_con(pca_data, I2C_PCA_CON_ENSIO); | ||
508 | } | ||
357 | udelay(500); /* 500 us for oscilator to stabilise */ | 509 | udelay(500); /* 500 us for oscilator to stabilise */ |
358 | 510 | ||
359 | return 0; | 511 | return 0; |
@@ -388,7 +540,7 @@ EXPORT_SYMBOL(i2c_pca_add_numbered_bus); | |||
388 | 540 | ||
389 | MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, " | 541 | MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, " |
390 | "Wolfram Sang <w.sang@pengutronix.de>"); | 542 | "Wolfram Sang <w.sang@pengutronix.de>"); |
391 | MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm"); | 543 | MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm"); |
392 | MODULE_LICENSE("GPL"); | 544 | MODULE_LICENSE("GPL"); |
393 | 545 | ||
394 | module_param(i2c_debug, int, 0); | 546 | module_param(i2c_debug, int, 0); |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 7f95905bbb9d..68650643d116 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -617,12 +617,12 @@ config I2C_ELEKTOR | |||
617 | will be called i2c-elektor. | 617 | will be called i2c-elektor. |
618 | 618 | ||
619 | config I2C_PCA_ISA | 619 | config I2C_PCA_ISA |
620 | tristate "PCA9564 on an ISA bus" | 620 | tristate "PCA9564/PCA9665 on an ISA bus" |
621 | depends on ISA | 621 | depends on ISA |
622 | select I2C_ALGOPCA | 622 | select I2C_ALGOPCA |
623 | default n | 623 | default n |
624 | help | 624 | help |
625 | This driver supports ISA boards using the Philips PCA9564 | 625 | This driver supports ISA boards using the Philips PCA9564/PCA9665 |
626 | parallel bus to I2C bus controller. | 626 | parallel bus to I2C bus controller. |
627 | 627 | ||
628 | This driver can also be built as a module. If so, the module | 628 | This driver can also be built as a module. If so, the module |
@@ -634,11 +634,11 @@ config I2C_PCA_ISA | |||
634 | time). If unsure, say N. | 634 | time). If unsure, say N. |
635 | 635 | ||
636 | config I2C_PCA_PLATFORM | 636 | config I2C_PCA_PLATFORM |
637 | tristate "PCA9564 as platform device" | 637 | tristate "PCA9564/PCA9665 as platform device" |
638 | select I2C_ALGOPCA | 638 | select I2C_ALGOPCA |
639 | default n | 639 | default n |
640 | help | 640 | help |
641 | This driver supports a memory mapped Philips PCA9564 | 641 | This driver supports a memory mapped Philips PCA9564/PCA9665 |
642 | parallel bus to I2C bus controller. | 642 | parallel bus to I2C bus controller. |
643 | 643 | ||
644 | This driver can also be built as a module. If so, the module | 644 | This driver can also be built as a module. If so, the module |
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index c420a7c0f3e4..0cc8017b3f64 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c | |||
@@ -41,7 +41,7 @@ static int irq = -1; | |||
41 | 41 | ||
42 | /* Data sheet recommends 59kHz for 100kHz operation due to variation | 42 | /* Data sheet recommends 59kHz for 100kHz operation due to variation |
43 | * in the actual clock rate */ | 43 | * in the actual clock rate */ |
44 | static int clock = I2C_PCA_CON_59kHz; | 44 | static int clock = 59000; |
45 | 45 | ||
46 | static wait_queue_head_t pca_wait; | 46 | static wait_queue_head_t pca_wait; |
47 | 47 | ||
@@ -103,7 +103,7 @@ static struct i2c_algo_pca_data pca_isa_data = { | |||
103 | static struct i2c_adapter pca_isa_ops = { | 103 | static struct i2c_adapter pca_isa_ops = { |
104 | .owner = THIS_MODULE, | 104 | .owner = THIS_MODULE, |
105 | .algo_data = &pca_isa_data, | 105 | .algo_data = &pca_isa_data, |
106 | .name = "PCA9564 ISA Adapter", | 106 | .name = "PCA9564/PCA9665 ISA Adapter", |
107 | .timeout = 100, | 107 | .timeout = 100, |
108 | }; | 108 | }; |
109 | 109 | ||
@@ -196,7 +196,7 @@ static void __exit pca_isa_exit(void) | |||
196 | } | 196 | } |
197 | 197 | ||
198 | MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>"); | 198 | MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>"); |
199 | MODULE_DESCRIPTION("ISA base PCA9564 driver"); | 199 | MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver"); |
200 | MODULE_LICENSE("GPL"); | 200 | MODULE_LICENSE("GPL"); |
201 | 201 | ||
202 | module_param(base, ulong, 0); | 202 | module_param(base, ulong, 0); |
@@ -205,7 +205,13 @@ MODULE_PARM_DESC(base, "I/O base address"); | |||
205 | module_param(irq, int, 0); | 205 | module_param(irq, int, 0); |
206 | MODULE_PARM_DESC(irq, "IRQ"); | 206 | MODULE_PARM_DESC(irq, "IRQ"); |
207 | module_param(clock, int, 0); | 207 | module_param(clock, int, 0); |
208 | MODULE_PARM_DESC(clock, "Clock rate as described in table 1 of PCA9564 datasheet"); | 208 | MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t" |
209 | "For PCA9564: 330000,288000,217000,146000," | ||
210 | "88000,59000,44000,36000\n" | ||
211 | "\t\tFor PCA9665:\tStandard: 60300 - 100099\n" | ||
212 | "\t\t\t\tFast: 100100 - 400099\n" | ||
213 | "\t\t\t\tFast+: 400100 - 10000099\n" | ||
214 | "\t\t\t\tTurbo: Up to 1265800"); | ||
209 | 215 | ||
210 | module_init(pca_isa_init); | 216 | module_init(pca_isa_init); |
211 | module_exit(pca_isa_exit); | 217 | module_exit(pca_isa_exit); |
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index 6bb15ad0a6b6..51d179bbddf9 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c | |||
@@ -172,8 +172,9 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev) | |||
172 | 172 | ||
173 | i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; | 173 | i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; |
174 | i2c->adap.owner = THIS_MODULE; | 174 | i2c->adap.owner = THIS_MODULE; |
175 | snprintf(i2c->adap.name, sizeof(i2c->adap.name), "PCA9564 at 0x%08lx", | 175 | snprintf(i2c->adap.name, sizeof(i2c->adap.name), |
176 | (unsigned long) res->start); | 176 | "PCA9564/PCA9665 at 0x%08lx", |
177 | (unsigned long) res->start); | ||
177 | i2c->adap.algo_data = &i2c->algo_data; | 178 | i2c->adap.algo_data = &i2c->algo_data; |
178 | i2c->adap.dev.parent = &pdev->dev; | 179 | i2c->adap.dev.parent = &pdev->dev; |
179 | i2c->adap.timeout = platform_data->timeout; | 180 | i2c->adap.timeout = platform_data->timeout; |
@@ -246,7 +247,7 @@ e_remap: | |||
246 | e_alloc: | 247 | e_alloc: |
247 | release_mem_region(res->start, res_len(res)); | 248 | release_mem_region(res->start, res_len(res)); |
248 | e_print: | 249 | e_print: |
249 | printk(KERN_ERR "Registering PCA9564 FAILED! (%d)\n", ret); | 250 | printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret); |
250 | return ret; | 251 | return ret; |
251 | } | 252 | } |
252 | 253 | ||
@@ -290,7 +291,7 @@ static void __exit i2c_pca_pf_exit(void) | |||
290 | } | 291 | } |
291 | 292 | ||
292 | MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); | 293 | MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); |
293 | MODULE_DESCRIPTION("I2C-PCA9564 platform driver"); | 294 | MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver"); |
294 | MODULE_LICENSE("GPL"); | 295 | MODULE_LICENSE("GPL"); |
295 | 296 | ||
296 | module_init(i2c_pca_pf_init); | 297 | module_init(i2c_pca_pf_init); |