sh_cmt.c revision da64c2a8dee66ca03f4f3e15d84be7bedf73db3d
13fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm/* 23fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * SuperH Timer Support - CMT 33fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * 43fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * Copyright (C) 2008 Magnus Damm 53fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * 63fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * This program is free software; you can redistribute it and/or modify 73fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * it under the terms of the GNU General Public License as published by 83fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * the Free Software Foundation; either version 2 of the License 93fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * 103fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * This program is distributed in the hope that it will be useful, 113fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * but WITHOUT ANY WARRANTY; without even the implied warranty of 123fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 133fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * GNU General Public License for more details. 143fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * 153fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * You should have received a copy of the GNU General Public License 163fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * along with this program; if not, write to the Free Software 173fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 183fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm */ 193fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 203fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/init.h> 213fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/platform_device.h> 223fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/spinlock.h> 233fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/interrupt.h> 243fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/ioport.h> 253fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/io.h> 263fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/clk.h> 273fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/irq.h> 283fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/err.h> 293fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/clocksource.h> 303fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#include <linux/clockchips.h> 3146a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt#include <linux/sh_timer.h> 323fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 333fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstruct sh_cmt_priv { 343fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm void __iomem *mapbase; 353fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct clk *clk; 363fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long width; /* 16 or 32 bit version of hardware block */ 373fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long overflow_bit; 383fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long clear_bits; 393fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct irqaction irqaction; 403fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct platform_device *pdev; 413fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 423fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long flags; 43f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm unsigned long flags_suspend; 443fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long match_value; 453fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long next_match_value; 463fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long max_match_value; 473fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long rate; 483fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spinlock_t lock; 493fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct clock_event_device ced; 5019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm struct clocksource cs; 513fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long total_cycles; 523fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm}; 533fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 543fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic DEFINE_SPINLOCK(sh_cmt_lock); 553fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 563fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define CMSTR -1 /* shared register */ 573fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define CMCSR 0 /* channel register */ 583fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define CMCNT 1 /* channel register */ 593fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define CMCOR 2 /* channel register */ 603fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 613fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr) 623fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 6346a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = p->pdev->dev.platform_data; 643fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm void __iomem *base = p->mapbase; 653fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long offs; 663fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 673fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (reg_nr == CMSTR) { 683fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm offs = 0; 693fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm base -= cfg->channel_offset; 703fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } else 713fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm offs = reg_nr; 723fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 733fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->width == 16) 743fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm offs <<= 1; 753fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm else { 763fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm offs <<= 2; 773fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if ((reg_nr == CMCNT) || (reg_nr == CMCOR)) 783fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return ioread32(base + offs); 793fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 803fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 813fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return ioread16(base + offs); 823fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 833fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 843fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr, 853fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long value) 863fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 8746a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = p->pdev->dev.platform_data; 883fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm void __iomem *base = p->mapbase; 893fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long offs; 903fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 913fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (reg_nr == CMSTR) { 923fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm offs = 0; 933fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm base -= cfg->channel_offset; 943fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } else 953fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm offs = reg_nr; 963fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 973fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->width == 16) 983fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm offs <<= 1; 993fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm else { 1003fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm offs <<= 2; 1013fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if ((reg_nr == CMCNT) || (reg_nr == CMCOR)) { 1023fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm iowrite32(value, base + offs); 1033fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return; 1043fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 1053fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 1063fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1073fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm iowrite16(value, base + offs); 1083fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 1093fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1103fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p, 1113fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm int *has_wrapped) 1123fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 1133fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long v1, v2, v3; 1145b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm int o1, o2; 1155b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm 1165b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit; 1173fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1183fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* Make sure the timer value is stable. Stolen from acpi_pm.c */ 1193fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm do { 1205b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm o2 = o1; 1213fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm v1 = sh_cmt_read(p, CMCNT); 1223fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm v2 = sh_cmt_read(p, CMCNT); 1233fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm v3 = sh_cmt_read(p, CMCNT); 1245b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit; 1255b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3) 1265b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); 1273fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1285b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm *has_wrapped = o1; 1293fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return v2; 1303fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 1313fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1323fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1333fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start) 1343fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 13546a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = p->pdev->dev.platform_data; 1363fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long flags, value; 1373fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1383fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* start stop register shared by multiple timer channels */ 1393fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_lock_irqsave(&sh_cmt_lock, flags); 1403fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm value = sh_cmt_read(p, CMSTR); 1413fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1423fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (start) 1433fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm value |= 1 << cfg->timer_bit; 1443fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm else 1453fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm value &= ~(1 << cfg->timer_bit); 1463fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1473fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_write(p, CMSTR, value); 1483fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_unlock_irqrestore(&sh_cmt_lock, flags); 1493fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 1503fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1513fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate) 1523fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 15346a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = p->pdev->dev.platform_data; 1543fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm int ret; 1553fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1563fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* enable clock */ 1573fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ret = clk_enable(p->clk); 1583fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (ret) { 1593fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk); 1603fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return ret; 1613fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 1623fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1633fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* make sure channel is disabled */ 1643fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_start_stop_ch(p, 0); 1653fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1663fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* configure channel, periodic mode and maximum timeout */ 1673014f47460ecfb13d4169daae51f26a20bacfa17Magnus Damm if (p->width == 16) { 1683014f47460ecfb13d4169daae51f26a20bacfa17Magnus Damm *rate = clk_get_rate(p->clk) / 512; 1693014f47460ecfb13d4169daae51f26a20bacfa17Magnus Damm sh_cmt_write(p, CMCSR, 0x43); 1703014f47460ecfb13d4169daae51f26a20bacfa17Magnus Damm } else { 1713014f47460ecfb13d4169daae51f26a20bacfa17Magnus Damm *rate = clk_get_rate(p->clk) / 8; 1723fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_write(p, CMCSR, 0x01a4); 1733014f47460ecfb13d4169daae51f26a20bacfa17Magnus Damm } 1743fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1753fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_write(p, CMCOR, 0xffffffff); 1763fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_write(p, CMCNT, 0); 1773fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1783fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* enable channel */ 1793fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_start_stop_ch(p, 1); 1803fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return 0; 1813fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 1823fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1833fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void sh_cmt_disable(struct sh_cmt_priv *p) 1843fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 1853fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* disable channel */ 1863fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_start_stop_ch(p, 0); 1873fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 188be890a1a95fb439594e796f1968f86ee9f36e718Magnus Damm /* disable interrupts in CMT block */ 189be890a1a95fb439594e796f1968f86ee9f36e718Magnus Damm sh_cmt_write(p, CMCSR, 0); 190be890a1a95fb439594e796f1968f86ee9f36e718Magnus Damm 1913fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* stop clock */ 1923fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm clk_disable(p->clk); 1933fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 1943fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 1953fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm/* private flags */ 1963fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define FLAG_CLOCKEVENT (1 << 0) 1973fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define FLAG_CLOCKSOURCE (1 << 1) 1983fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define FLAG_REPROGRAM (1 << 2) 1993fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define FLAG_SKIPEVENT (1 << 3) 2003fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm#define FLAG_IRQCONTEXT (1 << 4) 2013fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2023fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p, 2033fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm int absolute) 2043fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 2053fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long new_match; 2063fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long value = p->next_match_value; 2073fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long delay = 0; 2083fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long now = 0; 2093fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm int has_wrapped; 2103fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2113fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm now = sh_cmt_get_counter(p, &has_wrapped); 2123fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags |= FLAG_REPROGRAM; /* force reprogram */ 2133fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2143fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (has_wrapped) { 2153fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* we're competing with the interrupt handler. 2163fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> let the interrupt handler reprogram the timer. 2173fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> interrupt number two handles the event. 2183fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm */ 2193fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags |= FLAG_SKIPEVENT; 2203fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return; 2213fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 2223fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2233fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (absolute) 2243fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm now = 0; 2253fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2263fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm do { 2273fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* reprogram the timer hardware, 2283fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * but don't save the new match value yet. 2293fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm */ 2303fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm new_match = now + value + delay; 2313fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (new_match > p->max_match_value) 2323fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm new_match = p->max_match_value; 2333fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2343fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_write(p, CMCOR, new_match); 2353fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2363fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm now = sh_cmt_get_counter(p, &has_wrapped); 2373fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (has_wrapped && (new_match > p->match_value)) { 2383fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* we are changing to a greater match value, 2393fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * so this wrap must be caused by the counter 2403fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * matching the old value. 2413fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> first interrupt reprograms the timer. 2423fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> interrupt number two handles the event. 2433fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm */ 2443fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags |= FLAG_SKIPEVENT; 2453fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 2463fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 2473fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2483fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (has_wrapped) { 2493fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* we are changing to a smaller match value, 2503fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * so the wrap must be caused by the counter 2513fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * matching the new value. 2523fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> save programmed match value. 2533fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> let isr handle the event. 2543fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm */ 2553fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->match_value = new_match; 2563fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 2573fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 2583fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2593fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* be safe: verify hardware settings */ 2603fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (now < new_match) { 2613fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* timer value is below match value, all good. 2623fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * this makes sure we won't miss any match events. 2633fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> save programmed match value. 2643fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> let isr handle the event. 2653fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm */ 2663fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->match_value = new_match; 2673fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 2683fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 2693fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2703fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* the counter has reached a value greater 2713fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * than our new match value. and since the 2723fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * has_wrapped flag isn't set we must have 2733fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * programmed a too close event. 2743fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * -> increase delay and retry. 2753fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm */ 2763fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (delay) 2773fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm delay <<= 1; 2783fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm else 2793fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm delay = 1; 2803fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2813fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (!delay) 2823fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm pr_warning("sh_cmt: too long delay\n"); 2833fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2843fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } while (delay); 2853fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 2863fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2873fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) 2883fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 2893fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long flags; 2903fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2913fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (delta > p->max_match_value) 2923fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm pr_warning("sh_cmt: delta out of range\n"); 2933fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 2943fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_lock_irqsave(&p->lock, flags); 2953fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->next_match_value = delta; 2963fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_clock_event_program_verify(p, 0); 2973fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_unlock_irqrestore(&p->lock, flags); 2983fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 2993fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3003fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) 3013fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 3023fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct sh_cmt_priv *p = dev_id; 3033fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3043fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* clear flags */ 3053fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_write(p, CMCSR, sh_cmt_read(p, CMCSR) & p->clear_bits); 3063fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3073fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* update clock source counter to begin with if enabled 3083fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * the wrap flag should be cleared by the timer specific 3093fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm * isr before we end up here. 3103fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm */ 3113fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->flags & FLAG_CLOCKSOURCE) 3123fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->total_cycles += p->match_value; 3133fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3143fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (!(p->flags & FLAG_REPROGRAM)) 3153fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->next_match_value = p->max_match_value; 3163fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3173fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags |= FLAG_IRQCONTEXT; 3183fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3193fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->flags & FLAG_CLOCKEVENT) { 3203fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (!(p->flags & FLAG_SKIPEVENT)) { 3213fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) { 3223fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->next_match_value = p->max_match_value; 3233fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags |= FLAG_REPROGRAM; 3243fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 3253fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3263fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->ced.event_handler(&p->ced); 3273fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 3283fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 3293fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3303fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags &= ~FLAG_SKIPEVENT; 3313fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3323fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->flags & FLAG_REPROGRAM) { 3333fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags &= ~FLAG_REPROGRAM; 3343fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_clock_event_program_verify(p, 1); 3353fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3363fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->flags & FLAG_CLOCKEVENT) 3373fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if ((p->ced.mode == CLOCK_EVT_MODE_SHUTDOWN) 3383fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm || (p->match_value == p->next_match_value)) 3393fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags &= ~FLAG_REPROGRAM; 3403fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 3413fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3423fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags &= ~FLAG_IRQCONTEXT; 3433fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3443fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return IRQ_HANDLED; 3453fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 3463fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3473fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic int sh_cmt_start(struct sh_cmt_priv *p, unsigned long flag) 3483fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 3493fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm int ret = 0; 3503fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long flags; 3513fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3523fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_lock_irqsave(&p->lock, flags); 3533fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3543fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (!(p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) 3553fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ret = sh_cmt_enable(p, &p->rate); 3563fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3573fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (ret) 3583fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm goto out; 3593fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags |= flag; 3603fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3613fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* setup timeout if no clockevent */ 3623fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT))) 3633fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_set_next(p, p->max_match_value); 3643fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm out: 3653fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_unlock_irqrestore(&p->lock, flags); 3663fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3673fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return ret; 3683fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 3693fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3703fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag) 3713fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 3723fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long flags; 3733fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm unsigned long f; 3743fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3753fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_lock_irqsave(&p->lock, flags); 3763fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3773fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm f = p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE); 3783fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->flags &= ~flag; 3793fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3803fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (f && !(p->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE))) 3813fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_disable(p); 3823fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3833fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* adjust the timeout to maximum if only clocksource left */ 3843fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE)) 3853fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_set_next(p, p->max_match_value); 3863fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 3873fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_unlock_irqrestore(&p->lock, flags); 3883fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 3893fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 39019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Dammstatic struct sh_cmt_priv *cs_to_sh_cmt(struct clocksource *cs) 39119bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm{ 39219bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm return container_of(cs, struct sh_cmt_priv, cs); 39319bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm} 39419bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 39519bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Dammstatic cycle_t sh_cmt_clocksource_read(struct clocksource *cs) 39619bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm{ 39719bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm struct sh_cmt_priv *p = cs_to_sh_cmt(cs); 39819bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm unsigned long flags, raw; 39919bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm unsigned long value; 40019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm int has_wrapped; 40119bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 40219bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm spin_lock_irqsave(&p->lock, flags); 40319bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm value = p->total_cycles; 40419bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm raw = sh_cmt_get_counter(p, &has_wrapped); 40519bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 40619bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm if (unlikely(has_wrapped)) 4075b644c7a218702668d7b610994e7dcbc3d4705d3Magnus Damm raw += p->match_value; 40819bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm spin_unlock_irqrestore(&p->lock, flags); 40919bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 41019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm return value + raw; 41119bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm} 41219bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 41319bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Dammstatic int sh_cmt_clocksource_enable(struct clocksource *cs) 41419bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm{ 41519bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm struct sh_cmt_priv *p = cs_to_sh_cmt(cs); 41619bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm int ret; 41719bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 41819bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm p->total_cycles = 0; 41919bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 42019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm ret = sh_cmt_start(p, FLAG_CLOCKSOURCE); 42119bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm if (ret) 42219bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm return ret; 42319bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 42419bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm /* TODO: calculate good shift from rate and counter bit width */ 42519bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->shift = 0; 42619bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->mult = clocksource_hz2mult(p->rate, cs->shift); 42719bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm return 0; 42819bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm} 42919bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 43019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Dammstatic void sh_cmt_clocksource_disable(struct clocksource *cs) 43119bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm{ 43219bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE); 43319bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm} 43419bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 43519bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Dammstatic int sh_cmt_register_clocksource(struct sh_cmt_priv *p, 43619bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm char *name, unsigned long rating) 43719bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm{ 43819bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm struct clocksource *cs = &p->cs; 43919bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 44019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->name = name; 44119bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->rating = rating; 44219bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->read = sh_cmt_clocksource_read; 44319bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->enable = sh_cmt_clocksource_enable; 44419bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->disable = sh_cmt_clocksource_disable; 44519bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8); 44619bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; 44719bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm pr_info("sh_cmt: %s used as clock source\n", cs->name); 44819bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm clocksource_register(cs); 44919bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm return 0; 45019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm} 45119bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 4523fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced) 4533fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 4543fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return container_of(ced, struct sh_cmt_priv, ced); 4553fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 4563fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 4573fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void sh_cmt_clock_event_start(struct sh_cmt_priv *p, int periodic) 4583fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 4593fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct clock_event_device *ced = &p->ced; 4603fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 4613fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_start(p, FLAG_CLOCKEVENT); 4623fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 4633fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* TODO: calculate good shift from rate and counter bit width */ 4643fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 4653fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->shift = 32; 4663fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift); 4673fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->max_delta_ns = clockevent_delta2ns(p->max_match_value, ced); 4683fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->min_delta_ns = clockevent_delta2ns(0x1f, ced); 4693fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 4703fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (periodic) 4713fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_set_next(p, (p->rate + HZ/2) / HZ); 4723fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm else 4733fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_set_next(p, p->max_match_value); 4743fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 4753fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 4763fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void sh_cmt_clock_event_mode(enum clock_event_mode mode, 4773fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct clock_event_device *ced) 4783fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 4793fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct sh_cmt_priv *p = ced_to_sh_cmt(ced); 4803fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 4813fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* deal with old setting first */ 4823fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm switch (ced->mode) { 4833fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm case CLOCK_EVT_MODE_PERIODIC: 4843fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm case CLOCK_EVT_MODE_ONESHOT: 4853fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_stop(p, FLAG_CLOCKEVENT); 4863fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 4873fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm default: 4883fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 4893fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 4903fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 4913fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm switch (mode) { 4923fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm case CLOCK_EVT_MODE_PERIODIC: 4933fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm pr_info("sh_cmt: %s used for periodic clock events\n", 4943fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->name); 4953fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_clock_event_start(p, 1); 4963fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 4973fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm case CLOCK_EVT_MODE_ONESHOT: 4983fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm pr_info("sh_cmt: %s used for oneshot clock events\n", 4993fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->name); 5003fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_clock_event_start(p, 0); 5013fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 5023fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm case CLOCK_EVT_MODE_SHUTDOWN: 5033fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm case CLOCK_EVT_MODE_UNUSED: 5043fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_stop(p, FLAG_CLOCKEVENT); 5053fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 5063fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm default: 5073fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm break; 5083fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 5093fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 5103fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5113fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic int sh_cmt_clock_event_next(unsigned long delta, 5123fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct clock_event_device *ced) 5133fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 5143fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct sh_cmt_priv *p = ced_to_sh_cmt(ced); 5153fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5163fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); 5173fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (likely(p->flags & FLAG_IRQCONTEXT)) 5183fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->next_match_value = delta; 5193fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm else 5203fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_set_next(p, delta); 5213fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5223fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return 0; 5233fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 5243fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5253fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void sh_cmt_register_clockevent(struct sh_cmt_priv *p, 5263fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm char *name, unsigned long rating) 5273fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 5283fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct clock_event_device *ced = &p->ced; 5293fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5303fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm memset(ced, 0, sizeof(*ced)); 5313fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5323fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->name = name; 5333fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->features = CLOCK_EVT_FEAT_PERIODIC; 5343fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->features |= CLOCK_EVT_FEAT_ONESHOT; 5353fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->rating = rating; 5363fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->cpumask = cpumask_of(0); 5373fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->set_next_event = sh_cmt_clock_event_next; 5383fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ced->set_mode = sh_cmt_clock_event_mode; 5393fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5403fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm pr_info("sh_cmt: %s used for clock events\n", ced->name); 5413fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm clockevents_register_device(ced); 5423fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 5433fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 544d1fcc0a8db5e47c1abaa783a3e83dbf5f2184969Paul Mundtstatic int sh_cmt_register(struct sh_cmt_priv *p, char *name, 545d1fcc0a8db5e47c1abaa783a3e83dbf5f2184969Paul Mundt unsigned long clockevent_rating, 546d1fcc0a8db5e47c1abaa783a3e83dbf5f2184969Paul Mundt unsigned long clocksource_rating) 5473fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 5483fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->width == (sizeof(p->max_match_value) * 8)) 5493fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->max_match_value = ~0; 5503fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm else 5513fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->max_match_value = (1 << p->width) - 1; 5523fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5533fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->match_value = p->max_match_value; 5543fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm spin_lock_init(&p->lock); 5553fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5563fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (clockevent_rating) 5573fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm sh_cmt_register_clockevent(p, name, clockevent_rating); 5583fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 55919bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm if (clocksource_rating) 56019bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm sh_cmt_register_clocksource(p, name, clocksource_rating); 56119bdc9d061bcb71efd2b53083d96b59bbe1a1751Magnus Damm 5623fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return 0; 5633fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 5643fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5653fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) 5663fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 56746a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = pdev->dev.platform_data; 5683fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct resource *res; 5693fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm int irq, ret; 5703fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ret = -ENXIO; 5713fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5723fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm memset(p, 0, sizeof(*p)); 5733fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->pdev = pdev; 5743fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5753fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (!cfg) { 5763fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm dev_err(&p->pdev->dev, "missing platform data\n"); 5773fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm goto err0; 5783fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 5793fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5803fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm platform_set_drvdata(pdev, p); 5813fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5823fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); 5833fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (!res) { 5843fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm dev_err(&p->pdev->dev, "failed to get I/O memory\n"); 5853fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm goto err0; 5863fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 5873fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5883fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm irq = platform_get_irq(p->pdev, 0); 5893fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (irq < 0) { 5903fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm dev_err(&p->pdev->dev, "failed to get irq\n"); 5913fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm goto err0; 5923fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 5933fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 5943fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* map memory, let mapbase point to our channel */ 5953fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->mapbase = ioremap_nocache(res->start, resource_size(res)); 5963fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p->mapbase == NULL) { 5973fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm pr_err("sh_cmt: failed to remap I/O memory\n"); 5983fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm goto err0; 5993fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 6003fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 6013fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* request irq using setup_irq() (too early for request_irq()) */ 6023fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->irqaction.name = cfg->name; 6033fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->irqaction.handler = sh_cmt_interrupt; 6043fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->irqaction.dev_id = p; 6053fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL; 6063fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 6073fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm /* get hold of clock */ 6083fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->clk = clk_get(&p->pdev->dev, cfg->clk); 6093fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (IS_ERR(p->clk)) { 6103fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk); 6113fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ret = PTR_ERR(p->clk); 612da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt goto err1; 6133fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 6143fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 6153fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (resource_size(res) == 6) { 6163fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->width = 16; 6173fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->overflow_bit = 0x80; 6183014f47460ecfb13d4169daae51f26a20bacfa17Magnus Damm p->clear_bits = ~0x80; 6193fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } else { 6203fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->width = 32; 6213fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->overflow_bit = 0x8000; 6223fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm p->clear_bits = ~0xc000; 6233fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 6243fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 625da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt ret = sh_cmt_register(p, cfg->name, 626da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt cfg->clockevent_rating, 627da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt cfg->clocksource_rating); 628da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt if (ret) { 629da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt pr_err("sh_cmt: registration failed\n"); 630da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt goto err1; 631da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt } 632da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt 633da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt ret = setup_irq(irq, &p->irqaction); 634da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt if (ret) { 635da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt pr_err("sh_cmt: failed to request irq %d\n", irq); 636da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt goto err1; 637da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt } 638da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt 639da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt return 0; 640da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundt 641da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundterr1: 6423fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm iounmap(p->mapbase); 643da64c2a8dee66ca03f4f3e15d84be7bedf73db3dPaul Mundterr0: 6443fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return ret; 6453fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 6463fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 6473fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic int __devinit sh_cmt_probe(struct platform_device *pdev) 6483fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 6493fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm struct sh_cmt_priv *p = platform_get_drvdata(pdev); 65046a12f7426d71cabc08972cf8d3ffdd441d26a3aPaul Mundt struct sh_timer_config *cfg = pdev->dev.platform_data; 6513fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm int ret; 6523fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 653e475eedb09ee9a0fd855f3e923aa9af31c17d141Magnus Damm if (p) { 654e475eedb09ee9a0fd855f3e923aa9af31c17d141Magnus Damm pr_info("sh_cmt: %s kept as earlytimer\n", cfg->name); 655e475eedb09ee9a0fd855f3e923aa9af31c17d141Magnus Damm return 0; 656e475eedb09ee9a0fd855f3e923aa9af31c17d141Magnus Damm } 657e475eedb09ee9a0fd855f3e923aa9af31c17d141Magnus Damm 6588e0b842948156e3463879caed12b4ce51bed772eMagnus Damm p = kmalloc(sizeof(*p), GFP_KERNEL); 6593fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (p == NULL) { 6603fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm dev_err(&pdev->dev, "failed to allocate driver data\n"); 6613fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return -ENOMEM; 6623fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 6633fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 6643fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm ret = sh_cmt_setup(p, pdev); 6653fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm if (ret) { 6668e0b842948156e3463879caed12b4ce51bed772eMagnus Damm kfree(p); 6673fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm platform_set_drvdata(pdev, NULL); 6683fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 6693fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return ret; 6703fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 6713fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 6723fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic int __devexit sh_cmt_remove(struct platform_device *pdev) 6733fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 6743fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return -EBUSY; /* cannot unregister clockevent and clocksource */ 6753fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 6763fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 677f6431732f128a241b149c0aa85dfec852455ebf9Magnus Dammstatic int sh_cmt_suspend(struct device *dev) 678f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm{ 679f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm struct platform_device *pdev = to_platform_device(dev); 680f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm struct sh_cmt_priv *p = platform_get_drvdata(pdev); 681f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm 682f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm /* save flag state and stop CMT channel */ 683f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm p->flags_suspend = p->flags; 684f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm sh_cmt_stop(p, p->flags); 685f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm return 0; 686f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm} 687f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm 688f6431732f128a241b149c0aa85dfec852455ebf9Magnus Dammstatic int sh_cmt_resume(struct device *dev) 689f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm{ 690f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm struct platform_device *pdev = to_platform_device(dev); 691f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm struct sh_cmt_priv *p = platform_get_drvdata(pdev); 692f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm 693f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm /* start CMT channel from saved state */ 694f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm sh_cmt_start(p, p->flags_suspend); 695f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm return 0; 696f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm} 697f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm 698f6431732f128a241b149c0aa85dfec852455ebf9Magnus Dammstatic struct dev_pm_ops sh_cmt_dev_pm_ops = { 699f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm .suspend = sh_cmt_suspend, 700f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm .resume = sh_cmt_resume, 701f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm}; 702f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm 7033fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic struct platform_driver sh_cmt_device_driver = { 7043fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm .probe = sh_cmt_probe, 7053fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm .remove = __devexit_p(sh_cmt_remove), 7063fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm .driver = { 7073fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm .name = "sh_cmt", 708f6431732f128a241b149c0aa85dfec852455ebf9Magnus Damm .pm = &sh_cmt_dev_pm_ops, 7093fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm } 7103fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm}; 7113fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 7123fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic int __init sh_cmt_init(void) 7133fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 7143fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm return platform_driver_register(&sh_cmt_device_driver); 7153fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 7163fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 7173fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammstatic void __exit sh_cmt_exit(void) 7183fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm{ 7193fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm platform_driver_unregister(&sh_cmt_device_driver); 7203fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm} 7213fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 722e475eedb09ee9a0fd855f3e923aa9af31c17d141Magnus Dammearly_platform_init("earlytimer", &sh_cmt_device_driver); 7233fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammmodule_init(sh_cmt_init); 7243fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Dammmodule_exit(sh_cmt_exit); 7253fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus Damm 7263fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus DammMODULE_AUTHOR("Magnus Damm"); 7273fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus DammMODULE_DESCRIPTION("SuperH CMT Timer Driver"); 7283fb1b6ad0679ad671bd496712b2a088550ee86b2Magnus DammMODULE_LICENSE("GPL v2"); 729