.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/arch/arm/plat-omap/dmtimer.c |
---|
3 | 4 | * |
---|
4 | 5 | * OMAP Dual-Mode Timers |
---|
5 | 6 | * |
---|
6 | | - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ |
---|
| 7 | + * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ |
---|
7 | 8 | * Tarun Kanti DebBarma <tarun.kanti@ti.com> |
---|
8 | 9 | * Thara Gopinath <thara@ti.com> |
---|
9 | 10 | * |
---|
.. | .. |
---|
15 | 16 | * |
---|
16 | 17 | * Copyright (C) 2009 Texas Instruments |
---|
17 | 18 | * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> |
---|
18 | | - * |
---|
19 | | - * This program is free software; you can redistribute it and/or modify it |
---|
20 | | - * under the terms of the GNU General Public License as published by the |
---|
21 | | - * Free Software Foundation; either version 2 of the License, or (at your |
---|
22 | | - * option) any later version. |
---|
23 | | - * |
---|
24 | | - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
---|
25 | | - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
---|
26 | | - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
---|
27 | | - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
28 | | - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
29 | | - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
30 | | - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
31 | | - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
32 | | - * |
---|
33 | | - * You should have received a copy of the GNU General Public License along |
---|
34 | | - * with this program; if not, write to the Free Software Foundation, Inc., |
---|
35 | | - * 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
36 | 19 | */ |
---|
37 | 20 | |
---|
38 | 21 | #include <linux/clk.h> |
---|
39 | 22 | #include <linux/clk-provider.h> |
---|
| 23 | +#include <linux/cpu_pm.h> |
---|
40 | 24 | #include <linux/module.h> |
---|
41 | 25 | #include <linux/io.h> |
---|
42 | 26 | #include <linux/device.h> |
---|
.. | .. |
---|
94 | 78 | |
---|
95 | 79 | static void omap_timer_restore_context(struct omap_dm_timer *timer) |
---|
96 | 80 | { |
---|
| 81 | + __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, |
---|
| 82 | + timer->context.ocp_cfg, 0); |
---|
| 83 | + |
---|
97 | 84 | omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, |
---|
98 | 85 | timer->context.twer); |
---|
99 | 86 | omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, |
---|
.. | .. |
---|
107 | 94 | writel_relaxed(timer->context.tier, timer->irq_ena); |
---|
108 | 95 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, |
---|
109 | 96 | timer->context.tclr); |
---|
| 97 | +} |
---|
| 98 | + |
---|
| 99 | +static void omap_timer_save_context(struct omap_dm_timer *timer) |
---|
| 100 | +{ |
---|
| 101 | + timer->context.ocp_cfg = |
---|
| 102 | + __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0); |
---|
| 103 | + |
---|
| 104 | + timer->context.tclr = |
---|
| 105 | + omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
---|
| 106 | + timer->context.twer = |
---|
| 107 | + omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG); |
---|
| 108 | + timer->context.tldr = |
---|
| 109 | + omap_dm_timer_read_reg(timer, OMAP_TIMER_LOAD_REG); |
---|
| 110 | + timer->context.tmar = |
---|
| 111 | + omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG); |
---|
| 112 | + timer->context.tier = readl_relaxed(timer->irq_ena); |
---|
| 113 | + timer->context.tsicr = |
---|
| 114 | + omap_dm_timer_read_reg(timer, OMAP_TIMER_IF_CTRL_REG); |
---|
| 115 | +} |
---|
| 116 | + |
---|
| 117 | +static int omap_timer_context_notifier(struct notifier_block *nb, |
---|
| 118 | + unsigned long cmd, void *v) |
---|
| 119 | +{ |
---|
| 120 | + struct omap_dm_timer *timer; |
---|
| 121 | + |
---|
| 122 | + timer = container_of(nb, struct omap_dm_timer, nb); |
---|
| 123 | + |
---|
| 124 | + switch (cmd) { |
---|
| 125 | + case CPU_CLUSTER_PM_ENTER: |
---|
| 126 | + if ((timer->capability & OMAP_TIMER_ALWON) || |
---|
| 127 | + !atomic_read(&timer->enabled)) |
---|
| 128 | + break; |
---|
| 129 | + omap_timer_save_context(timer); |
---|
| 130 | + break; |
---|
| 131 | + case CPU_CLUSTER_PM_ENTER_FAILED: |
---|
| 132 | + case CPU_CLUSTER_PM_EXIT: |
---|
| 133 | + if ((timer->capability & OMAP_TIMER_ALWON) || |
---|
| 134 | + !atomic_read(&timer->enabled)) |
---|
| 135 | + break; |
---|
| 136 | + omap_timer_restore_context(timer); |
---|
| 137 | + break; |
---|
| 138 | + } |
---|
| 139 | + |
---|
| 140 | + return NOTIFY_OK; |
---|
110 | 141 | } |
---|
111 | 142 | |
---|
112 | 143 | static int omap_dm_timer_reset(struct omap_dm_timer *timer) |
---|
.. | .. |
---|
136 | 167 | timer->posted = 0; |
---|
137 | 168 | |
---|
138 | 169 | return 0; |
---|
139 | | -} |
---|
140 | | - |
---|
141 | | -static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer) |
---|
142 | | -{ |
---|
143 | | - int ret; |
---|
144 | | - struct clk *parent; |
---|
145 | | - |
---|
146 | | - /* |
---|
147 | | - * FIXME: OMAP1 devices do not use the clock framework for dmtimers so |
---|
148 | | - * do not call clk_get() for these devices. |
---|
149 | | - */ |
---|
150 | | - if (!timer->fclk) |
---|
151 | | - return -ENODEV; |
---|
152 | | - |
---|
153 | | - parent = clk_get(&timer->pdev->dev, NULL); |
---|
154 | | - if (IS_ERR(parent)) |
---|
155 | | - return -ENODEV; |
---|
156 | | - |
---|
157 | | - /* Bail out if both clocks point to fck */ |
---|
158 | | - if (clk_is_match(parent, timer->fclk)) |
---|
159 | | - return 0; |
---|
160 | | - |
---|
161 | | - ret = clk_set_parent(timer->fclk, parent); |
---|
162 | | - if (ret < 0) |
---|
163 | | - pr_err("%s: failed to set parent\n", __func__); |
---|
164 | | - |
---|
165 | | - clk_put(parent); |
---|
166 | | - |
---|
167 | | - return ret; |
---|
168 | 170 | } |
---|
169 | 171 | |
---|
170 | 172 | static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) |
---|
.. | .. |
---|
225 | 227 | |
---|
226 | 228 | static void omap_dm_timer_enable(struct omap_dm_timer *timer) |
---|
227 | 229 | { |
---|
228 | | - int c; |
---|
229 | | - |
---|
230 | 230 | pm_runtime_get_sync(&timer->pdev->dev); |
---|
231 | | - |
---|
232 | | - if (!(timer->capability & OMAP_TIMER_ALWON)) { |
---|
233 | | - if (timer->get_context_loss_count) { |
---|
234 | | - c = timer->get_context_loss_count(&timer->pdev->dev); |
---|
235 | | - if (c != timer->ctx_loss_count) { |
---|
236 | | - omap_timer_restore_context(timer); |
---|
237 | | - timer->ctx_loss_count = c; |
---|
238 | | - } |
---|
239 | | - } else { |
---|
240 | | - omap_timer_restore_context(timer); |
---|
241 | | - } |
---|
242 | | - } |
---|
243 | 231 | } |
---|
244 | 232 | |
---|
245 | 233 | static void omap_dm_timer_disable(struct omap_dm_timer *timer) |
---|
.. | .. |
---|
276 | 264 | __omap_dm_timer_enable_posted(timer); |
---|
277 | 265 | omap_dm_timer_disable(timer); |
---|
278 | 266 | |
---|
279 | | - rc = omap_dm_timer_of_set_source(timer); |
---|
280 | | - if (rc == -ENODEV) |
---|
281 | | - return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); |
---|
282 | | - |
---|
283 | | - return rc; |
---|
| 267 | + return 0; |
---|
284 | 268 | } |
---|
285 | 269 | |
---|
286 | 270 | static inline u32 omap_dm_timer_reserved_systimer(int id) |
---|
.. | .. |
---|
508 | 492 | |
---|
509 | 493 | int omap_dm_timer_trigger(struct omap_dm_timer *timer) |
---|
510 | 494 | { |
---|
511 | | - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { |
---|
| 495 | + if (unlikely(!timer || !atomic_read(&timer->enabled))) { |
---|
512 | 496 | pr_err("%s: timer not available or enabled.\n", __func__); |
---|
513 | 497 | return -EINVAL; |
---|
514 | 498 | } |
---|
.. | .. |
---|
532 | 516 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
---|
533 | 517 | } |
---|
534 | 518 | |
---|
535 | | - /* Save the context */ |
---|
536 | | - timer->context.tclr = l; |
---|
537 | 519 | return 0; |
---|
538 | 520 | } |
---|
539 | 521 | |
---|
.. | .. |
---|
549 | 531 | |
---|
550 | 532 | __omap_dm_timer_stop(timer, timer->posted, rate); |
---|
551 | 533 | |
---|
552 | | - /* |
---|
553 | | - * Since the register values are computed and written within |
---|
554 | | - * __omap_dm_timer_stop, we need to use read to retrieve the |
---|
555 | | - * context. |
---|
556 | | - */ |
---|
557 | | - timer->context.tclr = |
---|
558 | | - omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
---|
559 | 534 | omap_dm_timer_disable(timer); |
---|
560 | 535 | return 0; |
---|
561 | 536 | } |
---|
562 | 537 | |
---|
563 | | -static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, |
---|
| 538 | +static int omap_dm_timer_set_load(struct omap_dm_timer *timer, |
---|
564 | 539 | unsigned int load) |
---|
565 | 540 | { |
---|
566 | | - u32 l; |
---|
567 | | - |
---|
568 | 541 | if (unlikely(!timer)) |
---|
569 | 542 | return -EINVAL; |
---|
570 | 543 | |
---|
571 | 544 | omap_dm_timer_enable(timer); |
---|
572 | | - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
---|
573 | | - if (autoreload) |
---|
574 | | - l |= OMAP_TIMER_CTRL_AR; |
---|
575 | | - else |
---|
576 | | - l &= ~OMAP_TIMER_CTRL_AR; |
---|
577 | | - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
---|
578 | 545 | omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); |
---|
579 | 546 | |
---|
580 | | - omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); |
---|
581 | | - /* Save the context */ |
---|
582 | | - timer->context.tclr = l; |
---|
583 | | - timer->context.tldr = load; |
---|
584 | 547 | omap_dm_timer_disable(timer); |
---|
585 | 548 | return 0; |
---|
586 | 549 | } |
---|
587 | 550 | |
---|
588 | | -/* Optimized set_load which removes costly spin wait in timer_start */ |
---|
589 | | -int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, |
---|
590 | | - unsigned int load) |
---|
591 | | -{ |
---|
592 | | - u32 l; |
---|
593 | | - |
---|
594 | | - if (unlikely(!timer)) |
---|
595 | | - return -EINVAL; |
---|
596 | | - |
---|
597 | | - omap_dm_timer_enable(timer); |
---|
598 | | - |
---|
599 | | - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
---|
600 | | - if (autoreload) { |
---|
601 | | - l |= OMAP_TIMER_CTRL_AR; |
---|
602 | | - omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); |
---|
603 | | - } else { |
---|
604 | | - l &= ~OMAP_TIMER_CTRL_AR; |
---|
605 | | - } |
---|
606 | | - l |= OMAP_TIMER_CTRL_ST; |
---|
607 | | - |
---|
608 | | - __omap_dm_timer_load_start(timer, l, load, timer->posted); |
---|
609 | | - |
---|
610 | | - /* Save the context */ |
---|
611 | | - timer->context.tclr = l; |
---|
612 | | - timer->context.tldr = load; |
---|
613 | | - timer->context.tcrr = load; |
---|
614 | | - return 0; |
---|
615 | | -} |
---|
616 | 551 | static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, |
---|
617 | 552 | unsigned int match) |
---|
618 | 553 | { |
---|
.. | .. |
---|
630 | 565 | omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); |
---|
631 | 566 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
---|
632 | 567 | |
---|
633 | | - /* Save the context */ |
---|
634 | | - timer->context.tclr = l; |
---|
635 | | - timer->context.tmar = match; |
---|
636 | 568 | omap_dm_timer_disable(timer); |
---|
637 | 569 | return 0; |
---|
638 | 570 | } |
---|
639 | 571 | |
---|
640 | 572 | static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, |
---|
641 | | - int toggle, int trigger) |
---|
| 573 | + int toggle, int trigger, int autoreload) |
---|
642 | 574 | { |
---|
643 | 575 | u32 l; |
---|
644 | 576 | |
---|
.. | .. |
---|
648 | 580 | omap_dm_timer_enable(timer); |
---|
649 | 581 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
---|
650 | 582 | l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | |
---|
651 | | - OMAP_TIMER_CTRL_PT | (0x03 << 10)); |
---|
| 583 | + OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR); |
---|
652 | 584 | if (def_on) |
---|
653 | 585 | l |= OMAP_TIMER_CTRL_SCPWM; |
---|
654 | 586 | if (toggle) |
---|
655 | 587 | l |= OMAP_TIMER_CTRL_PT; |
---|
656 | 588 | l |= trigger << 10; |
---|
| 589 | + if (autoreload) |
---|
| 590 | + l |= OMAP_TIMER_CTRL_AR; |
---|
657 | 591 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
---|
658 | 592 | |
---|
659 | | - /* Save the context */ |
---|
660 | | - timer->context.tclr = l; |
---|
661 | 593 | omap_dm_timer_disable(timer); |
---|
662 | 594 | return 0; |
---|
| 595 | +} |
---|
| 596 | + |
---|
| 597 | +static int omap_dm_timer_get_pwm_status(struct omap_dm_timer *timer) |
---|
| 598 | +{ |
---|
| 599 | + u32 l; |
---|
| 600 | + |
---|
| 601 | + if (unlikely(!timer)) |
---|
| 602 | + return -EINVAL; |
---|
| 603 | + |
---|
| 604 | + omap_dm_timer_enable(timer); |
---|
| 605 | + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); |
---|
| 606 | + omap_dm_timer_disable(timer); |
---|
| 607 | + |
---|
| 608 | + return l; |
---|
663 | 609 | } |
---|
664 | 610 | |
---|
665 | 611 | static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, |
---|
.. | .. |
---|
679 | 625 | } |
---|
680 | 626 | omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); |
---|
681 | 627 | |
---|
682 | | - /* Save the context */ |
---|
683 | | - timer->context.tclr = l; |
---|
684 | 628 | omap_dm_timer_disable(timer); |
---|
685 | 629 | return 0; |
---|
686 | 630 | } |
---|
.. | .. |
---|
694 | 638 | omap_dm_timer_enable(timer); |
---|
695 | 639 | __omap_dm_timer_int_enable(timer, value); |
---|
696 | 640 | |
---|
697 | | - /* Save the context */ |
---|
698 | | - timer->context.tier = value; |
---|
699 | | - timer->context.twer = value; |
---|
700 | 641 | omap_dm_timer_disable(timer); |
---|
701 | 642 | return 0; |
---|
702 | 643 | } |
---|
.. | .. |
---|
724 | 665 | l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask; |
---|
725 | 666 | omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l); |
---|
726 | 667 | |
---|
727 | | - /* Save the context */ |
---|
728 | | - timer->context.tier &= ~mask; |
---|
729 | | - timer->context.twer &= ~mask; |
---|
730 | 668 | omap_dm_timer_disable(timer); |
---|
731 | 669 | return 0; |
---|
732 | 670 | } |
---|
.. | .. |
---|
735 | 673 | { |
---|
736 | 674 | unsigned int l; |
---|
737 | 675 | |
---|
738 | | - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { |
---|
| 676 | + if (unlikely(!timer || !atomic_read(&timer->enabled))) { |
---|
739 | 677 | pr_err("%s: timer not available or enabled.\n", __func__); |
---|
740 | 678 | return 0; |
---|
741 | 679 | } |
---|
.. | .. |
---|
747 | 685 | |
---|
748 | 686 | static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) |
---|
749 | 687 | { |
---|
750 | | - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) |
---|
| 688 | + if (unlikely(!timer || !atomic_read(&timer->enabled))) |
---|
751 | 689 | return -EINVAL; |
---|
752 | 690 | |
---|
753 | 691 | __omap_dm_timer_write_status(timer, value); |
---|
.. | .. |
---|
757 | 695 | |
---|
758 | 696 | static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) |
---|
759 | 697 | { |
---|
760 | | - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { |
---|
| 698 | + if (unlikely(!timer || !atomic_read(&timer->enabled))) { |
---|
761 | 699 | pr_err("%s: timer not iavailable or enabled.\n", __func__); |
---|
762 | 700 | return 0; |
---|
763 | 701 | } |
---|
.. | .. |
---|
767 | 705 | |
---|
768 | 706 | static int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) |
---|
769 | 707 | { |
---|
770 | | - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { |
---|
| 708 | + if (unlikely(!timer || !atomic_read(&timer->enabled))) { |
---|
771 | 709 | pr_err("%s: timer not available or enabled.\n", __func__); |
---|
772 | 710 | return -EINVAL; |
---|
773 | 711 | } |
---|
.. | .. |
---|
795 | 733 | return 0; |
---|
796 | 734 | } |
---|
797 | 735 | |
---|
| 736 | +static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev) |
---|
| 737 | +{ |
---|
| 738 | + struct omap_dm_timer *timer = dev_get_drvdata(dev); |
---|
| 739 | + |
---|
| 740 | + atomic_set(&timer->enabled, 0); |
---|
| 741 | + |
---|
| 742 | + if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base) |
---|
| 743 | + return 0; |
---|
| 744 | + |
---|
| 745 | + omap_timer_save_context(timer); |
---|
| 746 | + |
---|
| 747 | + return 0; |
---|
| 748 | +} |
---|
| 749 | + |
---|
| 750 | +static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev) |
---|
| 751 | +{ |
---|
| 752 | + struct omap_dm_timer *timer = dev_get_drvdata(dev); |
---|
| 753 | + |
---|
| 754 | + if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base) |
---|
| 755 | + omap_timer_restore_context(timer); |
---|
| 756 | + |
---|
| 757 | + atomic_set(&timer->enabled, 1); |
---|
| 758 | + |
---|
| 759 | + return 0; |
---|
| 760 | +} |
---|
| 761 | + |
---|
| 762 | +static const struct dev_pm_ops omap_dm_timer_pm_ops = { |
---|
| 763 | + SET_RUNTIME_PM_OPS(omap_dm_timer_runtime_suspend, |
---|
| 764 | + omap_dm_timer_runtime_resume, NULL) |
---|
| 765 | +}; |
---|
| 766 | + |
---|
798 | 767 | static const struct of_device_id omap_timer_match[]; |
---|
799 | 768 | |
---|
800 | 769 | /** |
---|
.. | .. |
---|
808 | 777 | { |
---|
809 | 778 | unsigned long flags; |
---|
810 | 779 | struct omap_dm_timer *timer; |
---|
811 | | - struct resource *mem, *irq; |
---|
812 | 780 | struct device *dev = &pdev->dev; |
---|
813 | 781 | const struct dmtimer_platform_data *pdata; |
---|
814 | 782 | int ret; |
---|
.. | .. |
---|
824 | 792 | return -ENODEV; |
---|
825 | 793 | } |
---|
826 | 794 | |
---|
827 | | - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
---|
828 | | - if (unlikely(!irq)) { |
---|
829 | | - dev_err(dev, "%s: no IRQ resource.\n", __func__); |
---|
830 | | - return -ENODEV; |
---|
831 | | - } |
---|
832 | | - |
---|
833 | | - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
834 | | - if (unlikely(!mem)) { |
---|
835 | | - dev_err(dev, "%s: no memory resource.\n", __func__); |
---|
836 | | - return -ENODEV; |
---|
837 | | - } |
---|
838 | | - |
---|
839 | 795 | timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL); |
---|
840 | 796 | if (!timer) |
---|
841 | 797 | return -ENOMEM; |
---|
842 | 798 | |
---|
| 799 | + timer->irq = platform_get_irq(pdev, 0); |
---|
| 800 | + if (timer->irq < 0) |
---|
| 801 | + return timer->irq; |
---|
| 802 | + |
---|
843 | 803 | timer->fclk = ERR_PTR(-ENODEV); |
---|
844 | | - timer->io_base = devm_ioremap_resource(dev, mem); |
---|
| 804 | + timer->io_base = devm_platform_ioremap_resource(pdev, 0); |
---|
845 | 805 | if (IS_ERR(timer->io_base)) |
---|
846 | 806 | return PTR_ERR(timer->io_base); |
---|
| 807 | + |
---|
| 808 | + platform_set_drvdata(pdev, timer); |
---|
847 | 809 | |
---|
848 | 810 | if (dev->of_node) { |
---|
849 | 811 | if (of_find_property(dev->of_node, "ti,timer-alwon", NULL)) |
---|
.. | .. |
---|
858 | 820 | timer->id = pdev->id; |
---|
859 | 821 | timer->capability = pdata->timer_capability; |
---|
860 | 822 | timer->reserved = omap_dm_timer_reserved_systimer(timer->id); |
---|
861 | | - timer->get_context_loss_count = pdata->get_context_loss_count; |
---|
| 823 | + } |
---|
| 824 | + |
---|
| 825 | + if (!(timer->capability & OMAP_TIMER_ALWON)) { |
---|
| 826 | + timer->nb.notifier_call = omap_timer_context_notifier; |
---|
| 827 | + cpu_pm_register_notifier(&timer->nb); |
---|
862 | 828 | } |
---|
863 | 829 | |
---|
864 | 830 | if (pdata) |
---|
865 | 831 | timer->errata = pdata->timer_errata; |
---|
866 | 832 | |
---|
867 | | - timer->irq = irq->start; |
---|
868 | 833 | timer->pdev = pdev; |
---|
869 | 834 | |
---|
870 | 835 | pm_runtime_enable(dev); |
---|
.. | .. |
---|
913 | 878 | list_for_each_entry(timer, &omap_timer_list, node) |
---|
914 | 879 | if (!strcmp(dev_name(&timer->pdev->dev), |
---|
915 | 880 | dev_name(&pdev->dev))) { |
---|
| 881 | + if (!(timer->capability & OMAP_TIMER_ALWON)) |
---|
| 882 | + cpu_pm_unregister_notifier(&timer->nb); |
---|
916 | 883 | list_del(&timer->node); |
---|
917 | 884 | ret = 0; |
---|
918 | 885 | break; |
---|
.. | .. |
---|
924 | 891 | return ret; |
---|
925 | 892 | } |
---|
926 | 893 | |
---|
927 | | -const static struct omap_dm_timer_ops dmtimer_ops = { |
---|
| 894 | +static const struct omap_dm_timer_ops dmtimer_ops = { |
---|
928 | 895 | .request_by_node = omap_dm_timer_request_by_node, |
---|
929 | 896 | .request_specific = omap_dm_timer_request_specific, |
---|
930 | 897 | .request = omap_dm_timer_request, |
---|
.. | .. |
---|
941 | 908 | .set_load = omap_dm_timer_set_load, |
---|
942 | 909 | .set_match = omap_dm_timer_set_match, |
---|
943 | 910 | .set_pwm = omap_dm_timer_set_pwm, |
---|
| 911 | + .get_pwm_status = omap_dm_timer_get_pwm_status, |
---|
944 | 912 | .set_prescaler = omap_dm_timer_set_prescaler, |
---|
945 | 913 | .read_counter = omap_dm_timer_read_counter, |
---|
946 | 914 | .write_counter = omap_dm_timer_write_counter, |
---|
.. | .. |
---|
991 | 959 | .driver = { |
---|
992 | 960 | .name = "omap_timer", |
---|
993 | 961 | .of_match_table = of_match_ptr(omap_timer_match), |
---|
| 962 | + .pm = &omap_dm_timer_pm_ops, |
---|
994 | 963 | }, |
---|
995 | 964 | }; |
---|
996 | 965 | |
---|
997 | | -early_platform_init("earlytimer", &omap_dm_timer_driver); |
---|
998 | 966 | module_platform_driver(omap_dm_timer_driver); |
---|
999 | 967 | |
---|
1000 | 968 | MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver"); |
---|
1001 | 969 | MODULE_LICENSE("GPL"); |
---|
1002 | | -MODULE_ALIAS("platform:" DRIVER_NAME); |
---|
1003 | 970 | MODULE_AUTHOR("Texas Instruments Inc"); |
---|