leds-renesas-tpu.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * LED control using Renesas TPU
  3. *
  4. * Copyright (C) 2011 Magnus Damm
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include <linux/module.h>
  20. #include <linux/init.h>
  21. #include <linux/platform_device.h>
  22. #include <linux/spinlock.h>
  23. #include <linux/printk.h>
  24. #include <linux/ioport.h>
  25. #include <linux/io.h>
  26. #include <linux/clk.h>
  27. #include <linux/leds.h>
  28. #include <linux/leds-renesas-tpu.h>
  29. #include <linux/gpio.h>
  30. #include <linux/err.h>
  31. #include <linux/slab.h>
  32. #include <linux/pm_runtime.h>
  33. enum r_tpu_pin { R_TPU_PIN_UNUSED, R_TPU_PIN_GPIO, R_TPU_PIN_GPIO_FN };
  34. enum r_tpu_timer { R_TPU_TIMER_UNUSED, R_TPU_TIMER_ON };
  35. struct r_tpu_priv {
  36. struct led_classdev ldev;
  37. void __iomem *mapbase;
  38. struct clk *clk;
  39. struct platform_device *pdev;
  40. enum r_tpu_pin pin_state;
  41. enum r_tpu_timer timer_state;
  42. unsigned long min_rate;
  43. unsigned int refresh_rate;
  44. };
  45. static DEFINE_SPINLOCK(r_tpu_lock);
  46. #define TSTR -1 /* Timer start register (shared register) */
  47. #define TCR 0 /* Timer control register (+0x00) */
  48. #define TMDR 1 /* Timer mode register (+0x04) */
  49. #define TIOR 2 /* Timer I/O control register (+0x08) */
  50. #define TIER 3 /* Timer interrupt enable register (+0x0c) */
  51. #define TSR 4 /* Timer status register (+0x10) */
  52. #define TCNT 5 /* Timer counter (+0x14) */
  53. #define TGRA 6 /* Timer general register A (+0x18) */
  54. #define TGRB 7 /* Timer general register B (+0x1c) */
  55. #define TGRC 8 /* Timer general register C (+0x20) */
  56. #define TGRD 9 /* Timer general register D (+0x24) */
  57. static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr)
  58. {
  59. struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
  60. void __iomem *base = p->mapbase;
  61. unsigned long offs = reg_nr << 2;
  62. if (reg_nr == TSTR)
  63. return ioread16(base - cfg->channel_offset);
  64. return ioread16(base + offs);
  65. }
  66. static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr,
  67. unsigned short value)
  68. {
  69. struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
  70. void __iomem *base = p->mapbase;
  71. unsigned long offs = reg_nr << 2;
  72. if (reg_nr == TSTR) {
  73. iowrite16(value, base - cfg->channel_offset);
  74. return;
  75. }
  76. iowrite16(value, base + offs);
  77. }
  78. static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start)
  79. {
  80. struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
  81. unsigned long flags, value;
  82. /* start stop register shared by multiple timer channels */
  83. spin_lock_irqsave(&r_tpu_lock, flags);
  84. value = r_tpu_read(p, TSTR);
  85. if (start)
  86. value |= 1 << cfg->timer_bit;
  87. else
  88. value &= ~(1 << cfg->timer_bit);
  89. r_tpu_write(p, TSTR, value);
  90. spin_unlock_irqrestore(&r_tpu_lock, flags);
  91. }
  92. static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness)
  93. {
  94. struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
  95. int prescaler[] = { 1, 4, 16, 64 };
  96. int k, ret;
  97. unsigned long rate, tmp;
  98. if (p->timer_state == R_TPU_TIMER_ON)
  99. return 0;
  100. /* wake up device and enable clock */
  101. pm_runtime_get_sync(&p->pdev->dev);
  102. ret = clk_enable(p->clk);
  103. if (ret) {
  104. dev_err(&p->pdev->dev, "cannot enable clock\n");
  105. return ret;
  106. }
  107. /* make sure channel is disabled */
  108. r_tpu_start_stop_ch(p, 0);
  109. /* get clock rate after enabling it */
  110. rate = clk_get_rate(p->clk);
  111. /* pick the lowest acceptable rate */
  112. for (k = 0; k < ARRAY_SIZE(prescaler); k++)
  113. if ((rate / prescaler[k]) < p->min_rate)
  114. break;
  115. if (!k) {
  116. dev_err(&p->pdev->dev, "clock rate mismatch\n");
  117. goto err0;
  118. }
  119. dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n",
  120. rate, prescaler[k - 1]);
  121. /* clear TCNT on TGRB match, count on rising edge, set prescaler */
  122. r_tpu_write(p, TCR, 0x0040 | (k - 1));
  123. /* output 0 until TGRA, output 1 until TGRB */
  124. r_tpu_write(p, TIOR, 0x0002);
  125. rate /= prescaler[k - 1] * p->refresh_rate;
  126. r_tpu_write(p, TGRB, rate);
  127. dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate);
  128. tmp = (cfg->max_brightness - brightness) * rate;
  129. r_tpu_write(p, TGRA, tmp / cfg->max_brightness);
  130. dev_dbg(&p->pdev->dev, "TRGA = 0x%04lx\n", tmp / cfg->max_brightness);
  131. /* PWM mode */
  132. r_tpu_write(p, TMDR, 0x0002);
  133. /* enable channel */
  134. r_tpu_start_stop_ch(p, 1);
  135. p->timer_state = R_TPU_TIMER_ON;
  136. return 0;
  137. err0:
  138. clk_disable(p->clk);
  139. pm_runtime_put_sync(&p->pdev->dev);
  140. return -ENOTSUPP;
  141. }
  142. static void r_tpu_disable(struct r_tpu_priv *p)
  143. {
  144. if (p->timer_state == R_TPU_TIMER_UNUSED)
  145. return;
  146. /* disable channel */
  147. r_tpu_start_stop_ch(p, 0);
  148. /* stop clock and mark device as idle */
  149. clk_disable(p->clk);
  150. pm_runtime_put_sync(&p->pdev->dev);
  151. p->timer_state = R_TPU_TIMER_UNUSED;
  152. }
  153. static void r_tpu_set_pin(struct r_tpu_priv *p, enum r_tpu_pin new_state,
  154. enum led_brightness brightness)
  155. {
  156. struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
  157. if (p->pin_state == new_state) {
  158. if (p->pin_state == R_TPU_PIN_GPIO)
  159. gpio_set_value(cfg->pin_gpio, brightness);
  160. return;
  161. }
  162. if (p->pin_state == R_TPU_PIN_GPIO)
  163. gpio_free(cfg->pin_gpio);
  164. if (p->pin_state == R_TPU_PIN_GPIO_FN)
  165. gpio_free(cfg->pin_gpio_fn);
  166. if (new_state == R_TPU_PIN_GPIO) {
  167. gpio_request(cfg->pin_gpio, cfg->name);
  168. gpio_direction_output(cfg->pin_gpio, !!brightness);
  169. }
  170. if (new_state == R_TPU_PIN_GPIO_FN)
  171. gpio_request(cfg->pin_gpio_fn, cfg->name);
  172. p->pin_state = new_state;
  173. }
  174. static void r_tpu_set_brightness(struct led_classdev *ldev,
  175. enum led_brightness brightness)
  176. {
  177. struct r_tpu_priv *p = container_of(ldev, struct r_tpu_priv, ldev);
  178. r_tpu_disable(p);
  179. /* off and maximum are handled as GPIO pins, in between PWM */
  180. if ((brightness == 0) || (brightness == ldev->max_brightness))
  181. r_tpu_set_pin(p, R_TPU_PIN_GPIO, brightness);
  182. else {
  183. r_tpu_set_pin(p, R_TPU_PIN_GPIO_FN, 0);
  184. r_tpu_enable(p, brightness);
  185. }
  186. }
  187. static int __devinit r_tpu_probe(struct platform_device *pdev)
  188. {
  189. struct led_renesas_tpu_config *cfg = pdev->dev.platform_data;
  190. struct r_tpu_priv *p;
  191. struct resource *res;
  192. int ret = -ENXIO;
  193. if (!cfg) {
  194. dev_err(&pdev->dev, "missing platform data\n");
  195. goto err0;
  196. }
  197. p = kzalloc(sizeof(*p), GFP_KERNEL);
  198. if (p == NULL) {
  199. dev_err(&pdev->dev, "failed to allocate driver data\n");
  200. ret = -ENOMEM;
  201. goto err0;
  202. }
  203. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  204. if (!res) {
  205. dev_err(&pdev->dev, "failed to get I/O memory\n");
  206. goto err1;
  207. }
  208. /* map memory, let mapbase point to our channel */
  209. p->mapbase = ioremap_nocache(res->start, resource_size(res));
  210. if (p->mapbase == NULL) {
  211. dev_err(&pdev->dev, "failed to remap I/O memory\n");
  212. goto err1;
  213. }
  214. /* get hold of clock */
  215. p->clk = clk_get(&pdev->dev, NULL);
  216. if (IS_ERR(p->clk)) {
  217. dev_err(&pdev->dev, "cannot get clock\n");
  218. ret = PTR_ERR(p->clk);
  219. goto err2;
  220. }
  221. p->pdev = pdev;
  222. p->pin_state = R_TPU_PIN_UNUSED;
  223. p->timer_state = R_TPU_TIMER_UNUSED;
  224. p->refresh_rate = cfg->refresh_rate ? cfg->refresh_rate : 100;
  225. r_tpu_set_pin(p, R_TPU_PIN_GPIO, LED_OFF);
  226. platform_set_drvdata(pdev, p);
  227. p->ldev.name = cfg->name;
  228. p->ldev.brightness = LED_OFF;
  229. p->ldev.max_brightness = cfg->max_brightness;
  230. p->ldev.brightness_set = r_tpu_set_brightness;
  231. p->ldev.flags |= LED_CORE_SUSPENDRESUME;
  232. ret = led_classdev_register(&pdev->dev, &p->ldev);
  233. if (ret < 0)
  234. goto err3;
  235. /* max_brightness may be updated by the LED core code */
  236. p->min_rate = p->ldev.max_brightness * p->refresh_rate;
  237. pm_runtime_enable(&pdev->dev);
  238. return 0;
  239. err3:
  240. r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
  241. clk_put(p->clk);
  242. err2:
  243. iounmap(p->mapbase);
  244. err1:
  245. kfree(p);
  246. err0:
  247. return ret;
  248. }
  249. static int __devexit r_tpu_remove(struct platform_device *pdev)
  250. {
  251. struct r_tpu_priv *p = platform_get_drvdata(pdev);
  252. r_tpu_set_brightness(&p->ldev, LED_OFF);
  253. led_classdev_unregister(&p->ldev);
  254. r_tpu_disable(p);
  255. r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
  256. pm_runtime_disable(&pdev->dev);
  257. clk_put(p->clk);
  258. iounmap(p->mapbase);
  259. kfree(p);
  260. return 0;
  261. }
  262. static struct platform_driver r_tpu_device_driver = {
  263. .probe = r_tpu_probe,
  264. .remove = __devexit_p(r_tpu_remove),
  265. .driver = {
  266. .name = "leds-renesas-tpu",
  267. }
  268. };
  269. static int __init r_tpu_init(void)
  270. {
  271. return platform_driver_register(&r_tpu_device_driver);
  272. }
  273. static void __exit r_tpu_exit(void)
  274. {
  275. platform_driver_unregister(&r_tpu_device_driver);
  276. }
  277. module_init(r_tpu_init);
  278. module_exit(r_tpu_exit);
  279. MODULE_AUTHOR("Magnus Damm");
  280. MODULE_DESCRIPTION("Renesas TPU LED Driver");
  281. MODULE_LICENSE("GPL v2");