diff options
| author | Olof Johansson <olof@lixom.net> | 2013-08-14 02:33:07 -0400 |
|---|---|---|
| committer | Olof Johansson <olof@lixom.net> | 2013-08-14 02:33:07 -0400 |
| commit | 8b2496a22810531cb9157191cd0264bae8efeca0 (patch) | |
| tree | 04b3e07e094df65b2ea083eea30af6ac9a15c34e /drivers/clocksource | |
| parent | bee22087faf5bbf33fcb61e6c5e8f8ef7ebd77a5 (diff) | |
| parent | 4380c39ad3efbe58d7ed3b6adf6e602b23402b1e (diff) | |
Merge tag 'v3.12-pwm-cleanup-for-olof' of git://github.com/tom3q/linux into next/cleanup
From Tomasz Figa:
Here is the Samsung PWM cleanup series. Particular patches of the series
involve following modifications:
- fixing up few things in samsung_pwm_timer clocksource driver,
- moving remaining Samsung platforms to the new clocksource driver,
- removing old clocksource driver,
- adding new multiplatform- and DT-aware PWM driver,
- moving all Samsung platforms to use the new PWM driver,
- removing old PWM driver,
- removing all PWM-related code that is not used anymore.
* tag 'v3.12-pwm-cleanup-for-olof' of git://github.com/tom3q/linux: (684 commits)
ARM: SAMSUNG: Remove plat/regs-timer.h header
ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header
ARM: SAMSUNG: Remove pwm-clock infrastructure
ARM: SAMSUNG: Remove old PWM timer platform devices
pwm: Remove superseded pwm-samsung-legacy driver
ARM: SAMSUNG: Modify board files to use new PWM platform device
ARM: SAMSUNG: Rework private data handling in dev-backlight
pwm: Add new pwm-samsung driver
pwm: samsung: Rename to pwm-samsung-legacy
ARM: SAMSUNG: Remove unused PWM timer IRQ chip code
ARM: SAMSUNG: Remove old samsung-time driver
ARM: SAMSUNG: Move all platforms to new clocksource driver
ARM: SAMSUNG: Set PWM platform data
ARM: SAMSUNG: Add new PWM platform device
ARM: SAMSUNG: Unify base address definitions of timer block
clocksource: samsung_pwm_timer: Handle suspend/resume correctly
clocksource: samsung_pwm_timer: Do not use clocksource_mmio
clocksource: samsung_pwm_timer: Cache clocksource register address
clocksource: samsung_pwm_timer: Correct definition of AUTORELOAD bit
clocksource: samsung_pwm_timer: Do not request PWM mem region
+ v3.11-rc4
Conflicts:
arch/arm/Kconfig.debug
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/clocksource')
| -rw-r--r-- | drivers/clocksource/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/clocksource/samsung_pwm_timer.c | 108 |
2 files changed, 59 insertions, 50 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index b7b9b040a89b..41c69469ce20 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -99,7 +99,6 @@ config CLKSRC_EXYNOS_MCT | |||
| 99 | 99 | ||
| 100 | config CLKSRC_SAMSUNG_PWM | 100 | config CLKSRC_SAMSUNG_PWM |
| 101 | bool | 101 | bool |
| 102 | select CLKSRC_MMIO | ||
| 103 | help | 102 | help |
| 104 | This is a new clocksource driver for the PWM timer found in | 103 | This is a new clocksource driver for the PWM timer found in |
| 105 | Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver | 104 | Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver |
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 584b5472eea3..ac60f8b8a5f7 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c | |||
| @@ -44,16 +44,28 @@ | |||
| 44 | #define TCFG1_SHIFT(x) ((x) * 4) | 44 | #define TCFG1_SHIFT(x) ((x) * 4) |
| 45 | #define TCFG1_MUX_MASK 0xf | 45 | #define TCFG1_MUX_MASK 0xf |
| 46 | 46 | ||
| 47 | /* | ||
| 48 | * Each channel occupies 4 bits in TCON register, but there is a gap of 4 | ||
| 49 | * bits (one channel) after channel 0, so channels have different numbering | ||
| 50 | * when accessing TCON register. | ||
| 51 | * | ||
| 52 | * In addition, the location of autoreload bit for channel 4 (TCON channel 5) | ||
| 53 | * in its set of bits is 2 as opposed to 3 for other channels. | ||
| 54 | */ | ||
| 47 | #define TCON_START(chan) (1 << (4 * (chan) + 0)) | 55 | #define TCON_START(chan) (1 << (4 * (chan) + 0)) |
| 48 | #define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1)) | 56 | #define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1)) |
| 49 | #define TCON_INVERT(chan) (1 << (4 * (chan) + 2)) | 57 | #define TCON_INVERT(chan) (1 << (4 * (chan) + 2)) |
| 50 | #define TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3)) | 58 | #define _TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3)) |
| 59 | #define _TCON_AUTORELOAD4(chan) (1 << (4 * (chan) + 2)) | ||
| 60 | #define TCON_AUTORELOAD(chan) \ | ||
| 61 | ((chan < 5) ? _TCON_AUTORELOAD(chan) : _TCON_AUTORELOAD4(chan)) | ||
| 51 | 62 | ||
| 52 | DEFINE_SPINLOCK(samsung_pwm_lock); | 63 | DEFINE_SPINLOCK(samsung_pwm_lock); |
| 53 | EXPORT_SYMBOL(samsung_pwm_lock); | 64 | EXPORT_SYMBOL(samsung_pwm_lock); |
| 54 | 65 | ||
| 55 | struct samsung_pwm_clocksource { | 66 | struct samsung_pwm_clocksource { |
| 56 | void __iomem *base; | 67 | void __iomem *base; |
| 68 | void __iomem *source_reg; | ||
| 57 | unsigned int irq[SAMSUNG_PWM_NUM]; | 69 | unsigned int irq[SAMSUNG_PWM_NUM]; |
| 58 | struct samsung_pwm_variant variant; | 70 | struct samsung_pwm_variant variant; |
| 59 | 71 | ||
| @@ -195,17 +207,6 @@ static int samsung_set_next_event(unsigned long cycles, | |||
| 195 | return 0; | 207 | return 0; |
| 196 | } | 208 | } |
| 197 | 209 | ||
| 198 | static void samsung_timer_resume(void) | ||
| 199 | { | ||
| 200 | /* event timer restart */ | ||
| 201 | samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1); | ||
| 202 | samsung_time_start(pwm.event_id, true); | ||
| 203 | |||
| 204 | /* source timer restart */ | ||
| 205 | samsung_time_setup(pwm.source_id, pwm.tcnt_max); | ||
| 206 | samsung_time_start(pwm.source_id, true); | ||
| 207 | } | ||
| 208 | |||
| 209 | static void samsung_set_mode(enum clock_event_mode mode, | 210 | static void samsung_set_mode(enum clock_event_mode mode, |
| 210 | struct clock_event_device *evt) | 211 | struct clock_event_device *evt) |
| 211 | { | 212 | { |
| @@ -222,20 +223,29 @@ static void samsung_set_mode(enum clock_event_mode mode, | |||
| 222 | 223 | ||
| 223 | case CLOCK_EVT_MODE_UNUSED: | 224 | case CLOCK_EVT_MODE_UNUSED: |
| 224 | case CLOCK_EVT_MODE_SHUTDOWN: | 225 | case CLOCK_EVT_MODE_SHUTDOWN: |
| 225 | break; | ||
| 226 | |||
| 227 | case CLOCK_EVT_MODE_RESUME: | 226 | case CLOCK_EVT_MODE_RESUME: |
| 228 | samsung_timer_resume(); | ||
| 229 | break; | 227 | break; |
| 230 | } | 228 | } |
| 231 | } | 229 | } |
| 232 | 230 | ||
| 231 | static void samsung_clockevent_resume(struct clock_event_device *cev) | ||
| 232 | { | ||
| 233 | samsung_timer_set_prescale(pwm.event_id, pwm.tscaler_div); | ||
| 234 | samsung_timer_set_divisor(pwm.event_id, pwm.tdiv); | ||
| 235 | |||
| 236 | if (pwm.variant.has_tint_cstat) { | ||
| 237 | u32 mask = (1 << pwm.event_id); | ||
| 238 | writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 233 | static struct clock_event_device time_event_device = { | 242 | static struct clock_event_device time_event_device = { |
| 234 | .name = "samsung_event_timer", | 243 | .name = "samsung_event_timer", |
| 235 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 244 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
| 236 | .rating = 200, | 245 | .rating = 200, |
| 237 | .set_next_event = samsung_set_next_event, | 246 | .set_next_event = samsung_set_next_event, |
| 238 | .set_mode = samsung_set_mode, | 247 | .set_mode = samsung_set_mode, |
| 248 | .resume = samsung_clockevent_resume, | ||
| 239 | }; | 249 | }; |
| 240 | 250 | ||
| 241 | static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) | 251 | static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) |
| @@ -286,23 +296,34 @@ static void __init samsung_clockevent_init(void) | |||
| 286 | } | 296 | } |
| 287 | } | 297 | } |
| 288 | 298 | ||
| 289 | static void __iomem *samsung_timer_reg(void) | 299 | static void samsung_clocksource_suspend(struct clocksource *cs) |
| 290 | { | 300 | { |
| 291 | switch (pwm.source_id) { | 301 | samsung_time_stop(pwm.source_id); |
| 292 | case 0: | ||
| 293 | case 1: | ||
| 294 | case 2: | ||
| 295 | case 3: | ||
| 296 | return pwm.base + pwm.source_id * 0x0c + 0x14; | ||
| 297 | |||
| 298 | case 4: | ||
| 299 | return pwm.base + 0x40; | ||
| 300 | |||
| 301 | default: | ||
| 302 | BUG(); | ||
| 303 | } | ||
| 304 | } | 302 | } |
| 305 | 303 | ||
| 304 | static void samsung_clocksource_resume(struct clocksource *cs) | ||
| 305 | { | ||
| 306 | samsung_timer_set_prescale(pwm.source_id, pwm.tscaler_div); | ||
| 307 | samsung_timer_set_divisor(pwm.source_id, pwm.tdiv); | ||
| 308 | |||
| 309 | samsung_time_setup(pwm.source_id, pwm.tcnt_max); | ||
| 310 | samsung_time_start(pwm.source_id, true); | ||
| 311 | } | ||
| 312 | |||
| 313 | static cycle_t samsung_clocksource_read(struct clocksource *c) | ||
| 314 | { | ||
| 315 | return ~readl_relaxed(pwm.source_reg); | ||
| 316 | } | ||
| 317 | |||
| 318 | static struct clocksource samsung_clocksource = { | ||
| 319 | .name = "samsung_clocksource_timer", | ||
| 320 | .rating = 250, | ||
| 321 | .read = samsung_clocksource_read, | ||
| 322 | .suspend = samsung_clocksource_suspend, | ||
| 323 | .resume = samsung_clocksource_resume, | ||
| 324 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 325 | }; | ||
| 326 | |||
| 306 | /* | 327 | /* |
| 307 | * Override the global weak sched_clock symbol with this | 328 | * Override the global weak sched_clock symbol with this |
| 308 | * local implementation which uses the clocksource to get some | 329 | * local implementation which uses the clocksource to get some |
| @@ -312,17 +333,11 @@ static void __iomem *samsung_timer_reg(void) | |||
| 312 | */ | 333 | */ |
| 313 | static u32 notrace samsung_read_sched_clock(void) | 334 | static u32 notrace samsung_read_sched_clock(void) |
| 314 | { | 335 | { |
| 315 | void __iomem *reg = samsung_timer_reg(); | 336 | return samsung_clocksource_read(NULL); |
| 316 | |||
| 317 | if (!reg) | ||
| 318 | return 0; | ||
| 319 | |||
| 320 | return ~__raw_readl(reg); | ||
| 321 | } | 337 | } |
| 322 | 338 | ||
| 323 | static void __init samsung_clocksource_init(void) | 339 | static void __init samsung_clocksource_init(void) |
| 324 | { | 340 | { |
| 325 | void __iomem *reg = samsung_timer_reg(); | ||
| 326 | unsigned long pclk; | 341 | unsigned long pclk; |
| 327 | unsigned long clock_rate; | 342 | unsigned long clock_rate; |
| 328 | int ret; | 343 | int ret; |
| @@ -337,12 +352,16 @@ static void __init samsung_clocksource_init(void) | |||
| 337 | samsung_time_setup(pwm.source_id, pwm.tcnt_max); | 352 | samsung_time_setup(pwm.source_id, pwm.tcnt_max); |
| 338 | samsung_time_start(pwm.source_id, true); | 353 | samsung_time_start(pwm.source_id, true); |
| 339 | 354 | ||
| 355 | if (pwm.source_id == 4) | ||
| 356 | pwm.source_reg = pwm.base + 0x40; | ||
| 357 | else | ||
| 358 | pwm.source_reg = pwm.base + pwm.source_id * 0x0c + 0x14; | ||
| 359 | |||
| 340 | setup_sched_clock(samsung_read_sched_clock, | 360 | setup_sched_clock(samsung_read_sched_clock, |
| 341 | pwm.variant.bits, clock_rate); | 361 | pwm.variant.bits, clock_rate); |
| 342 | 362 | ||
| 343 | ret = clocksource_mmio_init(reg, "samsung_clocksource_timer", | 363 | samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits); |
| 344 | clock_rate, 250, pwm.variant.bits, | 364 | ret = clocksource_register_hz(&samsung_clocksource, clock_rate); |
| 345 | clocksource_mmio_readl_down); | ||
| 346 | if (ret) | 365 | if (ret) |
| 347 | panic("samsung_clocksource_timer: can't register clocksource\n"); | 366 | panic("samsung_clocksource_timer: can't register clocksource\n"); |
| 348 | } | 367 | } |
| @@ -404,7 +423,6 @@ void __init samsung_pwm_clocksource_init(void __iomem *base, | |||
| 404 | static void __init samsung_pwm_alloc(struct device_node *np, | 423 | static void __init samsung_pwm_alloc(struct device_node *np, |
| 405 | const struct samsung_pwm_variant *variant) | 424 | const struct samsung_pwm_variant *variant) |
| 406 | { | 425 | { |
| 407 | struct resource res; | ||
| 408 | struct property *prop; | 426 | struct property *prop; |
| 409 | const __be32 *cur; | 427 | const __be32 *cur; |
| 410 | u32 val; | 428 | u32 val; |
| @@ -423,17 +441,9 @@ static void __init samsung_pwm_alloc(struct device_node *np, | |||
| 423 | pwm.variant.output_mask |= 1 << val; | 441 | pwm.variant.output_mask |= 1 << val; |
| 424 | } | 442 | } |
| 425 | 443 | ||
| 426 | of_address_to_resource(np, 0, &res); | 444 | pwm.base = of_iomap(np, 0); |
| 427 | if (!request_mem_region(res.start, | ||
| 428 | resource_size(&res), "samsung-pwm")) { | ||
| 429 | pr_err("%s: failed to request IO mem region\n", __func__); | ||
| 430 | return; | ||
| 431 | } | ||
| 432 | |||
| 433 | pwm.base = ioremap(res.start, resource_size(&res)); | ||
| 434 | if (!pwm.base) { | 445 | if (!pwm.base) { |
| 435 | pr_err("%s: failed to map PWM registers\n", __func__); | 446 | pr_err("%s: failed to map PWM registers\n", __func__); |
| 436 | release_mem_region(res.start, resource_size(&res)); | ||
| 437 | return; | 447 | return; |
| 438 | } | 448 | } |
| 439 | 449 | ||
