Guest User

Test

a guest
Mar 17th, 2012
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.91 KB | None | 0 0
  1. /* drivers/leds/leds-omap_pwm.c
  2. *
  3. * Driver to blink LEDs using OMAP PWM timers
  4. *
  5. * Copyright (C) 2006 Nokia Corporation
  6. * Author: Timo Teras
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12.  
  13. #include <linux/kernel.h>
  14. #include <linux/init.h>
  15. #include <linux/err.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/leds.h>
  18. #include <linux/ctype.h>
  19. #include <linux/sched.h>
  20. #include <linux/slab.h>
  21. #include <asm/delay.h>
  22. #include <plat/board.h>
  23. #include <plat/dmtimer.h>
  24.  
  25. struct omap_pwm_led {
  26. struct led_classdev cdev;
  27. struct work_struct work;
  28. struct omap_pwm_led_platform_data *pdata;
  29. struct omap_dm_timer *intensity_timer;
  30. struct omap_dm_timer *blink_timer;
  31. int powered;
  32. unsigned int on_period, off_period;
  33. enum led_brightness brightness;
  34. };
  35.  
  36. static inline struct omap_pwm_led *pdev_to_omap_pwm_led(struct platform_device *pdev)
  37. {
  38. return platform_get_drvdata(pdev);
  39. }
  40.  
  41. static inline struct omap_pwm_led *cdev_to_omap_pwm_led(struct led_classdev *led_cdev)
  42. {
  43. return container_of(led_cdev, struct omap_pwm_led, cdev);
  44. }
  45.  
  46. static inline struct omap_pwm_led *work_to_omap_pwm_led(struct work_struct *work)
  47. {
  48. return container_of(work, struct omap_pwm_led, work);
  49. }
  50.  
  51. static void omap_pwm_led_set_blink(struct omap_pwm_led *led)
  52. {
  53. if (!led->powered)
  54. return;
  55.  
  56. if (led->on_period != 0 && led->off_period != 0) {
  57. unsigned long load_reg, cmp_reg;
  58.  
  59. load_reg = 32768 * (led->on_period + led->off_period) / 1000;
  60. cmp_reg = 32768 * led->on_period / 1000;
  61.  
  62. omap_dm_timer_stop(led->blink_timer);
  63. omap_dm_timer_set_load(led->blink_timer, 1, -load_reg);
  64. omap_dm_timer_set_match(led->blink_timer, 1, -cmp_reg);
  65. omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
  66. OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
  67. omap_dm_timer_write_counter(led->blink_timer, -2);
  68. omap_dm_timer_start(led->blink_timer);
  69. } else {
  70. omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
  71. OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
  72. omap_dm_timer_stop(led->blink_timer);
  73. }
  74. }
  75.  
  76. static void omap_pwm_led_power_on(struct omap_pwm_led *led)
  77. {
  78. //printk("!!!!!!!!!!%s the brightness is %d \n",__func__, led->brightness);
  79. if (led->powered)
  80. return;
  81. led->powered = 1;
  82.  
  83. /* Select clock */
  84. omap_dm_timer_enable(led->intensity_timer);
  85. omap_dm_timer_set_source(led->intensity_timer, OMAP_TIMER_SRC_SYS_CLK);
  86. omap_dm_timer_set_prescaler(led->intensity_timer, 0);
  87.  
  88. /* Turn voltage on */
  89. if (led->pdata->set_power != NULL)
  90. led->pdata->set_power(led->pdata, 1);
  91.  
  92. /* Enable PWM timers */
  93. if (led->blink_timer != NULL) {
  94. omap_dm_timer_enable(led->blink_timer);
  95. omap_dm_timer_set_source(led->blink_timer,
  96. OMAP_TIMER_SRC_32_KHZ);
  97. omap_pwm_led_set_blink(led);
  98. }
  99.  
  100. omap_dm_timer_set_load(led->intensity_timer, 1, 0xffffff00);
  101. }
  102.  
  103. static void omap_pwm_led_power_off(struct omap_pwm_led *led)
  104. {
  105. //printk("!!!!!!!!!!%s the brightness is %d \n",__func__, led->brightness);
  106. if (!led->powered)
  107. return;
  108. led->powered = 0;
  109.  
  110. /* Everything off */
  111. omap_dm_timer_set_pwm(led->intensity_timer, 0, 1,
  112. OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
  113. omap_dm_timer_stop(led->intensity_timer);
  114. omap_dm_timer_disable(led->intensity_timer);
  115.  
  116. if (led->blink_timer != NULL) {
  117. omap_dm_timer_stop(led->blink_timer);
  118. omap_dm_timer_disable(led->blink_timer);
  119. }
  120.  
  121. if (led->pdata->set_power != NULL)
  122. led->pdata->set_power(led->pdata, 0);
  123. }
  124.  
  125. static void omap_pwm_led_set_pwm_cycle(struct omap_pwm_led *led, int cycle)
  126. {
  127. int n;
  128.  
  129. if (cycle == 0)
  130. n = 0xff;
  131. else n = cycle - 1;
  132.  
  133. if (cycle == LED_FULL) {
  134. omap_dm_timer_start(led->intensity_timer);
  135. omap_dm_timer_set_pwm(led->intensity_timer, 1, 1,
  136. OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
  137. omap_dm_timer_set_match(led->intensity_timer, 1,
  138. 0xffffff00);
  139. } else {
  140. omap_dm_timer_start(led->intensity_timer);
  141. omap_dm_timer_set_pwm(led->intensity_timer, 0, 1,
  142. OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
  143. omap_dm_timer_set_match(led->intensity_timer, 1,
  144. (0xffffff00) | cycle);
  145. }
  146. }
  147.  
  148. static void omap_pwm_led_set(struct led_classdev *led_cdev,
  149. enum led_brightness value)
  150. {
  151. struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
  152.  
  153. led->brightness = value;
  154. schedule_work(&led->work);
  155. }
  156.  
  157. static void omap_pwm_led_work(struct work_struct *work)
  158. {
  159. struct omap_pwm_led *led = work_to_omap_pwm_led(work);
  160.  
  161. if (led->brightness != LED_OFF) {
  162. omap_pwm_led_power_on(led);
  163. omap_pwm_led_set_pwm_cycle(led, led->brightness);
  164. } else {
  165. omap_pwm_led_power_off(led);
  166. }
  167. }
  168.  
  169. static ssize_t omap_pwm_led_on_period_show(struct device *dev,
  170. struct device_attribute *attr, char *buf)
  171. {
  172. struct led_classdev *led_cdev = dev_get_drvdata(dev);
  173. struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
  174.  
  175. return sprintf(buf, "%u\n", led->on_period) + 1;
  176. }
  177.  
  178. static ssize_t omap_pwm_led_on_period_store(struct device *dev,
  179. struct device_attribute *attr,
  180. const char *buf, size_t size)
  181. {
  182. struct led_classdev *led_cdev = dev_get_drvdata(dev);
  183. struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
  184. int ret = -EINVAL;
  185. unsigned long val;
  186. char *after;
  187. size_t count;
  188.  
  189. val = simple_strtoul(buf, &after, 10);
  190. count = after - buf;
  191. if (*after && isspace(*after))
  192. count++;
  193.  
  194. if (count == size) {
  195. led->on_period = val;
  196. omap_pwm_led_set_blink(led);
  197. ret = count;
  198. }
  199.  
  200. return ret;
  201. }
  202.  
  203. static ssize_t omap_pwm_led_off_period_show(struct device *dev,
  204. struct device_attribute *attr, char *buf)
  205. {
  206. struct led_classdev *led_cdev = dev_get_drvdata(dev);
  207. struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
  208.  
  209. return sprintf(buf, "%u\n", led->off_period) + 1;
  210. }
  211.  
  212. static ssize_t omap_pwm_led_off_period_store(struct device *dev,
  213. struct device_attribute *attr,
  214. const char *buf, size_t size)
  215. {
  216. struct led_classdev *led_cdev = dev_get_drvdata(dev);
  217. struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
  218. int ret = -EINVAL;
  219. unsigned long val;
  220. char *after;
  221. size_t count;
  222.  
  223. val = simple_strtoul(buf, &after, 10);
  224. count = after - buf;
  225. if (*after && isspace(*after))
  226. count++;
  227.  
  228. if (count == size) {
  229. led->off_period = val;
  230. omap_pwm_led_set_blink(led);
  231. ret = count;
  232. }
  233.  
  234. return ret;
  235. }
  236.  
  237. static DEVICE_ATTR(on_period, 0644, omap_pwm_led_on_period_show,
  238. omap_pwm_led_on_period_store);
  239. static DEVICE_ATTR(off_period, 0644, omap_pwm_led_off_period_show,
  240. omap_pwm_led_off_period_store);
  241.  
  242. static int omap_pwm_led_probe(struct platform_device *pdev)
  243. {
  244. struct omap_pwm_led_platform_data *pdata = pdev->dev.platform_data;
  245. struct omap_pwm_led *led;
  246. int ret;
  247.  
  248. led = kzalloc(sizeof(struct omap_pwm_led), GFP_KERNEL);
  249. if (led == NULL) {
  250. dev_err(&pdev->dev, "No memory for device\n");
  251. return -ENOMEM;
  252. }
  253.  
  254. platform_set_drvdata(pdev, led);
  255. led->cdev.brightness_set = omap_pwm_led_set;
  256. led->cdev.max_brightness = LED_FULL;
  257. led->cdev.brightness = pdata->def_brightness;
  258. led->cdev.default_trigger = NULL;
  259. led->cdev.name = pdata->name;
  260. led->pdata = pdata;
  261. INIT_WORK(&led->work, omap_pwm_led_work);
  262.  
  263. dev_info(&pdev->dev, "OMAP PWM LED (%s) at GP timer %d/%d\n",
  264. pdata->name, pdata->intensity_timer, pdata->blink_timer);
  265.  
  266. /* register our new led device */
  267. ret = led_classdev_register(&pdev->dev, &led->cdev);
  268. if (ret < 0) {
  269. dev_err(&pdev->dev, "led_classdev_register failed\n");
  270. goto error_classdev;
  271. }
  272.  
  273. /* get related dm timers */
  274. led->intensity_timer = omap_dm_timer_request_specific(pdata->intensity_timer);
  275. if (led->intensity_timer == NULL) {
  276. dev_err(&pdev->dev, "failed to request intensity pwm timer\n");
  277. ret = -ENODEV;
  278. goto error_intensity;
  279. }
  280. //omap_dm_timer_disable(led->intensity_timer);
  281.  
  282. if (pdata->blink_timer != 0) {
  283. led->blink_timer = omap_dm_timer_request_specific(pdata->blink_timer);
  284. if (led->blink_timer == NULL) {
  285. dev_err(&pdev->dev, "failed to request blinking pwm timer\n");
  286. ret = -ENODEV;
  287. goto error_blink1;
  288. }
  289. omap_dm_timer_disable(led->blink_timer);
  290.  
  291. ret = device_create_file(led->cdev.dev,
  292. &dev_attr_on_period);
  293. if(ret)
  294. goto error_blink2;
  295.  
  296. ret = device_create_file(led->cdev.dev,
  297. &dev_attr_off_period);
  298. if(ret)
  299. goto error_blink3;
  300.  
  301. }
  302.  
  303. #if 0
  304. if (led->cdev.brightness) {
  305. omap_pwm_led_set(&led->cdev, led->cdev.brightness);
  306. }
  307. #endif
  308.  
  309. return 0;
  310.  
  311. error_blink3:
  312. device_remove_file(led->cdev.dev,
  313. &dev_attr_on_period);
  314. error_blink2:
  315. dev_err(&pdev->dev, "failed to create device file(s)\n");
  316. error_blink1:
  317. omap_dm_timer_free(led->intensity_timer);
  318. error_intensity:
  319. led_classdev_unregister(&led->cdev);
  320. error_classdev:
  321. kfree(led);
  322. return ret;
  323. }
  324.  
  325. static int omap_pwm_led_remove(struct platform_device *pdev)
  326. {
  327. struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
  328.  
  329. device_remove_file(led->cdev.dev,
  330. &dev_attr_on_period);
  331. device_remove_file(led->cdev.dev,
  332. &dev_attr_off_period);
  333. led_classdev_unregister(&led->cdev);
  334.  
  335. omap_pwm_led_set(&led->cdev, LED_OFF);
  336. if (led->blink_timer != NULL)
  337. omap_dm_timer_free(led->blink_timer);
  338. omap_dm_timer_free(led->intensity_timer);
  339. kfree(led);
  340.  
  341. return 0;
  342. }
  343.  
  344. #ifdef CONFIG_PM
  345. static int omap_pwm_led_suspend(struct platform_device *pdev, pm_message_t state)
  346. {
  347. struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
  348.  
  349. led_classdev_suspend(&led->cdev);
  350. return 0;
  351. }
  352.  
  353. static int omap_pwm_led_resume(struct platform_device *pdev)
  354. {
  355. struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
  356.  
  357. led_classdev_resume(&led->cdev);
  358. return 0;
  359. }
  360. #else
  361. #define omap_pwm_led_suspend NULL
  362. #define omap_pwm_led_resume NULL
  363. #endif
  364.  
  365. static struct platform_driver omap_pwm_led_driver = {
  366. .probe = omap_pwm_led_probe,
  367. .remove = omap_pwm_led_remove,
  368. .suspend = omap_pwm_led_suspend,
  369. .resume = omap_pwm_led_resume,
  370. .driver = {
  371. .name = "omap_pwm_led",
  372. .owner = THIS_MODULE,
  373. },
  374. };
  375.  
  376. static int __init omap_pwm_led_init(void)
  377. {
  378. return platform_driver_register(&omap_pwm_led_driver);
  379. }
  380.  
  381. static void __exit omap_pwm_led_exit(void)
  382. {
  383. platform_driver_unregister(&omap_pwm_led_driver);
  384. }
  385.  
  386. module_init(omap_pwm_led_init);
  387. module_exit(omap_pwm_led_exit);
  388.  
  389. MODULE_AUTHOR("Timo Teras");
  390. MODULE_DESCRIPTION("OMAP PWM LED driver");
  391. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment