diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-sh_mobile.c')
-rw-r--r-- | drivers/i2c/busses/i2c-sh_mobile.c | 43 |
1 files changed, 27 insertions, 16 deletions
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 598c49acaeb5..f633a53b6dbe 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/clk.h> | 32 | #include <linux/clk.h> |
33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/i2c/i2c-sh_mobile.h> | ||
35 | 36 | ||
36 | /* Transmit operation: */ | 37 | /* Transmit operation: */ |
37 | /* */ | 38 | /* */ |
@@ -117,7 +118,7 @@ struct sh_mobile_i2c_data { | |||
117 | struct device *dev; | 118 | struct device *dev; |
118 | void __iomem *reg; | 119 | void __iomem *reg; |
119 | struct i2c_adapter adap; | 120 | struct i2c_adapter adap; |
120 | 121 | unsigned long bus_speed; | |
121 | struct clk *clk; | 122 | struct clk *clk; |
122 | u_int8_t icic; | 123 | u_int8_t icic; |
123 | u_int8_t iccl; | 124 | u_int8_t iccl; |
@@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) | |||
205 | * We also round off the result. | 206 | * We also round off the result. |
206 | */ | 207 | */ |
207 | num = i2c_clk * 5; | 208 | num = i2c_clk * 5; |
208 | denom = NORMAL_SPEED * 9; | 209 | denom = pd->bus_speed * 9; |
209 | tmp = num * 10 / denom; | 210 | tmp = num * 10 / denom; |
210 | if (tmp % 10 >= 5) | 211 | if (tmp % 10 >= 5) |
211 | pd->iccl = (u_int8_t)((num/denom) + 1); | 212 | pd->iccl = (u_int8_t)((num/denom) + 1); |
@@ -538,15 +539,17 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) | |||
538 | { | 539 | { |
539 | struct resource *res; | 540 | struct resource *res; |
540 | int ret = -ENXIO; | 541 | int ret = -ENXIO; |
541 | int q, m; | 542 | int n, k = 0; |
542 | int k = 0; | ||
543 | int n = 0; | ||
544 | 543 | ||
545 | while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { | 544 | while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { |
546 | for (n = res->start; hook && n <= res->end; n++) { | 545 | for (n = res->start; hook && n <= res->end; n++) { |
547 | if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED, | 546 | if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED, |
548 | dev_name(&dev->dev), dev)) | 547 | dev_name(&dev->dev), dev)) { |
548 | for (n--; n >= res->start; n--) | ||
549 | free_irq(n, dev); | ||
550 | |||
549 | goto rollback; | 551 | goto rollback; |
552 | } | ||
550 | } | 553 | } |
551 | k++; | 554 | k++; |
552 | } | 555 | } |
@@ -554,16 +557,17 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) | |||
554 | if (hook) | 557 | if (hook) |
555 | return k > 0 ? 0 : -ENOENT; | 558 | return k > 0 ? 0 : -ENOENT; |
556 | 559 | ||
557 | k--; | ||
558 | ret = 0; | 560 | ret = 0; |
559 | 561 | ||
560 | rollback: | 562 | rollback: |
561 | for (q = k; k >= 0; k--) { | 563 | k--; |
562 | for (m = n; m >= res->start; m--) | 564 | |
563 | free_irq(m, dev); | 565 | while (k >= 0) { |
566 | res = platform_get_resource(dev, IORESOURCE_IRQ, k); | ||
567 | for (n = res->start; n <= res->end; n++) | ||
568 | free_irq(n, dev); | ||
564 | 569 | ||
565 | res = platform_get_resource(dev, IORESOURCE_IRQ, k - 1); | 570 | k--; |
566 | m = res->end; | ||
567 | } | 571 | } |
568 | 572 | ||
569 | return ret; | 573 | return ret; |
@@ -571,10 +575,10 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) | |||
571 | 575 | ||
572 | static int sh_mobile_i2c_probe(struct platform_device *dev) | 576 | static int sh_mobile_i2c_probe(struct platform_device *dev) |
573 | { | 577 | { |
578 | struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data; | ||
574 | struct sh_mobile_i2c_data *pd; | 579 | struct sh_mobile_i2c_data *pd; |
575 | struct i2c_adapter *adap; | 580 | struct i2c_adapter *adap; |
576 | struct resource *res; | 581 | struct resource *res; |
577 | char clk_name[8]; | ||
578 | int size; | 582 | int size; |
579 | int ret; | 583 | int ret; |
580 | 584 | ||
@@ -584,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) | |||
584 | return -ENOMEM; | 588 | return -ENOMEM; |
585 | } | 589 | } |
586 | 590 | ||
587 | snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id); | 591 | pd->clk = clk_get(&dev->dev, NULL); |
588 | pd->clk = clk_get(&dev->dev, clk_name); | ||
589 | if (IS_ERR(pd->clk)) { | 592 | if (IS_ERR(pd->clk)) { |
590 | dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name); | 593 | dev_err(&dev->dev, "cannot get clock\n"); |
591 | ret = PTR_ERR(pd->clk); | 594 | ret = PTR_ERR(pd->clk); |
592 | goto err; | 595 | goto err; |
593 | } | 596 | } |
@@ -617,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) | |||
617 | goto err_irq; | 620 | goto err_irq; |
618 | } | 621 | } |
619 | 622 | ||
623 | /* Use platformd data bus speed or NORMAL_SPEED */ | ||
624 | pd->bus_speed = NORMAL_SPEED; | ||
625 | if (pdata && pdata->bus_speed) | ||
626 | pd->bus_speed = pdata->bus_speed; | ||
627 | |||
620 | /* The IIC blocks on SH-Mobile ARM processors | 628 | /* The IIC blocks on SH-Mobile ARM processors |
621 | * come with two new bits in ICIC. | 629 | * come with two new bits in ICIC. |
622 | */ | 630 | */ |
@@ -657,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) | |||
657 | goto err_all; | 665 | goto err_all; |
658 | } | 666 | } |
659 | 667 | ||
668 | dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n", | ||
669 | adap->nr, pd->bus_speed); | ||
660 | return 0; | 670 | return 0; |
661 | 671 | ||
662 | err_all: | 672 | err_all: |
@@ -726,3 +736,4 @@ module_exit(sh_mobile_i2c_adap_exit); | |||
726 | MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver"); | 736 | MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver"); |
727 | MODULE_AUTHOR("Magnus Damm"); | 737 | MODULE_AUTHOR("Magnus Damm"); |
728 | MODULE_LICENSE("GPL v2"); | 738 | MODULE_LICENSE("GPL v2"); |
739 | MODULE_ALIAS("platform:i2c-sh_mobile"); | ||