dmtimer.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. /*
  2. * linux/arch/arm/plat-omap/dmtimer.c
  3. *
  4. * OMAP Dual-Mode Timers
  5. *
  6. * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
  7. * Tarun Kanti DebBarma <tarun.kanti@ti.com>
  8. * Thara Gopinath <thara@ti.com>
  9. *
  10. * dmtimer adaptation to platform_driver.
  11. *
  12. * Copyright (C) 2005 Nokia Corporation
  13. * OMAP2 support by Juha Yrjola
  14. * API improvements and OMAP2 clock framework support by Timo Teras
  15. *
  16. * Copyright (C) 2009 Texas Instruments
  17. * 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. */
  37. #include <linux/clk.h>
  38. #include <linux/module.h>
  39. #include <linux/io.h>
  40. #include <linux/device.h>
  41. #include <linux/err.h>
  42. #include <linux/pm_runtime.h>
  43. #include <linux/of.h>
  44. #include <linux/of_device.h>
  45. #include <linux/platform_device.h>
  46. #include <linux/platform_data/dmtimer-omap.h>
  47. #include <plat/dmtimer.h>
  48. static u32 omap_reserved_systimers;
  49. static LIST_HEAD(omap_timer_list);
  50. static DEFINE_SPINLOCK(dm_timer_lock);
  51. /**
  52. * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
  53. * @timer: timer pointer over which read operation to perform
  54. * @reg: lowest byte holds the register offset
  55. *
  56. * The posted mode bit is encoded in reg. Note that in posted mode write
  57. * pending bit must be checked. Otherwise a read of a non completed write
  58. * will produce an error.
  59. */
  60. static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
  61. {
  62. WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
  63. return __omap_dm_timer_read(timer, reg, timer->posted);
  64. }
  65. /**
  66. * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
  67. * @timer: timer pointer over which write operation is to perform
  68. * @reg: lowest byte holds the register offset
  69. * @value: data to write into the register
  70. *
  71. * The posted mode bit is encoded in reg. Note that in posted mode the write
  72. * pending bit must be checked. Otherwise a write on a register which has a
  73. * pending write will be lost.
  74. */
  75. static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
  76. u32 value)
  77. {
  78. WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
  79. __omap_dm_timer_write(timer, reg, value, timer->posted);
  80. }
  81. static void omap_timer_restore_context(struct omap_dm_timer *timer)
  82. {
  83. omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
  84. timer->context.twer);
  85. omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
  86. timer->context.tcrr);
  87. omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
  88. timer->context.tldr);
  89. omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG,
  90. timer->context.tmar);
  91. omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG,
  92. timer->context.tsicr);
  93. __raw_writel(timer->context.tier, timer->irq_ena);
  94. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG,
  95. timer->context.tclr);
  96. }
  97. static int omap_dm_timer_reset(struct omap_dm_timer *timer)
  98. {
  99. u32 l, timeout = 100000;
  100. if (timer->revision != 1)
  101. return -EINVAL;
  102. omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
  103. do {
  104. l = __omap_dm_timer_read(timer,
  105. OMAP_TIMER_V1_SYS_STAT_OFFSET, 0);
  106. } while (!l && timeout--);
  107. if (!timeout) {
  108. dev_err(&timer->pdev->dev, "Timer failed to reset\n");
  109. return -ETIMEDOUT;
  110. }
  111. /* Configure timer for smart-idle mode */
  112. l = __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
  113. l |= 0x2 << 0x3;
  114. __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l, 0);
  115. timer->posted = 0;
  116. return 0;
  117. }
  118. static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
  119. {
  120. int rc;
  121. /*
  122. * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
  123. * do not call clk_get() for these devices.
  124. */
  125. if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
  126. timer->fclk = clk_get(&timer->pdev->dev, "fck");
  127. if (WARN_ON_ONCE(IS_ERR(timer->fclk))) {
  128. dev_err(&timer->pdev->dev, ": No fclk handle.\n");
  129. return -EINVAL;
  130. }
  131. }
  132. omap_dm_timer_enable(timer);
  133. if (timer->capability & OMAP_TIMER_NEEDS_RESET) {
  134. rc = omap_dm_timer_reset(timer);
  135. if (rc) {
  136. omap_dm_timer_disable(timer);
  137. return rc;
  138. }
  139. }
  140. __omap_dm_timer_enable_posted(timer);
  141. omap_dm_timer_disable(timer);
  142. return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
  143. }
  144. static inline u32 omap_dm_timer_reserved_systimer(int id)
  145. {
  146. return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0;
  147. }
  148. int omap_dm_timer_reserve_systimer(int id)
  149. {
  150. if (omap_dm_timer_reserved_systimer(id))
  151. return -ENODEV;
  152. omap_reserved_systimers |= (1 << (id - 1));
  153. return 0;
  154. }
  155. struct omap_dm_timer *omap_dm_timer_request(void)
  156. {
  157. struct omap_dm_timer *timer = NULL, *t;
  158. unsigned long flags;
  159. int ret = 0;
  160. spin_lock_irqsave(&dm_timer_lock, flags);
  161. list_for_each_entry(t, &omap_timer_list, node) {
  162. if (t->reserved)
  163. continue;
  164. timer = t;
  165. timer->reserved = 1;
  166. break;
  167. }
  168. spin_unlock_irqrestore(&dm_timer_lock, flags);
  169. if (timer) {
  170. ret = omap_dm_timer_prepare(timer);
  171. if (ret) {
  172. timer->reserved = 0;
  173. timer = NULL;
  174. }
  175. }
  176. if (!timer)
  177. pr_debug("%s: timer request failed!\n", __func__);
  178. return timer;
  179. }
  180. EXPORT_SYMBOL_GPL(omap_dm_timer_request);
  181. struct omap_dm_timer *omap_dm_timer_request_specific(int id)
  182. {
  183. struct omap_dm_timer *timer = NULL, *t;
  184. unsigned long flags;
  185. int ret = 0;
  186. /* Requesting timer by ID is not supported when device tree is used */
  187. if (of_have_populated_dt()) {
  188. pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n",
  189. __func__);
  190. return NULL;
  191. }
  192. spin_lock_irqsave(&dm_timer_lock, flags);
  193. list_for_each_entry(t, &omap_timer_list, node) {
  194. if (t->pdev->id == id && !t->reserved) {
  195. timer = t;
  196. timer->reserved = 1;
  197. break;
  198. }
  199. }
  200. spin_unlock_irqrestore(&dm_timer_lock, flags);
  201. if (timer) {
  202. ret = omap_dm_timer_prepare(timer);
  203. if (ret) {
  204. timer->reserved = 0;
  205. timer = NULL;
  206. }
  207. }
  208. if (!timer)
  209. pr_debug("%s: timer%d request failed!\n", __func__, id);
  210. return timer;
  211. }
  212. EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
  213. /**
  214. * omap_dm_timer_request_by_cap - Request a timer by capability
  215. * @cap: Bit mask of capabilities to match
  216. *
  217. * Find a timer based upon capabilities bit mask. Callers of this function
  218. * should use the definitions found in the plat/dmtimer.h file under the
  219. * comment "timer capabilities used in hwmod database". Returns pointer to
  220. * timer handle on success and a NULL pointer on failure.
  221. */
  222. struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
  223. {
  224. struct omap_dm_timer *timer = NULL, *t;
  225. unsigned long flags;
  226. if (!cap)
  227. return NULL;
  228. spin_lock_irqsave(&dm_timer_lock, flags);
  229. list_for_each_entry(t, &omap_timer_list, node) {
  230. if ((!t->reserved) && ((t->capability & cap) == cap)) {
  231. /*
  232. * If timer is not NULL, we have already found one timer
  233. * but it was not an exact match because it had more
  234. * capabilites that what was required. Therefore,
  235. * unreserve the last timer found and see if this one
  236. * is a better match.
  237. */
  238. if (timer)
  239. timer->reserved = 0;
  240. timer = t;
  241. timer->reserved = 1;
  242. /* Exit loop early if we find an exact match */
  243. if (t->capability == cap)
  244. break;
  245. }
  246. }
  247. spin_unlock_irqrestore(&dm_timer_lock, flags);
  248. if (timer && omap_dm_timer_prepare(timer)) {
  249. timer->reserved = 0;
  250. timer = NULL;
  251. }
  252. if (!timer)
  253. pr_debug("%s: timer request failed!\n", __func__);
  254. return timer;
  255. }
  256. EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
  257. int omap_dm_timer_free(struct omap_dm_timer *timer)
  258. {
  259. if (unlikely(!timer))
  260. return -EINVAL;
  261. clk_put(timer->fclk);
  262. WARN_ON(!timer->reserved);
  263. timer->reserved = 0;
  264. return 0;
  265. }
  266. EXPORT_SYMBOL_GPL(omap_dm_timer_free);
  267. void omap_dm_timer_enable(struct omap_dm_timer *timer)
  268. {
  269. pm_runtime_get_sync(&timer->pdev->dev);
  270. }
  271. EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
  272. void omap_dm_timer_disable(struct omap_dm_timer *timer)
  273. {
  274. pm_runtime_put_sync(&timer->pdev->dev);
  275. }
  276. EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
  277. int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
  278. {
  279. if (timer)
  280. return timer->irq;
  281. return -EINVAL;
  282. }
  283. EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
  284. #if defined(CONFIG_ARCH_OMAP1)
  285. #include <mach/hardware.h>
  286. /**
  287. * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
  288. * @inputmask: current value of idlect mask
  289. */
  290. __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
  291. {
  292. int i = 0;
  293. struct omap_dm_timer *timer = NULL;
  294. unsigned long flags;
  295. /* If ARMXOR cannot be idled this function call is unnecessary */
  296. if (!(inputmask & (1 << 1)))
  297. return inputmask;
  298. /* If any active timer is using ARMXOR return modified mask */
  299. spin_lock_irqsave(&dm_timer_lock, flags);
  300. list_for_each_entry(timer, &omap_timer_list, node) {
  301. u32 l;
  302. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  303. if (l & OMAP_TIMER_CTRL_ST) {
  304. if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
  305. inputmask &= ~(1 << 1);
  306. else
  307. inputmask &= ~(1 << 2);
  308. }
  309. i++;
  310. }
  311. spin_unlock_irqrestore(&dm_timer_lock, flags);
  312. return inputmask;
  313. }
  314. EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
  315. #else
  316. struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
  317. {
  318. if (timer && !IS_ERR(timer->fclk))
  319. return timer->fclk;
  320. return NULL;
  321. }
  322. EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
  323. __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
  324. {
  325. BUG();
  326. return 0;
  327. }
  328. EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
  329. #endif
  330. int omap_dm_timer_trigger(struct omap_dm_timer *timer)
  331. {
  332. if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
  333. pr_err("%s: timer not available or enabled.\n", __func__);
  334. return -EINVAL;
  335. }
  336. omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
  337. return 0;
  338. }
  339. EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
  340. int omap_dm_timer_start(struct omap_dm_timer *timer)
  341. {
  342. u32 l;
  343. if (unlikely(!timer))
  344. return -EINVAL;
  345. omap_dm_timer_enable(timer);
  346. if (!(timer->capability & OMAP_TIMER_ALWON)) {
  347. if (timer->get_context_loss_count &&
  348. timer->get_context_loss_count(&timer->pdev->dev) !=
  349. timer->ctx_loss_count)
  350. omap_timer_restore_context(timer);
  351. }
  352. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  353. if (!(l & OMAP_TIMER_CTRL_ST)) {
  354. l |= OMAP_TIMER_CTRL_ST;
  355. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  356. }
  357. /* Save the context */
  358. timer->context.tclr = l;
  359. return 0;
  360. }
  361. EXPORT_SYMBOL_GPL(omap_dm_timer_start);
  362. int omap_dm_timer_stop(struct omap_dm_timer *timer)
  363. {
  364. unsigned long rate = 0;
  365. if (unlikely(!timer))
  366. return -EINVAL;
  367. if (!(timer->capability & OMAP_TIMER_NEEDS_RESET))
  368. rate = clk_get_rate(timer->fclk);
  369. __omap_dm_timer_stop(timer, timer->posted, rate);
  370. if (!(timer->capability & OMAP_TIMER_ALWON)) {
  371. if (timer->get_context_loss_count)
  372. timer->ctx_loss_count =
  373. timer->get_context_loss_count(&timer->pdev->dev);
  374. }
  375. /*
  376. * Since the register values are computed and written within
  377. * __omap_dm_timer_stop, we need to use read to retrieve the
  378. * context.
  379. */
  380. timer->context.tclr =
  381. omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  382. omap_dm_timer_disable(timer);
  383. return 0;
  384. }
  385. EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
  386. int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
  387. {
  388. int ret;
  389. char *parent_name = NULL;
  390. struct clk *parent;
  391. struct dmtimer_platform_data *pdata;
  392. if (unlikely(!timer))
  393. return -EINVAL;
  394. pdata = timer->pdev->dev.platform_data;
  395. if (source < 0 || source >= 3)
  396. return -EINVAL;
  397. /*
  398. * FIXME: Used for OMAP1 devices only because they do not currently
  399. * use the clock framework to set the parent clock. To be removed
  400. * once OMAP1 migrated to using clock framework for dmtimers
  401. */
  402. if (pdata && pdata->set_timer_src)
  403. return pdata->set_timer_src(timer->pdev, source);
  404. if (IS_ERR(timer->fclk))
  405. return -EINVAL;
  406. switch (source) {
  407. case OMAP_TIMER_SRC_SYS_CLK:
  408. parent_name = "timer_sys_ck";
  409. break;
  410. case OMAP_TIMER_SRC_32_KHZ:
  411. parent_name = "timer_32k_ck";
  412. break;
  413. case OMAP_TIMER_SRC_EXT_CLK:
  414. parent_name = "timer_ext_ck";
  415. break;
  416. }
  417. parent = clk_get(&timer->pdev->dev, parent_name);
  418. if (IS_ERR(parent)) {
  419. pr_err("%s: %s not found\n", __func__, parent_name);
  420. return -EINVAL;
  421. }
  422. ret = clk_set_parent(timer->fclk, parent);
  423. if (ret < 0)
  424. pr_err("%s: failed to set %s as parent\n", __func__,
  425. parent_name);
  426. clk_put(parent);
  427. return ret;
  428. }
  429. EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
  430. int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
  431. unsigned int load)
  432. {
  433. u32 l;
  434. if (unlikely(!timer))
  435. return -EINVAL;
  436. omap_dm_timer_enable(timer);
  437. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  438. if (autoreload)
  439. l |= OMAP_TIMER_CTRL_AR;
  440. else
  441. l &= ~OMAP_TIMER_CTRL_AR;
  442. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  443. omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
  444. omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
  445. /* Save the context */
  446. timer->context.tclr = l;
  447. timer->context.tldr = load;
  448. omap_dm_timer_disable(timer);
  449. return 0;
  450. }
  451. EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
  452. /* Optimized set_load which removes costly spin wait in timer_start */
  453. int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
  454. unsigned int load)
  455. {
  456. u32 l;
  457. if (unlikely(!timer))
  458. return -EINVAL;
  459. omap_dm_timer_enable(timer);
  460. if (!(timer->capability & OMAP_TIMER_ALWON)) {
  461. if (timer->get_context_loss_count &&
  462. timer->get_context_loss_count(&timer->pdev->dev) !=
  463. timer->ctx_loss_count)
  464. omap_timer_restore_context(timer);
  465. }
  466. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  467. if (autoreload) {
  468. l |= OMAP_TIMER_CTRL_AR;
  469. omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
  470. } else {
  471. l &= ~OMAP_TIMER_CTRL_AR;
  472. }
  473. l |= OMAP_TIMER_CTRL_ST;
  474. __omap_dm_timer_load_start(timer, l, load, timer->posted);
  475. /* Save the context */
  476. timer->context.tclr = l;
  477. timer->context.tldr = load;
  478. timer->context.tcrr = load;
  479. return 0;
  480. }
  481. EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
  482. int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
  483. unsigned int match)
  484. {
  485. u32 l;
  486. if (unlikely(!timer))
  487. return -EINVAL;
  488. omap_dm_timer_enable(timer);
  489. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  490. if (enable)
  491. l |= OMAP_TIMER_CTRL_CE;
  492. else
  493. l &= ~OMAP_TIMER_CTRL_CE;
  494. omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
  495. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  496. /* Save the context */
  497. timer->context.tclr = l;
  498. timer->context.tmar = match;
  499. omap_dm_timer_disable(timer);
  500. return 0;
  501. }
  502. EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
  503. int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
  504. int toggle, int trigger)
  505. {
  506. u32 l;
  507. if (unlikely(!timer))
  508. return -EINVAL;
  509. omap_dm_timer_enable(timer);
  510. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  511. l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
  512. OMAP_TIMER_CTRL_PT | (0x03 << 10));
  513. if (def_on)
  514. l |= OMAP_TIMER_CTRL_SCPWM;
  515. if (toggle)
  516. l |= OMAP_TIMER_CTRL_PT;
  517. l |= trigger << 10;
  518. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  519. /* Save the context */
  520. timer->context.tclr = l;
  521. omap_dm_timer_disable(timer);
  522. return 0;
  523. }
  524. EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
  525. int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
  526. {
  527. u32 l;
  528. if (unlikely(!timer))
  529. return -EINVAL;
  530. omap_dm_timer_enable(timer);
  531. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  532. l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
  533. if (prescaler >= 0x00 && prescaler <= 0x07) {
  534. l |= OMAP_TIMER_CTRL_PRE;
  535. l |= prescaler << 2;
  536. }
  537. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  538. /* Save the context */
  539. timer->context.tclr = l;
  540. omap_dm_timer_disable(timer);
  541. return 0;
  542. }
  543. EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
  544. int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
  545. unsigned int value)
  546. {
  547. if (unlikely(!timer))
  548. return -EINVAL;
  549. omap_dm_timer_enable(timer);
  550. __omap_dm_timer_int_enable(timer, value);
  551. /* Save the context */
  552. timer->context.tier = value;
  553. timer->context.twer = value;
  554. omap_dm_timer_disable(timer);
  555. return 0;
  556. }
  557. EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
  558. /**
  559. * omap_dm_timer_set_int_disable - disable timer interrupts
  560. * @timer: pointer to timer handle
  561. * @mask: bit mask of interrupts to be disabled
  562. *
  563. * Disables the specified timer interrupts for a timer.
  564. */
  565. int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
  566. {
  567. u32 l = mask;
  568. if (unlikely(!timer))
  569. return -EINVAL;
  570. omap_dm_timer_enable(timer);
  571. if (timer->revision == 1)
  572. l = __raw_readl(timer->irq_ena) & ~mask;
  573. __raw_writel(l, timer->irq_dis);
  574. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
  575. omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
  576. /* Save the context */
  577. timer->context.tier &= ~mask;
  578. timer->context.twer &= ~mask;
  579. omap_dm_timer_disable(timer);
  580. return 0;
  581. }
  582. EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);
  583. unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
  584. {
  585. unsigned int l;
  586. if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
  587. pr_err("%s: timer not available or enabled.\n", __func__);
  588. return 0;
  589. }
  590. l = __raw_readl(timer->irq_stat);
  591. return l;
  592. }
  593. EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
  594. int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
  595. {
  596. if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
  597. return -EINVAL;
  598. __omap_dm_timer_write_status(timer, value);
  599. return 0;
  600. }
  601. EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
  602. unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
  603. {
  604. if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
  605. pr_err("%s: timer not iavailable or enabled.\n", __func__);
  606. return 0;
  607. }
  608. return __omap_dm_timer_read_counter(timer, timer->posted);
  609. }
  610. EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
  611. int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
  612. {
  613. if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
  614. pr_err("%s: timer not available or enabled.\n", __func__);
  615. return -EINVAL;
  616. }
  617. omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
  618. /* Save the context */
  619. timer->context.tcrr = value;
  620. return 0;
  621. }
  622. EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
  623. int omap_dm_timers_active(void)
  624. {
  625. struct omap_dm_timer *timer;
  626. list_for_each_entry(timer, &omap_timer_list, node) {
  627. if (!timer->reserved)
  628. continue;
  629. if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
  630. OMAP_TIMER_CTRL_ST) {
  631. return 1;
  632. }
  633. }
  634. return 0;
  635. }
  636. EXPORT_SYMBOL_GPL(omap_dm_timers_active);
  637. /**
  638. * omap_dm_timer_probe - probe function called for every registered device
  639. * @pdev: pointer to current timer platform device
  640. *
  641. * Called by driver framework at the end of device registration for all
  642. * timer devices.
  643. */
  644. static int omap_dm_timer_probe(struct platform_device *pdev)
  645. {
  646. unsigned long flags;
  647. struct omap_dm_timer *timer;
  648. struct resource *mem, *irq;
  649. struct device *dev = &pdev->dev;
  650. struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
  651. if (!pdata && !dev->of_node) {
  652. dev_err(dev, "%s: no platform data.\n", __func__);
  653. return -ENODEV;
  654. }
  655. irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
  656. if (unlikely(!irq)) {
  657. dev_err(dev, "%s: no IRQ resource.\n", __func__);
  658. return -ENODEV;
  659. }
  660. mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  661. if (unlikely(!mem)) {
  662. dev_err(dev, "%s: no memory resource.\n", __func__);
  663. return -ENODEV;
  664. }
  665. timer = devm_kzalloc(dev, sizeof(struct omap_dm_timer), GFP_KERNEL);
  666. if (!timer) {
  667. dev_err(dev, "%s: memory alloc failed!\n", __func__);
  668. return -ENOMEM;
  669. }
  670. timer->fclk = ERR_PTR(-ENODEV);
  671. timer->io_base = devm_request_and_ioremap(dev, mem);
  672. if (!timer->io_base) {
  673. dev_err(dev, "%s: region already claimed.\n", __func__);
  674. return -ENOMEM;
  675. }
  676. if (dev->of_node) {
  677. if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
  678. timer->capability |= OMAP_TIMER_ALWON;
  679. if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
  680. timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
  681. if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
  682. timer->capability |= OMAP_TIMER_HAS_PWM;
  683. if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
  684. timer->capability |= OMAP_TIMER_SECURE;
  685. } else {
  686. timer->id = pdev->id;
  687. timer->errata = pdata->timer_errata;
  688. timer->capability = pdata->timer_capability;
  689. timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
  690. timer->get_context_loss_count = pdata->get_context_loss_count;
  691. }
  692. timer->irq = irq->start;
  693. timer->pdev = pdev;
  694. /* Skip pm_runtime_enable for OMAP1 */
  695. if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
  696. pm_runtime_enable(dev);
  697. pm_runtime_irq_safe(dev);
  698. }
  699. if (!timer->reserved) {
  700. pm_runtime_get_sync(dev);
  701. __omap_dm_timer_init_regs(timer);
  702. pm_runtime_put(dev);
  703. }
  704. /* add the timer element to the list */
  705. spin_lock_irqsave(&dm_timer_lock, flags);
  706. list_add_tail(&timer->node, &omap_timer_list);
  707. spin_unlock_irqrestore(&dm_timer_lock, flags);
  708. dev_dbg(dev, "Device Probed.\n");
  709. return 0;
  710. }
  711. /**
  712. * omap_dm_timer_remove - cleanup a registered timer device
  713. * @pdev: pointer to current timer platform device
  714. *
  715. * Called by driver framework whenever a timer device is unregistered.
  716. * In addition to freeing platform resources it also deletes the timer
  717. * entry from the local list.
  718. */
  719. static int omap_dm_timer_remove(struct platform_device *pdev)
  720. {
  721. struct omap_dm_timer *timer;
  722. unsigned long flags;
  723. int ret = -EINVAL;
  724. spin_lock_irqsave(&dm_timer_lock, flags);
  725. list_for_each_entry(timer, &omap_timer_list, node)
  726. if (!strcmp(dev_name(&timer->pdev->dev),
  727. dev_name(&pdev->dev))) {
  728. list_del(&timer->node);
  729. ret = 0;
  730. break;
  731. }
  732. spin_unlock_irqrestore(&dm_timer_lock, flags);
  733. return ret;
  734. }
  735. static const struct of_device_id omap_timer_match[] = {
  736. { .compatible = "ti,omap2-timer", },
  737. {},
  738. };
  739. MODULE_DEVICE_TABLE(of, omap_timer_match);
  740. static struct platform_driver omap_dm_timer_driver = {
  741. .probe = omap_dm_timer_probe,
  742. .remove = omap_dm_timer_remove,
  743. .driver = {
  744. .name = "omap_timer",
  745. .of_match_table = of_match_ptr(omap_timer_match),
  746. },
  747. };
  748. early_platform_init("earlytimer", &omap_dm_timer_driver);
  749. module_platform_driver(omap_dm_timer_driver);
  750. MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
  751. MODULE_LICENSE("GPL");
  752. MODULE_ALIAS("platform:" DRIVER_NAME);
  753. MODULE_AUTHOR("Texas Instruments Inc");