1. From 6545f0e751940aea67a5a6f937b26c304f4bc975 Mon Sep 17 00:00:00 2001
  2. From: Nishanth Menon <nm@ti.com>
  3. Date: Thu, 11 Oct 2012 13:31:34 -0500
  4. Subject: [PATCH] PM / devfreq: add omap_coproc dummy test driver
  5.  
  6. UNDER DEVEL
  7. play with:/sys/devices/platform/iva.0/stat_busy_time
  8. and /sys/devices/platform/pvrsrvkm.0/stat_busy_time
  9. to input "system behavior"
  10.  
  11. Change-Id: Ie8a461cee1cb9d61f83e5d221e4b3e3167445946
  12. Signed-off-by: Nishanth Menon <nm@ti.com>
  13. ---
  14.  drivers/devfreq/Kconfig       |    8 +
  15.  drivers/devfreq/Makefile      |    1 +
  16.  drivers/devfreq/omap_coproc.c |  359 +++++++++++++++++++++++++++++++++++++++++
  17.  3 files changed, 368 insertions(+)
  18.  create mode 100644 drivers/devfreq/omap_coproc.c
  19.  
  20. diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
  21. index f6b0a6e2..630cf14 100644
  22. --- a/drivers/devfreq/Kconfig
  23. +++ b/drivers/devfreq/Kconfig
  24. @@ -78,4 +78,12 @@ config ARM_EXYNOS4_BUS_DEVFREQ
  25.           To operate with optimal voltages, ASV support is required
  26.           (CONFIG_EXYNOS_ASV).
  27.  
  28. +config ARM_OMAP_COPROC_DEVFREQ
  29. +       bool "ARM OMAPx Co processor devfreq driver"
  30. +       depends on ARCH_OMAP && ARCH_HAS_OPP
  31. +       default y
  32. +       select DEVFREQ_GOV_SIMPLE_ONDEMAND
  33. +       help
  34. +         This adds OMAP Co processor devfreq driver.. yada yada..
  35. +
  36.  endif # PM_DEVFREQ
  37. diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
  38. index 8c46423..3bedc27 100644
  39. --- a/drivers/devfreq/Makefile
  40. +++ b/drivers/devfreq/Makefile
  41. @@ -6,3 +6,4 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)     += governor_userspace.o
  42.  
  43.  # DEVFREQ Drivers
  44.  obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)  += exynos4_bus.o
  45. +obj-$(CONFIG_ARM_OMAP_COPROC_DEVFREQ)  += omap_coproc.o
  46. diff --git a/drivers/devfreq/omap_coproc.c b/drivers/devfreq/omap_coproc.c
  47. new file mode 100644
  48. index 0000000..9b3b726
  49. --- /dev/null
  50. +++ b/drivers/devfreq/omap_coproc.c
  51. @@ -0,0 +1,359 @@
  52. +/*
  53. + * OMAP SoC Coprocessor devfreq driver
  54. + *
  55. + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
  56. + *     Nishanth Menon
  57. + *
  58. + * This program is free software; you can redistribute it and/or modify
  59. + * it under the terms of the GNU General Public License version 2 as
  60. + * published by the Free Software Foundation.
  61. +
  62. + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  63. + * kind, whether express or implied; without even the implied warranty
  64. + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  65. + * GNU General Public License for more details.
  66. + */
  67. +#include <linux/io.h>
  68. +#include <linux/slab.h>
  69. +#include <linux/mutex.h>
  70. +#include <linux/suspend.h>
  71. +#include <linux/opp.h>
  72. +#include <linux/devfreq.h>
  73. +#include <linux/platform_device.h>
  74. +#include <linux/regulator/consumer.h>
  75. +#include <linux/module.h>
  76. +#include <linux/clk.h>
  77. +
  78. +/**
  79. + * struct omap_devfreq_data - Co processor private data
  80. + * @profile:   devfreq profile specific for this device
  81. + * @dev:       device pointer
  82. + * @devfreq:   devfreq for this device
  83. + * @stat:      my current statistics
  84. + *
  85. + * TBD: write something nice here.
  86. + */
  87. +struct omap_devfreq_data {
  88. +       struct devfreq_dev_profile profile;
  89. +       struct device *dev;
  90. +       struct devfreq *devfreq;
  91. +       struct devfreq_dev_status stat;
  92. +};
  93. +
  94. +static struct clk *dev_clk;
  95. +static char *dev_clk_name = "dpll2_ck";
  96. +#define DEV_NAME "iva"
  97. +
  98. +static int omap_device_getrate(struct device *dev, unsigned long *rate)
  99. +{
  100. +       if (!dev_clk)
  101. +               dev_clk = clk_get(dev, dev_clk_name);
  102. +       *rate = clk_get_rate(dev_clk);
  103. +       return 0;
  104. +}
  105. +
  106. +
  107. +static int omap_device_scale(struct device *dev, unsigned long rate)
  108. +{
  109. +       if (!dev_clk)
  110. +               dev_clk = clk_get(dev, dev_clk_name);
  111. +       return clk_set_rate(dev_clk, rate);
  112. +}
  113. +/**
  114. + * omap_coproc_target() - devfreq handle for setting a rate
  115. + * @dev:       device
  116. + * @req_freq:  requested frequency
  117. + * @flags:     what directional flag
  118. + *
  119. + */
  120. +static int omap_coproc_target(struct device *dev, unsigned long *req_freq,
  121. +                             u32 flags)
  122. +{
  123. +       struct omap_devfreq_data *d;
  124. +       unsigned long new_freq, old_freq;
  125. +       struct opp *opp;
  126. +       int r = 0;
  127. +
  128. +       if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(req_freq)) {
  129. +               WARN("Bad pointer(s): dev=%p freq=%p\n",
  130. +                    (void *)dev, (void *)req_freq);
  131. +               return -EINVAL;
  132. +       }
  133. +       d = dev_get_drvdata(dev);
  134. +
  135. +       rcu_read_lock();
  136. +       opp = devfreq_recommended_opp(dev, req_freq, flags);
  137. +       if (IS_ERR(opp)) {
  138. +               rcu_read_unlock();
  139. +               dev_err(dev, "%s: %pF Unable to find OPP for freq%ld\n",
  140. +                       __func__, (void *)_RET_IP_, *req_freq);
  141. +               r = PTR_ERR(opp);
  142. +               goto out;
  143. +       }
  144. +       new_freq = opp_get_freq(opp);
  145. +       rcu_read_unlock();
  146. +
  147. +       /*
  148. +        * We could potentially optimize this a bit by storing current_freq
  149. +        * BUT, we dont know about external influences - e.g. thermal throttle
  150. +        */
  151. +       r = omap_device_getrate(d->dev, &old_freq);
  152. +       if (r) {
  153. +               dev_err(d->dev, "%s: unable to get rate(%d)\n", __func__, r);
  154. +               goto out;
  155. +       }
  156. +
  157. +       if (old_freq != new_freq) {
  158. +               r = omap_device_scale(d->dev, new_freq);
  159. +               dev_err(d->dev, "%s: Did a setrate(%d) n=%ld o=%ld r=%ld\n",
  160. +                       __func__, r, new_freq, old_freq, *req_freq);
  161. +       }
  162. +       if (r) {
  163. +               dev_err(d->dev, "%s: fail set rate(%d) n=%ld o=%ld r=%ld\n",
  164. +                       __func__, r, new_freq, old_freq, *req_freq);
  165. +               /* Fall through to exit */
  166. +       }
  167. +       dev_dbg(dev, "%s:target -  %ld %d\n", __func__, new_freq, r);
  168. +out:
  169. +       return r;
  170. +}
  171. +
  172. +/**
  173. + * omap_coproc_get_dev_status() - devfreq handle to know about the device
  174. + * @dev:       device we are interested in
  175. + * @stat:      return back statistics for the device
  176. + */
  177. +static int omap_coproc_get_dev_status(struct device *dev,
  178. +                                     struct devfreq_dev_status *stat)
  179. +{
  180. +       struct omap_devfreq_data *d;
  181. +       int r;
  182. +
  183. +       if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(stat)) {
  184. +               WARN("Bad pointer(s): dev=%p stat=%p\n",
  185. +                    (void *)dev, (void *)stat);
  186. +               return -EINVAL;
  187. +       }
  188. +
  189. +       d = dev_get_drvdata(dev);
  190. +       /* Completely BOGUS values */
  191. +       stat->total_time = d->stat.total_time;
  192. +       stat->busy_time = d->stat.busy_time;
  193. +       r = omap_device_getrate(d->dev, &stat->current_frequency);
  194. +       if (r)
  195. +               dev_err(dev, "%s: bad get rate req = %d\n", __func__, r);
  196. +       dev_dbg(dev, "%s:polled -  %ld\n", __func__, stat->current_frequency);
  197. +
  198. +       return r;
  199. +}
  200. +
  201. +/**
  202. + * omap_coproc_exit() - done using the device
  203. + * @dev:       device
  204. + */
  205. +static void omap_coproc_exit(struct device *dev)
  206. +{
  207. +       struct omap_devfreq_data *d = dev_get_drvdata(dev);
  208. +
  209. +       devfreq_unregister_opp_notifier(dev, d->devfreq);
  210. +}
  211. +
  212. +static ssize_t store_stat(const char *buf, size_t count, unsigned long *store)
  213. +{
  214. +       int ret;
  215. +       unsigned long value;
  216. +       ret = sscanf(buf, "%lu", &value);
  217. +       if (ret == 0) {
  218. +               ret = -EINVAL;
  219. +               goto out;
  220. +       }
  221. +       *store = value;
  222. +       ret = count;
  223. +out:
  224. +       return ret;
  225. +}
  226. +
  227. +static ssize_t show_stat_total_time(struct device *dev,
  228. +                                   struct device_attribute *attr, char *buf)
  229. +{
  230. +       struct omap_devfreq_data *d = dev_get_drvdata(dev);
  231. +       return sprintf(buf, "%lu\n", d->stat.total_time);
  232. +}
  233. +
  234. +static ssize_t store_stat_total_time(struct device *dev, struct device_attribute *attr,
  235. +                             const char *buf, size_t count)
  236. +{
  237. +       struct omap_devfreq_data *d = dev_get_drvdata(dev);
  238. +       return store_stat(buf, count, &d->stat.total_time);
  239. +}
  240. +
  241. +static ssize_t show_stat_busy_time(struct device *dev,
  242. +                                   struct device_attribute *attr, char *buf)
  243. +{
  244. +       struct omap_devfreq_data *d = dev_get_drvdata(dev);
  245. +       return sprintf(buf, "%lu\n", d->stat.busy_time);
  246. +}
  247. +static ssize_t store_stat_busy_time(struct device *dev, struct device_attribute *attr,
  248. +                             const char *buf, size_t count)
  249. +{
  250. +       struct omap_devfreq_data *d = dev_get_drvdata(dev);
  251. +       return store_stat(buf, count, &d->stat.busy_time);
  252. +}
  253. +
  254. +static struct device_attribute omap_debug_attr[] = {
  255. +       __ATTR(stat_total_time, S_IRUSR | S_IWUSR, show_stat_total_time, store_stat_total_time),
  256. +       __ATTR(stat_busy_time, S_IRUSR | S_IWUSR, show_stat_busy_time, store_stat_busy_time),
  257. +       { },
  258. +};
  259. +
  260. +/**
  261. + * omap_coproc_probe() - probe when we find a device to control
  262. + * @pdev:      which platform device to control?
  263. + */
  264. +static __devinit int omap_coproc_probe(struct platform_device *pdev)
  265. +{
  266. +       struct omap_devfreq_data *d;
  267. +       struct device *dev = &pdev->dev;
  268. +       int err = 0;
  269. +       struct device_attribute *attr = omap_debug_attr;
  270. +
  271. +       d = kzalloc(sizeof(struct omap_devfreq_data), GFP_KERNEL);
  272. +       if (d == NULL) {
  273. +               dev_err(dev, "%s: Cannot allocate memory.\n", __func__);
  274. +               err = -ENOMEM;
  275. +               goto out;
  276. +       }
  277. +
  278. +       d->dev = dev;
  279. +       err = omap_device_getrate(dev, &d->profile.initial_freq);
  280. +       if (err) {
  281. +               dev_err(dev, "%s: Cannot get freq(%d).\n", __func__, err);
  282. +               goto out_mem;
  283. +       }
  284. +
  285. +       d->profile.target = omap_coproc_target;
  286. +       d->profile.get_dev_status = omap_coproc_get_dev_status;
  287. +       d->profile.exit = omap_coproc_exit;
  288. +       /* NOTE: the following should be based per device */
  289. +       d->profile.polling_ms = 50;
  290. +       dev_info(dev, "%s init rate = %ld\n", __func__,
  291. +                d->profile.initial_freq);
  292. +
  293. +       /* NOTE: option needs to be provided for governor to be selected */
  294. +       d->devfreq = devfreq_add_device(dev, &d->profile,
  295. +                                       &devfreq_simple_ondemand, NULL);
  296. +       if (IS_ERR(d->devfreq)) {
  297. +               err = PTR_ERR(d->devfreq);
  298. +               dev_err(dev, "%s: Cannot add to devfreq(%d).\n", __func__, err);
  299. +               goto out_mem;
  300. +       }
  301. +
  302. +       err = devfreq_register_opp_notifier(dev, d->devfreq);
  303. +       if (err) {
  304. +               dev_err(dev, "%s: Cannot add to devfreq opp notifier(%d).\n",
  305. +                       __func__, err);
  306. +               goto out_remove;
  307. +       }
  308. +
  309. +       platform_set_drvdata(pdev, d);
  310. +
  311. +       /* Completely BOGUS values */
  312. +       d->stat.total_time = 100;
  313. +       d->stat.busy_time = 1;
  314. +
  315. +       while(attr->show || attr->store) {
  316. +               int k = device_create_file(dev, attr);
  317. +               dev_err(dev, "attribute res = %d\n", k);
  318. +               attr++;
  319. +       }
  320. +
  321. +       /* All good.. */
  322. +       goto out;
  323. +
  324. +out_remove:
  325. +       devfreq_remove_device(d->devfreq);
  326. +out_mem:
  327. +       kfree(d);
  328. +out:
  329. +       dev_info(dev, "%s result=%d", __func__, err);
  330. +       return err;
  331. +}
  332. +
  333. +/**
  334. + * omap_coproc_remove() - remove the device
  335. + * @pdev:      device we are removing from system
  336. + */
  337. +static __devexit int omap_coproc_remove(struct platform_device *pdev)
  338. +{
  339. +       struct omap_devfreq_data *d = platform_get_drvdata(pdev);
  340. +
  341. +       //unregister_pm_notifier(&d->pm_notifier);
  342. +       devfreq_remove_device(d->devfreq);
  343. +
  344. +       kfree(d);
  345. +
  346. +       dev_err(&pdev->dev, "%s\n", __func__);
  347. +       return 0;
  348. +}
  349. +
  350. +/**
  351. + * omap_coproc_suspend() - dummy hook for suspend
  352. + * @dev: write something
  353. + */
  354. +static int omap_coproc_suspend(struct device *dev)
  355. +{
  356. +       dev_err(dev, "suspend");
  357. +       return 0;
  358. +}
  359. +
  360. +/**
  361. + * omap_coproc_resume() - dummy hook for resume
  362. + * @dev: write something
  363. + */
  364. +static int omap_coproc_resume(struct device *dev)
  365. +{
  366. +       dev_err(dev, "resume");
  367. +       return 0;
  368. +}
  369. +
  370. +/* Device power management hooks */
  371. +static const struct dev_pm_ops omap_coproc_pm = {
  372. +       .suspend = omap_coproc_suspend,
  373. +       .resume = omap_coproc_resume,
  374. +};
  375. +
  376. +/* Any generic devices that exist on ALL OMAPs - currently example devices */
  377. +static const struct platform_device_id omap_coproc_generic_device_id_list[] = {
  378. +       {DEV_NAME, 0},
  379. +       {},
  380. +};
  381. +
  382. +static struct platform_driver omap_coproc_driver = {
  383. +       .probe = omap_coproc_probe,
  384. +       .remove = __devexit_p(omap_coproc_remove),
  385. +       .id_table = omap_coproc_generic_device_id_list,
  386. +       .driver = {
  387. +                  .name = "omap_coproc_pm",
  388. +                  .owner = THIS_MODULE,
  389. +                  .pm = &omap_coproc_pm,
  390. +                  },
  391. +};
  392. +
  393. +static int __init omap_coproc_init(void)
  394. +{
  395. +       int r = platform_driver_register(&omap_coproc_driver);
  396. +       pr_err("OMAP Co-processor DEVFREQ Driver %s (%d)\n",
  397. +              r ? "Failed to initialize" : "Initialized", r);
  398. +       return r;
  399. +}
  400. +late_initcall(omap_coproc_init);
  401. +
  402. +static void __exit omap_coproc_deinit(void)
  403. +{
  404. +       platform_driver_unregister(&omap_coproc_driver);
  405. +}
  406. +module_exit(omap_coproc_deinit);
  407. +
  408. +MODULE_LICENSE("GPL");
  409. +MODULE_DESCRIPTION("OMAP Co-processor DEVFREQ Driver");
  410. +MODULE_AUTHOR("Nishanth Menon <nm@ti.com>");
  411. --
  412. 1.7.9.5
  413.  

Reply to "dummy patch"

Here you can reply to the paste above

Create a snipurl

Make Private

Feeling clever? Set some advanced options.