diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-mv64xxx.c')
-rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 133 |
1 files changed, 128 insertions, 5 deletions
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 4f44a33017b0..2e9d56719e99 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c | |||
@@ -18,6 +18,11 @@ | |||
18 | #include <linux/mv643xx_i2c.h> | 18 | #include <linux/mv643xx_i2c.h> |
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
21 | #include <linux/of.h> | ||
22 | #include <linux/of_irq.h> | ||
23 | #include <linux/of_i2c.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/err.h> | ||
21 | 26 | ||
22 | /* Register defines */ | 27 | /* Register defines */ |
23 | #define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 | 28 | #define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 |
@@ -98,6 +103,9 @@ struct mv64xxx_i2c_data { | |||
98 | int rc; | 103 | int rc; |
99 | u32 freq_m; | 104 | u32 freq_m; |
100 | u32 freq_n; | 105 | u32 freq_n; |
106 | #if defined(CONFIG_HAVE_CLK) | ||
107 | struct clk *clk; | ||
108 | #endif | ||
101 | wait_queue_head_t waitq; | 109 | wait_queue_head_t waitq; |
102 | spinlock_t lock; | 110 | spinlock_t lock; |
103 | struct i2c_msg *msg; | 111 | struct i2c_msg *msg; |
@@ -521,6 +529,82 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) | |||
521 | drv_data->reg_base_p = 0; | 529 | drv_data->reg_base_p = 0; |
522 | } | 530 | } |
523 | 531 | ||
532 | #ifdef CONFIG_OF | ||
533 | static int __devinit | ||
534 | mv64xxx_calc_freq(const int tclk, const int n, const int m) | ||
535 | { | ||
536 | return tclk / (10 * (m + 1) * (2 << n)); | ||
537 | } | ||
538 | |||
539 | static bool __devinit | ||
540 | mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n, | ||
541 | u32 *best_m) | ||
542 | { | ||
543 | int freq, delta, best_delta = INT_MAX; | ||
544 | int m, n; | ||
545 | |||
546 | for (n = 0; n <= 7; n++) | ||
547 | for (m = 0; m <= 15; m++) { | ||
548 | freq = mv64xxx_calc_freq(tclk, n, m); | ||
549 | delta = req_freq - freq; | ||
550 | if (delta >= 0 && delta < best_delta) { | ||
551 | *best_m = m; | ||
552 | *best_n = n; | ||
553 | best_delta = delta; | ||
554 | } | ||
555 | if (best_delta == 0) | ||
556 | return true; | ||
557 | } | ||
558 | if (best_delta == INT_MAX) | ||
559 | return false; | ||
560 | return true; | ||
561 | } | ||
562 | |||
563 | static int __devinit | ||
564 | mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, | ||
565 | struct device_node *np) | ||
566 | { | ||
567 | u32 bus_freq, tclk; | ||
568 | int rc = 0; | ||
569 | |||
570 | /* CLK is mandatory when using DT to describe the i2c bus. We | ||
571 | * need to know tclk in order to calculate bus clock | ||
572 | * factors. | ||
573 | */ | ||
574 | #if !defined(CONFIG_HAVE_CLK) | ||
575 | /* Have OF but no CLK */ | ||
576 | return -ENODEV; | ||
577 | #else | ||
578 | if (IS_ERR(drv_data->clk)) { | ||
579 | rc = -ENODEV; | ||
580 | goto out; | ||
581 | } | ||
582 | tclk = clk_get_rate(drv_data->clk); | ||
583 | of_property_read_u32(np, "clock-frequency", &bus_freq); | ||
584 | if (!mv64xxx_find_baud_factors(bus_freq, tclk, | ||
585 | &drv_data->freq_n, &drv_data->freq_m)) { | ||
586 | rc = -EINVAL; | ||
587 | goto out; | ||
588 | } | ||
589 | drv_data->irq = irq_of_parse_and_map(np, 0); | ||
590 | |||
591 | /* Its not yet defined how timeouts will be specified in device tree. | ||
592 | * So hard code the value to 1 second. | ||
593 | */ | ||
594 | drv_data->adapter.timeout = HZ; | ||
595 | out: | ||
596 | return rc; | ||
597 | #endif | ||
598 | } | ||
599 | #else /* CONFIG_OF */ | ||
600 | static int __devinit | ||
601 | mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, | ||
602 | struct device_node *np) | ||
603 | { | ||
604 | return -ENODEV; | ||
605 | } | ||
606 | #endif /* CONFIG_OF */ | ||
607 | |||
524 | static int __devinit | 608 | static int __devinit |
525 | mv64xxx_i2c_probe(struct platform_device *pd) | 609 | mv64xxx_i2c_probe(struct platform_device *pd) |
526 | { | 610 | { |
@@ -528,7 +612,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) | |||
528 | struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data; | 612 | struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data; |
529 | int rc; | 613 | int rc; |
530 | 614 | ||
531 | if ((pd->id != 0) || !pdata) | 615 | if ((!pdata && !pd->dev.of_node)) |
532 | return -ENODEV; | 616 | return -ENODEV; |
533 | 617 | ||
534 | drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); | 618 | drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); |
@@ -546,19 +630,35 @@ mv64xxx_i2c_probe(struct platform_device *pd) | |||
546 | init_waitqueue_head(&drv_data->waitq); | 630 | init_waitqueue_head(&drv_data->waitq); |
547 | spin_lock_init(&drv_data->lock); | 631 | spin_lock_init(&drv_data->lock); |
548 | 632 | ||
549 | drv_data->freq_m = pdata->freq_m; | 633 | #if defined(CONFIG_HAVE_CLK) |
550 | drv_data->freq_n = pdata->freq_n; | 634 | /* Not all platforms have a clk */ |
551 | drv_data->irq = platform_get_irq(pd, 0); | 635 | drv_data->clk = clk_get(&pd->dev, NULL); |
636 | if (!IS_ERR(drv_data->clk)) { | ||
637 | clk_prepare(drv_data->clk); | ||
638 | clk_enable(drv_data->clk); | ||
639 | } | ||
640 | #endif | ||
641 | if (pdata) { | ||
642 | drv_data->freq_m = pdata->freq_m; | ||
643 | drv_data->freq_n = pdata->freq_n; | ||
644 | drv_data->irq = platform_get_irq(pd, 0); | ||
645 | drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); | ||
646 | } else if (pd->dev.of_node) { | ||
647 | rc = mv64xxx_of_config(drv_data, pd->dev.of_node); | ||
648 | if (rc) | ||
649 | goto exit_unmap_regs; | ||
650 | } | ||
552 | if (drv_data->irq < 0) { | 651 | if (drv_data->irq < 0) { |
553 | rc = -ENXIO; | 652 | rc = -ENXIO; |
554 | goto exit_unmap_regs; | 653 | goto exit_unmap_regs; |
555 | } | 654 | } |
655 | |||
556 | drv_data->adapter.dev.parent = &pd->dev; | 656 | drv_data->adapter.dev.parent = &pd->dev; |
557 | drv_data->adapter.algo = &mv64xxx_i2c_algo; | 657 | drv_data->adapter.algo = &mv64xxx_i2c_algo; |
558 | drv_data->adapter.owner = THIS_MODULE; | 658 | drv_data->adapter.owner = THIS_MODULE; |
559 | drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; | 659 | drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; |
560 | drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); | ||
561 | drv_data->adapter.nr = pd->id; | 660 | drv_data->adapter.nr = pd->id; |
661 | drv_data->adapter.dev.of_node = pd->dev.of_node; | ||
562 | platform_set_drvdata(pd, drv_data); | 662 | platform_set_drvdata(pd, drv_data); |
563 | i2c_set_adapdata(&drv_data->adapter, drv_data); | 663 | i2c_set_adapdata(&drv_data->adapter, drv_data); |
564 | 664 | ||
@@ -577,11 +677,20 @@ mv64xxx_i2c_probe(struct platform_device *pd) | |||
577 | goto exit_free_irq; | 677 | goto exit_free_irq; |
578 | } | 678 | } |
579 | 679 | ||
680 | of_i2c_register_devices(&drv_data->adapter); | ||
681 | |||
580 | return 0; | 682 | return 0; |
581 | 683 | ||
582 | exit_free_irq: | 684 | exit_free_irq: |
583 | free_irq(drv_data->irq, drv_data); | 685 | free_irq(drv_data->irq, drv_data); |
584 | exit_unmap_regs: | 686 | exit_unmap_regs: |
687 | #if defined(CONFIG_HAVE_CLK) | ||
688 | /* Not all platforms have a clk */ | ||
689 | if (!IS_ERR(drv_data->clk)) { | ||
690 | clk_disable(drv_data->clk); | ||
691 | clk_unprepare(drv_data->clk); | ||
692 | } | ||
693 | #endif | ||
585 | mv64xxx_i2c_unmap_regs(drv_data); | 694 | mv64xxx_i2c_unmap_regs(drv_data); |
586 | exit_kfree: | 695 | exit_kfree: |
587 | kfree(drv_data); | 696 | kfree(drv_data); |
@@ -597,17 +706,31 @@ mv64xxx_i2c_remove(struct platform_device *dev) | |||
597 | rc = i2c_del_adapter(&drv_data->adapter); | 706 | rc = i2c_del_adapter(&drv_data->adapter); |
598 | free_irq(drv_data->irq, drv_data); | 707 | free_irq(drv_data->irq, drv_data); |
599 | mv64xxx_i2c_unmap_regs(drv_data); | 708 | mv64xxx_i2c_unmap_regs(drv_data); |
709 | #if defined(CONFIG_HAVE_CLK) | ||
710 | /* Not all platforms have a clk */ | ||
711 | if (!IS_ERR(drv_data->clk)) { | ||
712 | clk_disable(drv_data->clk); | ||
713 | clk_unprepare(drv_data->clk); | ||
714 | } | ||
715 | #endif | ||
600 | kfree(drv_data); | 716 | kfree(drv_data); |
601 | 717 | ||
602 | return rc; | 718 | return rc; |
603 | } | 719 | } |
604 | 720 | ||
721 | static const struct of_device_id mv64xxx_i2c_of_match_table[] __devinitdata = { | ||
722 | { .compatible = "marvell,mv64xxx-i2c", }, | ||
723 | {} | ||
724 | }; | ||
725 | MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); | ||
726 | |||
605 | static struct platform_driver mv64xxx_i2c_driver = { | 727 | static struct platform_driver mv64xxx_i2c_driver = { |
606 | .probe = mv64xxx_i2c_probe, | 728 | .probe = mv64xxx_i2c_probe, |
607 | .remove = __devexit_p(mv64xxx_i2c_remove), | 729 | .remove = __devexit_p(mv64xxx_i2c_remove), |
608 | .driver = { | 730 | .driver = { |
609 | .owner = THIS_MODULE, | 731 | .owner = THIS_MODULE, |
610 | .name = MV64XXX_I2C_CTLR_NAME, | 732 | .name = MV64XXX_I2C_CTLR_NAME, |
733 | .of_match_table = of_match_ptr(mv64xxx_i2c_of_match_table), | ||
611 | }, | 734 | }, |
612 | }; | 735 | }; |
613 | 736 | ||