diff options
| -rw-r--r-- | drivers/i2c/busses/i2c-davinci.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 7afeb28d6d76..352b4e7bdd9e 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
| 37 | #include <linux/io.h> | 37 | #include <linux/io.h> |
| 38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
| 39 | #include <linux/cpufreq.h> | ||
| 39 | 40 | ||
| 40 | #include <mach/hardware.h> | 41 | #include <mach/hardware.h> |
| 41 | #include <mach/i2c.h> | 42 | #include <mach/i2c.h> |
| @@ -107,6 +108,10 @@ struct davinci_i2c_dev { | |||
| 107 | int stop; | 108 | int stop; |
| 108 | u8 terminate; | 109 | u8 terminate; |
| 109 | struct i2c_adapter adapter; | 110 | struct i2c_adapter adapter; |
| 111 | #ifdef CONFIG_CPU_FREQ | ||
| 112 | struct completion xfr_complete; | ||
| 113 | struct notifier_block freq_transition; | ||
| 114 | #endif | ||
| 110 | }; | 115 | }; |
| 111 | 116 | ||
| 112 | /* default platform data to use if not supplied in the platform_device */ | 117 | /* default platform data to use if not supplied in the platform_device */ |
| @@ -391,6 +396,11 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | |||
| 391 | if (ret < 0) | 396 | if (ret < 0) |
| 392 | return ret; | 397 | return ret; |
| 393 | } | 398 | } |
| 399 | |||
| 400 | #ifdef CONFIG_CPU_FREQ | ||
| 401 | complete(&dev->xfr_complete); | ||
| 402 | #endif | ||
| 403 | |||
| 394 | return num; | 404 | return num; |
| 395 | } | 405 | } |
| 396 | 406 | ||
| @@ -523,6 +533,48 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) | |||
| 523 | return count ? IRQ_HANDLED : IRQ_NONE; | 533 | return count ? IRQ_HANDLED : IRQ_NONE; |
| 524 | } | 534 | } |
| 525 | 535 | ||
| 536 | #ifdef CONFIG_CPU_FREQ | ||
| 537 | static int i2c_davinci_cpufreq_transition(struct notifier_block *nb, | ||
| 538 | unsigned long val, void *data) | ||
| 539 | { | ||
| 540 | struct davinci_i2c_dev *dev; | ||
| 541 | |||
| 542 | dev = container_of(nb, struct davinci_i2c_dev, freq_transition); | ||
| 543 | if (val == CPUFREQ_PRECHANGE) { | ||
| 544 | wait_for_completion(&dev->xfr_complete); | ||
| 545 | davinci_i2c_reset_ctrl(dev, 0); | ||
| 546 | } else if (val == CPUFREQ_POSTCHANGE) { | ||
| 547 | i2c_davinci_calc_clk_dividers(dev); | ||
| 548 | davinci_i2c_reset_ctrl(dev, 1); | ||
| 549 | } | ||
| 550 | |||
| 551 | return 0; | ||
| 552 | } | ||
| 553 | |||
| 554 | static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev) | ||
| 555 | { | ||
| 556 | dev->freq_transition.notifier_call = i2c_davinci_cpufreq_transition; | ||
| 557 | |||
| 558 | return cpufreq_register_notifier(&dev->freq_transition, | ||
| 559 | CPUFREQ_TRANSITION_NOTIFIER); | ||
| 560 | } | ||
| 561 | |||
| 562 | static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev) | ||
| 563 | { | ||
| 564 | cpufreq_unregister_notifier(&dev->freq_transition, | ||
| 565 | CPUFREQ_TRANSITION_NOTIFIER); | ||
| 566 | } | ||
| 567 | #else | ||
| 568 | static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev) | ||
| 569 | { | ||
| 570 | return 0; | ||
| 571 | } | ||
| 572 | |||
| 573 | static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev) | ||
| 574 | { | ||
| 575 | } | ||
| 576 | #endif | ||
| 577 | |||
| 526 | static struct i2c_algorithm i2c_davinci_algo = { | 578 | static struct i2c_algorithm i2c_davinci_algo = { |
| 527 | .master_xfer = i2c_davinci_xfer, | 579 | .master_xfer = i2c_davinci_xfer, |
| 528 | .functionality = i2c_davinci_func, | 580 | .functionality = i2c_davinci_func, |
| @@ -562,6 +614,9 @@ static int davinci_i2c_probe(struct platform_device *pdev) | |||
| 562 | } | 614 | } |
| 563 | 615 | ||
| 564 | init_completion(&dev->cmd_complete); | 616 | init_completion(&dev->cmd_complete); |
| 617 | #ifdef CONFIG_CPU_FREQ | ||
| 618 | init_completion(&dev->xfr_complete); | ||
| 619 | #endif | ||
| 565 | dev->dev = get_device(&pdev->dev); | 620 | dev->dev = get_device(&pdev->dev); |
| 566 | dev->irq = irq->start; | 621 | dev->irq = irq->start; |
| 567 | platform_set_drvdata(pdev, dev); | 622 | platform_set_drvdata(pdev, dev); |
| @@ -587,6 +642,12 @@ static int davinci_i2c_probe(struct platform_device *pdev) | |||
| 587 | goto err_unuse_clocks; | 642 | goto err_unuse_clocks; |
| 588 | } | 643 | } |
| 589 | 644 | ||
| 645 | r = i2c_davinci_cpufreq_register(dev); | ||
| 646 | if (r) { | ||
| 647 | dev_err(&pdev->dev, "failed to register cpufreq\n"); | ||
| 648 | goto err_free_irq; | ||
| 649 | } | ||
| 650 | |||
| 590 | adap = &dev->adapter; | 651 | adap = &dev->adapter; |
| 591 | i2c_set_adapdata(adap, dev); | 652 | i2c_set_adapdata(adap, dev); |
| 592 | adap->owner = THIS_MODULE; | 653 | adap->owner = THIS_MODULE; |
| @@ -628,6 +689,8 @@ static int davinci_i2c_remove(struct platform_device *pdev) | |||
| 628 | struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); | 689 | struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); |
| 629 | struct resource *mem; | 690 | struct resource *mem; |
| 630 | 691 | ||
| 692 | i2c_davinci_cpufreq_deregister(dev); | ||
| 693 | |||
| 631 | platform_set_drvdata(pdev, NULL); | 694 | platform_set_drvdata(pdev, NULL); |
| 632 | i2c_del_adapter(&dev->adapter); | 695 | i2c_del_adapter(&dev->adapter); |
| 633 | put_device(&pdev->dev); | 696 | put_device(&pdev->dev); |
