diff options
| author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2014-02-11 17:46:48 -0500 |
|---|---|---|
| committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2014-04-16 06:03:10 -0400 |
| commit | 2cda3ac49d5744432e9ebffb8ba47bef6eca053d (patch) | |
| tree | 1869cd0f7a392e8cfdb0e09dd06becba4e3008c3 /drivers/clocksource | |
| parent | f5ec9b194a93c05e2ccdb3e90d9061cfedc806d9 (diff) | |
clocksource: sh_cmt: Split static information from sh_cmt_device
Create a new sh_cmt_info structure to hold static information about the
device model and reference that structure from the sh_cmt_device
structure.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/sh_cmt.c | 192 |
1 files changed, 122 insertions, 70 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index f94db327ac7c..879b8c2ae556 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
| @@ -37,6 +37,52 @@ | |||
| 37 | 37 | ||
| 38 | struct sh_cmt_device; | 38 | struct sh_cmt_device; |
| 39 | 39 | ||
| 40 | /* | ||
| 41 | * The CMT comes in 5 different identified flavours, depending not only on the | ||
| 42 | * SoC but also on the particular instance. The following table lists the main | ||
| 43 | * characteristics of those flavours. | ||
| 44 | * | ||
| 45 | * 16B 32B 32B-F 48B 48B-2 | ||
| 46 | * ----------------------------------------------------------------------------- | ||
| 47 | * Channels 2 1/4 1 6 2/8 | ||
| 48 | * Control Width 16 16 16 16 32 | ||
| 49 | * Counter Width 16 32 32 32/48 32/48 | ||
| 50 | * Shared Start/Stop Y Y Y Y N | ||
| 51 | * | ||
| 52 | * The 48-bit gen2 version has a per-channel start/stop register located in the | ||
| 53 | * channel registers block. All other versions have a shared start/stop register | ||
| 54 | * located in the global space. | ||
| 55 | * | ||
| 56 | * Note that CMT0 on r8a73a4, r8a7790 and r8a7791, while implementing 32-bit | ||
| 57 | * channels only, is a 48-bit gen2 CMT with the 48-bit channels unavailable. | ||
| 58 | */ | ||
| 59 | |||
| 60 | enum sh_cmt_model { | ||
| 61 | SH_CMT_16BIT, | ||
| 62 | SH_CMT_32BIT, | ||
| 63 | SH_CMT_32BIT_FAST, | ||
| 64 | SH_CMT_48BIT, | ||
| 65 | SH_CMT_48BIT_GEN2, | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct sh_cmt_info { | ||
| 69 | enum sh_cmt_model model; | ||
| 70 | |||
| 71 | unsigned long width; /* 16 or 32 bit version of hardware block */ | ||
| 72 | unsigned long overflow_bit; | ||
| 73 | unsigned long clear_bits; | ||
| 74 | |||
| 75 | /* callbacks for CMSTR and CMCSR access */ | ||
| 76 | unsigned long (*read_control)(void __iomem *base, unsigned long offs); | ||
| 77 | void (*write_control)(void __iomem *base, unsigned long offs, | ||
| 78 | unsigned long value); | ||
| 79 | |||
| 80 | /* callbacks for CMCNT and CMCOR access */ | ||
| 81 | unsigned long (*read_count)(void __iomem *base, unsigned long offs); | ||
| 82 | void (*write_count)(void __iomem *base, unsigned long offs, | ||
| 83 | unsigned long value); | ||
| 84 | }; | ||
| 85 | |||
| 40 | struct sh_cmt_channel { | 86 | struct sh_cmt_channel { |
| 41 | struct sh_cmt_device *cmt; | 87 | struct sh_cmt_device *cmt; |
| 42 | unsigned int index; | 88 | unsigned int index; |
| @@ -58,49 +104,16 @@ struct sh_cmt_channel { | |||
| 58 | struct sh_cmt_device { | 104 | struct sh_cmt_device { |
| 59 | struct platform_device *pdev; | 105 | struct platform_device *pdev; |
| 60 | 106 | ||
| 107 | const struct sh_cmt_info *info; | ||
| 108 | |||
| 61 | void __iomem *mapbase_ch; | 109 | void __iomem *mapbase_ch; |
| 62 | void __iomem *mapbase; | 110 | void __iomem *mapbase; |
| 63 | struct clk *clk; | 111 | struct clk *clk; |
| 64 | 112 | ||
| 65 | struct sh_cmt_channel *channels; | 113 | struct sh_cmt_channel *channels; |
| 66 | unsigned int num_channels; | 114 | unsigned int num_channels; |
| 67 | |||
| 68 | unsigned long width; /* 16 or 32 bit version of hardware block */ | ||
| 69 | unsigned long overflow_bit; | ||
| 70 | unsigned long clear_bits; | ||
| 71 | |||
| 72 | /* callbacks for CMSTR and CMCSR access */ | ||
| 73 | unsigned long (*read_control)(void __iomem *base, unsigned long offs); | ||
| 74 | void (*write_control)(void __iomem *base, unsigned long offs, | ||
| 75 | unsigned long value); | ||
| 76 | |||
| 77 | /* callbacks for CMCNT and CMCOR access */ | ||
| 78 | unsigned long (*read_count)(void __iomem *base, unsigned long offs); | ||
| 79 | void (*write_count)(void __iomem *base, unsigned long offs, | ||
| 80 | unsigned long value); | ||
| 81 | }; | 115 | }; |
| 82 | 116 | ||
| 83 | /* Examples of supported CMT timer register layouts and I/O access widths: | ||
| 84 | * | ||
| 85 | * "16-bit counter and 16-bit control" as found on sh7263: | ||
| 86 | * CMSTR 0xfffec000 16-bit | ||
| 87 | * CMCSR 0xfffec002 16-bit | ||
| 88 | * CMCNT 0xfffec004 16-bit | ||
| 89 | * CMCOR 0xfffec006 16-bit | ||
| 90 | * | ||
| 91 | * "32-bit counter and 16-bit control" as found on sh7372, sh73a0, r8a7740: | ||
| 92 | * CMSTR 0xffca0000 16-bit | ||
| 93 | * CMCSR 0xffca0060 16-bit | ||
| 94 | * CMCNT 0xffca0064 32-bit | ||
| 95 | * CMCOR 0xffca0068 32-bit | ||
| 96 | * | ||
| 97 | * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790: | ||
| 98 | * CMSTR 0xffca0500 32-bit | ||
| 99 | * CMCSR 0xffca0510 32-bit | ||
| 100 | * CMCNT 0xffca0514 32-bit | ||
| 101 | * CMCOR 0xffca0518 32-bit | ||
| 102 | */ | ||
| 103 | |||
| 104 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) | 117 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) |
| 105 | { | 118 | { |
| 106 | return ioread16(base + (offs << 1)); | 119 | return ioread16(base + (offs << 1)); |
| @@ -123,47 +136,100 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs, | |||
| 123 | iowrite32(value, base + (offs << 2)); | 136 | iowrite32(value, base + (offs << 2)); |
| 124 | } | 137 | } |
| 125 | 138 | ||
| 139 | static const struct sh_cmt_info sh_cmt_info[] = { | ||
| 140 | [SH_CMT_16BIT] = { | ||
| 141 | .model = SH_CMT_16BIT, | ||
| 142 | .width = 16, | ||
| 143 | .overflow_bit = 0x80, | ||
| 144 | .clear_bits = ~0x80, | ||
| 145 | .read_control = sh_cmt_read16, | ||
| 146 | .write_control = sh_cmt_write16, | ||
| 147 | .read_count = sh_cmt_read16, | ||
| 148 | .write_count = sh_cmt_write16, | ||
| 149 | }, | ||
| 150 | [SH_CMT_32BIT] = { | ||
| 151 | .model = SH_CMT_32BIT, | ||
| 152 | .width = 32, | ||
| 153 | .overflow_bit = 0x8000, | ||
| 154 | .clear_bits = ~0xc000, | ||
| 155 | .read_control = sh_cmt_read16, | ||
| 156 | .write_control = sh_cmt_write16, | ||
| 157 | .read_count = sh_cmt_read32, | ||
| 158 | .write_count = sh_cmt_write32, | ||
| 159 | }, | ||
| 160 | [SH_CMT_32BIT_FAST] = { | ||
| 161 | .model = SH_CMT_32BIT_FAST, | ||
| 162 | .width = 32, | ||
| 163 | .overflow_bit = 0x8000, | ||
| 164 | .clear_bits = ~0xc000, | ||
| 165 | .read_control = sh_cmt_read16, | ||
| 166 | .write_control = sh_cmt_write16, | ||
| 167 | .read_count = sh_cmt_read32, | ||
| 168 | .write_count = sh_cmt_write32, | ||
| 169 | }, | ||
| 170 | [SH_CMT_48BIT] = { | ||
| 171 | .model = SH_CMT_48BIT, | ||
| 172 | .width = 32, | ||
| 173 | .overflow_bit = 0x8000, | ||
| 174 | .clear_bits = ~0xc000, | ||
| 175 | .read_control = sh_cmt_read32, | ||
| 176 | .write_control = sh_cmt_write32, | ||
| 177 | .read_count = sh_cmt_read32, | ||
| 178 | .write_count = sh_cmt_write32, | ||
| 179 | }, | ||
| 180 | [SH_CMT_48BIT_GEN2] = { | ||
| 181 | .model = SH_CMT_48BIT_GEN2, | ||
| 182 | .width = 32, | ||
| 183 | .overflow_bit = 0x8000, | ||
| 184 | .clear_bits = ~0xc000, | ||
| 185 | .read_control = sh_cmt_read32, | ||
| 186 | .write_control = sh_cmt_write32, | ||
| 187 | .read_count = sh_cmt_read32, | ||
| 188 | .write_count = sh_cmt_write32, | ||
| 189 | }, | ||
| 190 | }; | ||
| 191 | |||
| 126 | #define CMCSR 0 /* channel register */ | 192 | #define CMCSR 0 /* channel register */ |
| 127 | #define CMCNT 1 /* channel register */ | 193 | #define CMCNT 1 /* channel register */ |
| 128 | #define CMCOR 2 /* channel register */ | 194 | #define CMCOR 2 /* channel register */ |
| 129 | 195 | ||
| 130 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch) | 196 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_channel *ch) |
| 131 | { | 197 | { |
| 132 | return ch->cmt->read_control(ch->cmt->mapbase, 0); | 198 | return ch->cmt->info->read_control(ch->cmt->mapbase, 0); |
| 133 | } | 199 | } |
| 134 | 200 | ||
| 135 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch) | 201 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_channel *ch) |
| 136 | { | 202 | { |
| 137 | return ch->cmt->read_control(ch->base, CMCSR); | 203 | return ch->cmt->info->read_control(ch->base, CMCSR); |
| 138 | } | 204 | } |
| 139 | 205 | ||
| 140 | static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch) | 206 | static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_channel *ch) |
| 141 | { | 207 | { |
| 142 | return ch->cmt->read_count(ch->base, CMCNT); | 208 | return ch->cmt->info->read_count(ch->base, CMCNT); |
| 143 | } | 209 | } |
| 144 | 210 | ||
| 145 | static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, | 211 | static inline void sh_cmt_write_cmstr(struct sh_cmt_channel *ch, |
| 146 | unsigned long value) | 212 | unsigned long value) |
| 147 | { | 213 | { |
| 148 | ch->cmt->write_control(ch->cmt->mapbase, 0, value); | 214 | ch->cmt->info->write_control(ch->cmt->mapbase, 0, value); |
| 149 | } | 215 | } |
| 150 | 216 | ||
| 151 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, | 217 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_channel *ch, |
| 152 | unsigned long value) | 218 | unsigned long value) |
| 153 | { | 219 | { |
| 154 | ch->cmt->write_control(ch->base, CMCSR, value); | 220 | ch->cmt->info->write_control(ch->base, CMCSR, value); |
| 155 | } | 221 | } |
| 156 | 222 | ||
| 157 | static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, | 223 | static inline void sh_cmt_write_cmcnt(struct sh_cmt_channel *ch, |
| 158 | unsigned long value) | 224 | unsigned long value) |
| 159 | { | 225 | { |
| 160 | ch->cmt->write_count(ch->base, CMCNT, value); | 226 | ch->cmt->info->write_count(ch->base, CMCNT, value); |
| 161 | } | 227 | } |
| 162 | 228 | ||
| 163 | static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, | 229 | static inline void sh_cmt_write_cmcor(struct sh_cmt_channel *ch, |
| 164 | unsigned long value) | 230 | unsigned long value) |
| 165 | { | 231 | { |
| 166 | ch->cmt->write_count(ch->base, CMCOR, value); | 232 | ch->cmt->info->write_count(ch->base, CMCOR, value); |
| 167 | } | 233 | } |
| 168 | 234 | ||
| 169 | static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, | 235 | static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, |
| @@ -172,7 +238,7 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, | |||
| 172 | unsigned long v1, v2, v3; | 238 | unsigned long v1, v2, v3; |
| 173 | int o1, o2; | 239 | int o1, o2; |
| 174 | 240 | ||
| 175 | o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->overflow_bit; | 241 | o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit; |
| 176 | 242 | ||
| 177 | /* Make sure the timer value is stable. Stolen from acpi_pm.c */ | 243 | /* Make sure the timer value is stable. Stolen from acpi_pm.c */ |
| 178 | do { | 244 | do { |
| @@ -180,7 +246,7 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_channel *ch, | |||
| 180 | v1 = sh_cmt_read_cmcnt(ch); | 246 | v1 = sh_cmt_read_cmcnt(ch); |
| 181 | v2 = sh_cmt_read_cmcnt(ch); | 247 | v2 = sh_cmt_read_cmcnt(ch); |
| 182 | v3 = sh_cmt_read_cmcnt(ch); | 248 | v3 = sh_cmt_read_cmcnt(ch); |
| 183 | o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->overflow_bit; | 249 | o1 = sh_cmt_read_cmcsr(ch) & ch->cmt->info->overflow_bit; |
| 184 | } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) | 250 | } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) |
| 185 | || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); | 251 | || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); |
| 186 | 252 | ||
| @@ -227,7 +293,7 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate) | |||
| 227 | sh_cmt_start_stop_ch(ch, 0); | 293 | sh_cmt_start_stop_ch(ch, 0); |
| 228 | 294 | ||
| 229 | /* configure channel, periodic mode and maximum timeout */ | 295 | /* configure channel, periodic mode and maximum timeout */ |
| 230 | if (ch->cmt->width == 16) { | 296 | if (ch->cmt->info->width == 16) { |
| 231 | *rate = clk_get_rate(ch->cmt->clk) / 512; | 297 | *rate = clk_get_rate(ch->cmt->clk) / 512; |
| 232 | sh_cmt_write_cmcsr(ch, 0x43); | 298 | sh_cmt_write_cmcsr(ch, 0x43); |
| 233 | } else { | 299 | } else { |
| @@ -405,7 +471,8 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) | |||
| 405 | struct sh_cmt_channel *ch = dev_id; | 471 | struct sh_cmt_channel *ch = dev_id; |
| 406 | 472 | ||
| 407 | /* clear flags */ | 473 | /* clear flags */ |
| 408 | sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) & ch->cmt->clear_bits); | 474 | sh_cmt_write_cmcsr(ch, sh_cmt_read_cmcsr(ch) & |
| 475 | ch->cmt->info->clear_bits); | ||
| 409 | 476 | ||
| 410 | /* update clock source counter to begin with if enabled | 477 | /* update clock source counter to begin with if enabled |
| 411 | * the wrap flag should be cleared by the timer specific | 478 | * the wrap flag should be cleared by the timer specific |
| @@ -719,10 +786,10 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index, | |||
| 719 | return irq; | 786 | return irq; |
| 720 | } | 787 | } |
| 721 | 788 | ||
| 722 | if (cmt->width == (sizeof(ch->max_match_value) * 8)) | 789 | if (cmt->info->width == (sizeof(ch->max_match_value) * 8)) |
| 723 | ch->max_match_value = ~0; | 790 | ch->max_match_value = ~0; |
| 724 | else | 791 | else |
| 725 | ch->max_match_value = (1 << cmt->width) - 1; | 792 | ch->max_match_value = (1 << cmt->info->width) - 1; |
| 726 | 793 | ||
| 727 | ch->match_value = ch->max_match_value; | 794 | ch->match_value = ch->max_match_value; |
| 728 | raw_spin_lock_init(&ch->lock); | 795 | raw_spin_lock_init(&ch->lock); |
| @@ -800,28 +867,13 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev) | |||
| 800 | if (ret < 0) | 867 | if (ret < 0) |
| 801 | goto err3; | 868 | goto err3; |
| 802 | 869 | ||
| 803 | if (res2 && (resource_size(res2) == 4)) { | 870 | /* identify the model based on the resources */ |
| 804 | /* assume both CMSTR and CMCSR to be 32-bit */ | 871 | if (resource_size(res) == 6) |
| 805 | cmt->read_control = sh_cmt_read32; | 872 | cmt->info = &sh_cmt_info[SH_CMT_16BIT]; |
| 806 | cmt->write_control = sh_cmt_write32; | 873 | else if (res2 && (resource_size(res2) == 4)) |
| 807 | } else { | 874 | cmt->info = &sh_cmt_info[SH_CMT_48BIT_GEN2]; |
| 808 | cmt->read_control = sh_cmt_read16; | 875 | else |
| 809 | cmt->write_control = sh_cmt_write16; | 876 | cmt->info = &sh_cmt_info[SH_CMT_32BIT]; |
| 810 | } | ||
| 811 | |||
| 812 | if (resource_size(res) == 6) { | ||
| 813 | cmt->width = 16; | ||
| 814 | cmt->read_count = sh_cmt_read16; | ||
| 815 | cmt->write_count = sh_cmt_write16; | ||
| 816 | cmt->overflow_bit = 0x80; | ||
| 817 | cmt->clear_bits = ~0x80; | ||
| 818 | } else { | ||
| 819 | cmt->width = 32; | ||
| 820 | cmt->read_count = sh_cmt_read32; | ||
| 821 | cmt->write_count = sh_cmt_write32; | ||
| 822 | cmt->overflow_bit = 0x8000; | ||
| 823 | cmt->clear_bits = ~0xc000; | ||
| 824 | } | ||
| 825 | 877 | ||
| 826 | cmt->channels = kzalloc(sizeof(*cmt->channels), GFP_KERNEL); | 878 | cmt->channels = kzalloc(sizeof(*cmt->channels), GFP_KERNEL); |
| 827 | if (cmt->channels == NULL) { | 879 | if (cmt->channels == NULL) { |
