leds-renesas-tpu.c 8.9 KB

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