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 | |
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>
-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) { |