diff options
Diffstat (limited to 'drivers/clocksource/sh_cmt.c')
-rw-r--r-- | drivers/clocksource/sh_cmt.c | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 08d0c418c94a..0965e9848b3d 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | struct sh_cmt_priv { | 38 | struct sh_cmt_priv { |
39 | void __iomem *mapbase; | 39 | void __iomem *mapbase; |
40 | void __iomem *mapbase_str; | ||
40 | struct clk *clk; | 41 | struct clk *clk; |
41 | unsigned long width; /* 16 or 32 bit version of hardware block */ | 42 | unsigned long width; /* 16 or 32 bit version of hardware block */ |
42 | unsigned long overflow_bit; | 43 | unsigned long overflow_bit; |
@@ -79,6 +80,12 @@ struct sh_cmt_priv { | |||
79 | * CMCSR 0xffca0060 16-bit | 80 | * CMCSR 0xffca0060 16-bit |
80 | * CMCNT 0xffca0064 32-bit | 81 | * CMCNT 0xffca0064 32-bit |
81 | * CMCOR 0xffca0068 32-bit | 82 | * CMCOR 0xffca0068 32-bit |
83 | * | ||
84 | * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790: | ||
85 | * CMSTR 0xffca0500 32-bit | ||
86 | * CMCSR 0xffca0510 32-bit | ||
87 | * CMCNT 0xffca0514 32-bit | ||
88 | * CMCOR 0xffca0518 32-bit | ||
82 | */ | 89 | */ |
83 | 90 | ||
84 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) | 91 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) |
@@ -109,9 +116,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs, | |||
109 | 116 | ||
110 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) | 117 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) |
111 | { | 118 | { |
112 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 119 | return p->read_control(p->mapbase_str, 0); |
113 | |||
114 | return p->read_control(p->mapbase - cfg->channel_offset, 0); | ||
115 | } | 120 | } |
116 | 121 | ||
117 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) | 122 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) |
@@ -127,9 +132,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p) | |||
127 | static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, | 132 | static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, |
128 | unsigned long value) | 133 | unsigned long value) |
129 | { | 134 | { |
130 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 135 | p->write_control(p->mapbase_str, 0, value); |
131 | |||
132 | p->write_control(p->mapbase - cfg->channel_offset, 0, value); | ||
133 | } | 136 | } |
134 | 137 | ||
135 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, | 138 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, |
@@ -676,7 +679,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name, | |||
676 | static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | 679 | static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) |
677 | { | 680 | { |
678 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 681 | struct sh_timer_config *cfg = pdev->dev.platform_data; |
679 | struct resource *res; | 682 | struct resource *res, *res2; |
680 | int irq, ret; | 683 | int irq, ret; |
681 | ret = -ENXIO; | 684 | ret = -ENXIO; |
682 | 685 | ||
@@ -694,6 +697,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
694 | goto err0; | 697 | goto err0; |
695 | } | 698 | } |
696 | 699 | ||
700 | /* optional resource for the shared timer start/stop register */ | ||
701 | res2 = platform_get_resource(p->pdev, IORESOURCE_MEM, 1); | ||
702 | |||
697 | irq = platform_get_irq(p->pdev, 0); | 703 | irq = platform_get_irq(p->pdev, 0); |
698 | if (irq < 0) { | 704 | if (irq < 0) { |
699 | dev_err(&p->pdev->dev, "failed to get irq\n"); | 705 | dev_err(&p->pdev->dev, "failed to get irq\n"); |
@@ -707,6 +713,15 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
707 | goto err0; | 713 | goto err0; |
708 | } | 714 | } |
709 | 715 | ||
716 | /* map second resource for CMSTR */ | ||
717 | p->mapbase_str = ioremap_nocache(res2 ? res2->start : | ||
718 | res->start - cfg->channel_offset, | ||
719 | res2 ? resource_size(res2) : 2); | ||
720 | if (p->mapbase_str == NULL) { | ||
721 | dev_err(&p->pdev->dev, "failed to remap I/O second memory\n"); | ||
722 | goto err1; | ||
723 | } | ||
724 | |||
710 | /* request irq using setup_irq() (too early for request_irq()) */ | 725 | /* request irq using setup_irq() (too early for request_irq()) */ |
711 | p->irqaction.name = dev_name(&p->pdev->dev); | 726 | p->irqaction.name = dev_name(&p->pdev->dev); |
712 | p->irqaction.handler = sh_cmt_interrupt; | 727 | p->irqaction.handler = sh_cmt_interrupt; |
@@ -719,11 +734,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
719 | if (IS_ERR(p->clk)) { | 734 | if (IS_ERR(p->clk)) { |
720 | dev_err(&p->pdev->dev, "cannot get clock\n"); | 735 | dev_err(&p->pdev->dev, "cannot get clock\n"); |
721 | ret = PTR_ERR(p->clk); | 736 | ret = PTR_ERR(p->clk); |
722 | goto err1; | 737 | goto err2; |
723 | } | 738 | } |
724 | 739 | ||
725 | p->read_control = sh_cmt_read16; | 740 | if (res2 && (resource_size(res2) == 4)) { |
726 | p->write_control = sh_cmt_write16; | 741 | /* assume both CMSTR and CMCSR to be 32-bit */ |
742 | p->read_control = sh_cmt_read32; | ||
743 | p->write_control = sh_cmt_write32; | ||
744 | } else { | ||
745 | p->read_control = sh_cmt_read16; | ||
746 | p->write_control = sh_cmt_write16; | ||
747 | } | ||
727 | 748 | ||
728 | if (resource_size(res) == 6) { | 749 | if (resource_size(res) == 6) { |
729 | p->width = 16; | 750 | p->width = 16; |
@@ -752,22 +773,23 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
752 | cfg->clocksource_rating); | 773 | cfg->clocksource_rating); |
753 | if (ret) { | 774 | if (ret) { |
754 | dev_err(&p->pdev->dev, "registration failed\n"); | 775 | dev_err(&p->pdev->dev, "registration failed\n"); |
755 | goto err2; | 776 | goto err3; |
756 | } | 777 | } |
757 | p->cs_enabled = false; | 778 | p->cs_enabled = false; |
758 | 779 | ||
759 | ret = setup_irq(irq, &p->irqaction); | 780 | ret = setup_irq(irq, &p->irqaction); |
760 | if (ret) { | 781 | if (ret) { |
761 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); | 782 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); |
762 | goto err2; | 783 | goto err3; |
763 | } | 784 | } |
764 | 785 | ||
765 | platform_set_drvdata(pdev, p); | 786 | platform_set_drvdata(pdev, p); |
766 | 787 | ||
767 | return 0; | 788 | return 0; |
768 | err2: | 789 | err3: |
769 | clk_put(p->clk); | 790 | clk_put(p->clk); |
770 | 791 | err2: | |
792 | iounmap(p->mapbase_str); | ||
771 | err1: | 793 | err1: |
772 | iounmap(p->mapbase); | 794 | iounmap(p->mapbase); |
773 | err0: | 795 | err0: |