diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-12 02:29:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-12 02:29:20 -0500 |
commit | 4c4d285ad5665bfbd983b95fde8d7a477d24a361 (patch) | |
tree | 05da51053d4c8943ae21ea0b152aef4c67eba19d /drivers/sh | |
parent | 56c8bc3b7ed3d24c665e2ce992f86a5bedffc852 (diff) | |
parent | e64e1b11b14d363ac70fd13ab809969a6d7e42a8 (diff) |
Merge tag 'rmobile-for-linus' of git://github.com/pmundt/linux-sh
SH/R-Mobile updates for 3.3 merge window.
* tag 'rmobile-for-linus' of git://github.com/pmundt/linux-sh: (32 commits)
arm: mach-shmobile: add a resource name for shdma
ARM: mach-shmobile: r8a7779 SMP support V3
ARM: mach-shmobile: Add kota2 defconfig.
ARM: mach-shmobile: Add marzen defconfig.
ARM: mach-shmobile: r8a7779 power domain support V2
ARM: mach-shmobile: Fix up marzen build for recent GIC changes.
ARM: mach-shmobile: r8a7779 PFC function support
ARM: mach-shmobile: Flush caches in platform_cpu_die()
ARM: mach-shmobile: Allow SoC specific CPU kill code
ARM: mach-shmobile: Fix headsmp.S code to use CPUINIT
ARM: mach-shmobile: clock-r8a7779: clkz/clkzs support
ARM: mach-shmobile: clock-r8a7779: add DIV4 clock support
ARM: mach-shmobile: Marzen LAN89218 support
ARM: mach-shmobile: Marzen SCIF2/SCIF4 support
ARM: mach-shmobile: r8a7779 PFC GPIO-only support V2
ARM: mach-shmobile: r8a7779 and Marzen base support V2
sh: pfc: Unlock register support
sh: pfc: Variable bitfield width config register support
sh: pfc: Add config_reg_helper() function
sh: pfc: Convert index to field and value pair
...
Diffstat (limited to 'drivers/sh')
-rw-r--r-- | drivers/sh/pfc.c | 176 |
1 files changed, 94 insertions, 82 deletions
diff --git a/drivers/sh/pfc.c b/drivers/sh/pfc.c index e7d127a9c1c..522c6c46d1b 100644 --- a/drivers/sh/pfc.c +++ b/drivers/sh/pfc.c | |||
@@ -135,6 +135,19 @@ static void gpio_write_raw_reg(void __iomem *mapped_reg, | |||
135 | BUG(); | 135 | BUG(); |
136 | } | 136 | } |
137 | 137 | ||
138 | static int gpio_read_bit(struct pinmux_data_reg *dr, | ||
139 | unsigned long in_pos) | ||
140 | { | ||
141 | unsigned long pos; | ||
142 | |||
143 | pos = dr->reg_width - (in_pos + 1); | ||
144 | |||
145 | pr_debug("read_bit: addr = %lx, pos = %ld, " | ||
146 | "r_width = %ld\n", dr->reg, pos, dr->reg_width); | ||
147 | |||
148 | return (gpio_read_raw_reg(dr->mapped_reg, dr->reg_width) >> pos) & 1; | ||
149 | } | ||
150 | |||
138 | static void gpio_write_bit(struct pinmux_data_reg *dr, | 151 | static void gpio_write_bit(struct pinmux_data_reg *dr, |
139 | unsigned long in_pos, unsigned long value) | 152 | unsigned long in_pos, unsigned long value) |
140 | { | 153 | { |
@@ -154,51 +167,69 @@ static void gpio_write_bit(struct pinmux_data_reg *dr, | |||
154 | gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow); | 167 | gpio_write_raw_reg(dr->mapped_reg, dr->reg_width, dr->reg_shadow); |
155 | } | 168 | } |
156 | 169 | ||
157 | static int gpio_read_reg(void __iomem *mapped_reg, unsigned long reg_width, | 170 | static void config_reg_helper(struct pinmux_info *gpioc, |
158 | unsigned long field_width, unsigned long in_pos, | 171 | struct pinmux_cfg_reg *crp, |
159 | unsigned long reg) | 172 | unsigned long in_pos, |
173 | void __iomem **mapped_regp, | ||
174 | unsigned long *maskp, | ||
175 | unsigned long *posp) | ||
160 | { | 176 | { |
161 | unsigned long data, mask, pos; | 177 | int k; |
162 | 178 | ||
163 | data = 0; | 179 | *mapped_regp = pfc_phys_to_virt(gpioc, crp->reg); |
164 | mask = (1 << field_width) - 1; | ||
165 | pos = reg_width - ((in_pos + 1) * field_width); | ||
166 | 180 | ||
167 | pr_debug("read_reg: addr = %lx, pos = %ld, " | 181 | if (crp->field_width) { |
182 | *maskp = (1 << crp->field_width) - 1; | ||
183 | *posp = crp->reg_width - ((in_pos + 1) * crp->field_width); | ||
184 | } else { | ||
185 | *maskp = (1 << crp->var_field_width[in_pos]) - 1; | ||
186 | *posp = crp->reg_width; | ||
187 | for (k = 0; k <= in_pos; k++) | ||
188 | *posp -= crp->var_field_width[k]; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static int read_config_reg(struct pinmux_info *gpioc, | ||
193 | struct pinmux_cfg_reg *crp, | ||
194 | unsigned long field) | ||
195 | { | ||
196 | void __iomem *mapped_reg; | ||
197 | unsigned long mask, pos; | ||
198 | |||
199 | config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos); | ||
200 | |||
201 | pr_debug("read_reg: addr = %lx, field = %ld, " | ||
168 | "r_width = %ld, f_width = %ld\n", | 202 | "r_width = %ld, f_width = %ld\n", |
169 | reg, pos, reg_width, field_width); | 203 | crp->reg, field, crp->reg_width, crp->field_width); |
170 | 204 | ||
171 | data = gpio_read_raw_reg(mapped_reg, reg_width); | 205 | return (gpio_read_raw_reg(mapped_reg, crp->reg_width) >> pos) & mask; |
172 | return (data >> pos) & mask; | ||
173 | } | 206 | } |
174 | 207 | ||
175 | static void gpio_write_reg(void __iomem *mapped_reg, unsigned long reg_width, | 208 | static void write_config_reg(struct pinmux_info *gpioc, |
176 | unsigned long field_width, unsigned long in_pos, | 209 | struct pinmux_cfg_reg *crp, |
177 | unsigned long value, unsigned long reg) | 210 | unsigned long field, unsigned long value) |
178 | { | 211 | { |
179 | unsigned long mask, pos; | 212 | void __iomem *mapped_reg; |
213 | unsigned long mask, pos, data; | ||
180 | 214 | ||
181 | mask = (1 << field_width) - 1; | 215 | config_reg_helper(gpioc, crp, field, &mapped_reg, &mask, &pos); |
182 | pos = reg_width - ((in_pos + 1) * field_width); | ||
183 | 216 | ||
184 | pr_debug("write_reg addr = %lx, value = %ld, pos = %ld, " | 217 | pr_debug("write_reg addr = %lx, value = %ld, field = %ld, " |
185 | "r_width = %ld, f_width = %ld\n", | 218 | "r_width = %ld, f_width = %ld\n", |
186 | reg, value, pos, reg_width, field_width); | 219 | crp->reg, value, field, crp->reg_width, crp->field_width); |
187 | 220 | ||
188 | mask = ~(mask << pos); | 221 | mask = ~(mask << pos); |
189 | value = value << pos; | 222 | value = value << pos; |
190 | 223 | ||
191 | switch (reg_width) { | 224 | data = gpio_read_raw_reg(mapped_reg, crp->reg_width); |
192 | case 8: | 225 | data &= mask; |
193 | iowrite8((ioread8(mapped_reg) & mask) | value, mapped_reg); | 226 | data |= value; |
194 | break; | 227 | |
195 | case 16: | 228 | if (gpioc->unlock_reg) |
196 | iowrite16((ioread16(mapped_reg) & mask) | value, mapped_reg); | 229 | gpio_write_raw_reg(pfc_phys_to_virt(gpioc, gpioc->unlock_reg), |
197 | break; | 230 | 32, ~data); |
198 | case 32: | 231 | |
199 | iowrite32((ioread32(mapped_reg) & mask) | value, mapped_reg); | 232 | gpio_write_raw_reg(mapped_reg, crp->reg_width, data); |
200 | break; | ||
201 | } | ||
202 | } | 233 | } |
203 | 234 | ||
204 | static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) | 235 | static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) |
@@ -274,12 +305,13 @@ static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | |||
274 | } | 305 | } |
275 | 306 | ||
276 | static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, | 307 | static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, |
277 | struct pinmux_cfg_reg **crp, int *indexp, | 308 | struct pinmux_cfg_reg **crp, |
309 | int *fieldp, int *valuep, | ||
278 | unsigned long **cntp) | 310 | unsigned long **cntp) |
279 | { | 311 | { |
280 | struct pinmux_cfg_reg *config_reg; | 312 | struct pinmux_cfg_reg *config_reg; |
281 | unsigned long r_width, f_width; | 313 | unsigned long r_width, f_width, curr_width, ncomb; |
282 | int k, n; | 314 | int k, m, n, pos, bit_pos; |
283 | 315 | ||
284 | k = 0; | 316 | k = 0; |
285 | while (1) { | 317 | while (1) { |
@@ -290,13 +322,27 @@ static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, | |||
290 | 322 | ||
291 | if (!r_width) | 323 | if (!r_width) |
292 | break; | 324 | break; |
293 | for (n = 0; n < (r_width / f_width) * (1 << f_width); n++) { | 325 | |
294 | if (config_reg->enum_ids[n] == enum_id) { | 326 | pos = 0; |
295 | *crp = config_reg; | 327 | m = 0; |
296 | *indexp = n; | 328 | for (bit_pos = 0; bit_pos < r_width; bit_pos += curr_width) { |
297 | *cntp = &config_reg->cnt[n / (1 << f_width)]; | 329 | if (f_width) |
298 | return 0; | 330 | curr_width = f_width; |
331 | else | ||
332 | curr_width = config_reg->var_field_width[m]; | ||
333 | |||
334 | ncomb = 1 << curr_width; | ||
335 | for (n = 0; n < ncomb; n++) { | ||
336 | if (config_reg->enum_ids[pos + n] == enum_id) { | ||
337 | *crp = config_reg; | ||
338 | *fieldp = m; | ||
339 | *valuep = n; | ||
340 | *cntp = &config_reg->cnt[m]; | ||
341 | return 0; | ||
342 | } | ||
299 | } | 343 | } |
344 | pos += ncomb; | ||
345 | m++; | ||
300 | } | 346 | } |
301 | k++; | 347 | k++; |
302 | } | 348 | } |
@@ -334,43 +380,6 @@ static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio, | |||
334 | return -1; | 380 | return -1; |
335 | } | 381 | } |
336 | 382 | ||
337 | static void write_config_reg(struct pinmux_info *gpioc, | ||
338 | struct pinmux_cfg_reg *crp, | ||
339 | int index) | ||
340 | { | ||
341 | unsigned long ncomb, pos, value; | ||
342 | void __iomem *mapped_reg; | ||
343 | |||
344 | ncomb = 1 << crp->field_width; | ||
345 | pos = index / ncomb; | ||
346 | value = index % ncomb; | ||
347 | |||
348 | mapped_reg = pfc_phys_to_virt(gpioc, crp->reg); | ||
349 | |||
350 | gpio_write_reg(mapped_reg, crp->reg_width, crp->field_width, | ||
351 | pos, value, crp->reg); | ||
352 | } | ||
353 | |||
354 | static int check_config_reg(struct pinmux_info *gpioc, | ||
355 | struct pinmux_cfg_reg *crp, | ||
356 | int index) | ||
357 | { | ||
358 | unsigned long ncomb, pos, value; | ||
359 | void __iomem *mapped_reg; | ||
360 | |||
361 | ncomb = 1 << crp->field_width; | ||
362 | pos = index / ncomb; | ||
363 | value = index % ncomb; | ||
364 | |||
365 | mapped_reg = pfc_phys_to_virt(gpioc, crp->reg); | ||
366 | |||
367 | if (gpio_read_reg(mapped_reg, crp->reg_width, | ||
368 | crp->field_width, pos, crp->reg) == value) | ||
369 | return 0; | ||
370 | |||
371 | return -1; | ||
372 | } | ||
373 | |||
374 | enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; | 383 | enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; |
375 | 384 | ||
376 | static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | 385 | static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, |
@@ -379,7 +388,7 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | |||
379 | struct pinmux_cfg_reg *cr = NULL; | 388 | struct pinmux_cfg_reg *cr = NULL; |
380 | pinmux_enum_t enum_id; | 389 | pinmux_enum_t enum_id; |
381 | struct pinmux_range *range; | 390 | struct pinmux_range *range; |
382 | int in_range, pos, index; | 391 | int in_range, pos, field, value; |
383 | unsigned long *cntp; | 392 | unsigned long *cntp; |
384 | 393 | ||
385 | switch (pinmux_type) { | 394 | switch (pinmux_type) { |
@@ -410,7 +419,8 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | |||
410 | 419 | ||
411 | pos = 0; | 420 | pos = 0; |
412 | enum_id = 0; | 421 | enum_id = 0; |
413 | index = 0; | 422 | field = 0; |
423 | value = 0; | ||
414 | while (1) { | 424 | while (1) { |
415 | pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); | 425 | pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); |
416 | if (pos <= 0) | 426 | if (pos <= 0) |
@@ -457,17 +467,19 @@ static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | |||
457 | if (!in_range) | 467 | if (!in_range) |
458 | continue; | 468 | continue; |
459 | 469 | ||
460 | if (get_config_reg(gpioc, enum_id, &cr, &index, &cntp) != 0) | 470 | if (get_config_reg(gpioc, enum_id, &cr, |
471 | &field, &value, &cntp) != 0) | ||
461 | goto out_err; | 472 | goto out_err; |
462 | 473 | ||
463 | switch (cfg_mode) { | 474 | switch (cfg_mode) { |
464 | case GPIO_CFG_DRYRUN: | 475 | case GPIO_CFG_DRYRUN: |
465 | if (!*cntp || !check_config_reg(gpioc, cr, index)) | 476 | if (!*cntp || |
477 | (read_config_reg(gpioc, cr, field) != value)) | ||
466 | continue; | 478 | continue; |
467 | break; | 479 | break; |
468 | 480 | ||
469 | case GPIO_CFG_REQ: | 481 | case GPIO_CFG_REQ: |
470 | write_config_reg(gpioc, cr, index); | 482 | write_config_reg(gpioc, cr, field, value); |
471 | *cntp = *cntp + 1; | 483 | *cntp = *cntp + 1; |
472 | break; | 484 | break; |
473 | 485 | ||
@@ -644,7 +656,7 @@ static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio) | |||
644 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) | 656 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) |
645 | return -EINVAL; | 657 | return -EINVAL; |
646 | 658 | ||
647 | return gpio_read_reg(dr->mapped_reg, dr->reg_width, 1, bit, dr->reg); | 659 | return gpio_read_bit(dr, bit); |
648 | } | 660 | } |
649 | 661 | ||
650 | static int sh_gpio_get(struct gpio_chip *chip, unsigned offset) | 662 | static int sh_gpio_get(struct gpio_chip *chip, unsigned offset) |