kernel_006_bl.patch 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
  2. index d83c87b90..2f1b6105e 100644
  3. --- a/drivers/video/backlight/Kconfig
  4. +++ b/drivers/video/backlight/Kconfig
  5. @@ -456,6 +456,12 @@ config BACKLIGHT_LED
  6. If you have a LCD backlight adjustable by LED class driver, say Y
  7. to enable this driver.
  8. +config BACKLIGHT_OCP8178
  9. + tristate "OCP8178 Backlight Driver"
  10. + depends on GPIOLIB
  11. + help
  12. + If you have an OCP8178, say Y to enable the backlight driver.
  13. +
  14. endif # BACKLIGHT_CLASS_DEVICE
  15. endmenu
  16. diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
  17. index 685f3f1ca..f1160d626 100644
  18. --- a/drivers/video/backlight/Makefile
  19. +++ b/drivers/video/backlight/Makefile
  20. @@ -57,3 +57,4 @@ obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
  21. obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
  22. obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o
  23. obj-$(CONFIG_BACKLIGHT_LED) += led_bl.o
  24. +obj-$(CONFIG_BACKLIGHT_OCP8178) += ocp8178_bl.o
  25. diff --git a/drivers/video/backlight/ocp8178_bl.c b/drivers/video/backlight/ocp8178_bl.c
  26. new file mode 100644
  27. index 000000000..db8db1771
  28. --- /dev/null
  29. +++ b/drivers/video/backlight/ocp8178_bl.c
  30. @@ -0,0 +1,277 @@
  31. +/*
  32. + * ocp8178_bl.c - ocp8178 backlight driver
  33. + *
  34. + * This program is free software; you can redistribute it and/or modify
  35. + * it under the terms of the GNU General Public License version 2 as
  36. + * published by the Free Software Foundation.
  37. + */
  38. +
  39. +#include <linux/backlight.h>
  40. +#include <linux/err.h>
  41. +#include <linux/fb.h>
  42. +#include <linux/gpio.h> /* Only for legacy support */
  43. +#include <linux/gpio/consumer.h>
  44. +#include <linux/init.h>
  45. +#include <linux/kernel.h>
  46. +#include <linux/module.h>
  47. +#include <linux/of.h>
  48. +#include <linux/of_gpio.h>
  49. +#include <linux/platform_data/gpio_backlight.h>
  50. +#include <linux/platform_device.h>
  51. +#include <linux/slab.h>
  52. +#include <linux/delay.h>
  53. +#include <linux/timer.h>
  54. +#include <linux/poll.h>
  55. +#include <linux/proc_fs.h>
  56. +#include <linux/seq_file.h>
  57. +#include <linux/sched.h>
  58. +#include <linux/interrupt.h>
  59. +#include <linux/irq.h>
  60. +#include <linux/io.h>
  61. +#include <linux/clk.h>
  62. +
  63. +struct ocp8178_backlight {
  64. + struct device *dev;
  65. + struct device *fbdev;
  66. +
  67. + struct gpio_desc *gpiod;
  68. + int def_value;
  69. + int current_value;
  70. +};
  71. +
  72. +#define DETECT_DELAY 200
  73. +#define DETECT_TIME 500
  74. +#define DETECT_WINDOW_TIME 1000
  75. +#define START_TIME 10
  76. +#define END_TIME 10
  77. +#define SHUTDOWN_TIME 3000
  78. +#define LOW_BIT_HIGH_TIME 10
  79. +#define LOW_BIT_LOW_TIME 50
  80. +#define HIGH_BIT_HIGH_TIME 50
  81. +#define HIGH_BIT_LOW_TIME 10
  82. +#define MAX_BRIGHTNESS_VALUE 9
  83. +
  84. +static void entry_1wire_mode(struct ocp8178_backlight *gbl)
  85. +{
  86. + unsigned long flags = 0;
  87. + local_irq_save(flags);
  88. + gpiod_set_value(gbl->gpiod, 0);
  89. + mdelay(SHUTDOWN_TIME/1000);
  90. + gpiod_set_value(gbl->gpiod, 1);
  91. + udelay(DETECT_DELAY);
  92. + gpiod_set_value(gbl->gpiod, 0);
  93. + udelay(DETECT_TIME);
  94. + gpiod_set_value(gbl->gpiod, 1);
  95. + udelay(DETECT_WINDOW_TIME);
  96. + local_irq_restore(flags);
  97. +}
  98. +
  99. +static inline void write_bit(struct ocp8178_backlight *gbl, int bit)
  100. +{
  101. + if (bit) {
  102. + gpiod_set_value(gbl->gpiod, 0);
  103. + udelay(HIGH_BIT_LOW_TIME);
  104. + gpiod_set_value(gbl->gpiod, 1);
  105. + udelay(HIGH_BIT_HIGH_TIME);
  106. + } else {
  107. + gpiod_set_value(gbl->gpiod, 0);
  108. + udelay(LOW_BIT_LOW_TIME);
  109. + gpiod_set_value(gbl->gpiod, 1);
  110. + udelay(LOW_BIT_HIGH_TIME);
  111. + }
  112. +}
  113. +
  114. +static void write_byte(struct ocp8178_backlight *gbl, int byte)
  115. +{
  116. + unsigned long flags = 0;
  117. + unsigned char data = 0x72;
  118. + int i;
  119. +
  120. + local_irq_save(flags);
  121. +
  122. + gpiod_set_value(gbl->gpiod, 1);
  123. + udelay(START_TIME);
  124. + for(i = 0; i < 8; i++) {
  125. + if(data & 0x80) {
  126. + write_bit(gbl, 1);
  127. + } else {
  128. + write_bit(gbl, 0);
  129. + }
  130. + data <<= 1;
  131. + }
  132. + gpiod_set_value(gbl->gpiod, 0);
  133. + udelay(END_TIME);
  134. +
  135. + data = byte & 0x1f;
  136. +
  137. + gpiod_set_value(gbl->gpiod, 1);
  138. + udelay(START_TIME);
  139. + for(i = 0; i < 8; i++) {
  140. + if(data & 0x80) {
  141. + write_bit(gbl, 1);
  142. + } else {
  143. + write_bit(gbl, 0);
  144. + }
  145. + data <<= 1;
  146. + }
  147. + gpiod_set_value(gbl->gpiod, 0);
  148. + udelay(END_TIME);
  149. + gpiod_set_value(gbl->gpiod, 1);
  150. +
  151. + local_irq_restore(flags);
  152. +}
  153. +
  154. +unsigned char ocp8178_bl_table[MAX_BRIGHTNESS_VALUE+1] = {0, 1, 4, 8, 12, 16, 20, 24, 28, 31};
  155. +
  156. +static int ocp8178_update_status(struct backlight_device *bl)
  157. +{
  158. + struct ocp8178_backlight *gbl = bl_get_data(bl);
  159. + int brightness = bl->props.brightness, i;
  160. +
  161. + if (bl->props.power != FB_BLANK_UNBLANK ||
  162. + bl->props.fb_blank != FB_BLANK_UNBLANK ||
  163. + bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
  164. + brightness = 0;
  165. +
  166. + if(brightness > MAX_BRIGHTNESS_VALUE)
  167. + brightness = MAX_BRIGHTNESS_VALUE;
  168. +
  169. + for(i = 0; i < 2; i++) {
  170. + entry_1wire_mode(gbl);
  171. + write_byte(gbl, ocp8178_bl_table[brightness]);
  172. + }
  173. + gbl->current_value = brightness;
  174. +
  175. + return 0;
  176. +}
  177. +
  178. +static int ocp8178_get_brightness(struct backlight_device *bl)
  179. +{
  180. + struct ocp8178_backlight *gbl = bl_get_data(bl);
  181. + return gbl->current_value;
  182. +}
  183. +
  184. +static int ocp8178_check_fb(struct backlight_device *bl,
  185. + struct fb_info *info)
  186. +{
  187. + struct ocp8178_backlight *gbl = bl_get_data(bl);
  188. + return gbl->fbdev == NULL || gbl->fbdev == info->dev;
  189. +}
  190. +
  191. +static const struct backlight_ops ocp8178_backlight_ops = {
  192. + .options = BL_CORE_SUSPENDRESUME,
  193. + .update_status = ocp8178_update_status,
  194. + .get_brightness = ocp8178_get_brightness,
  195. + .check_fb = ocp8178_check_fb,
  196. +};
  197. +
  198. +static int ocp8178_probe_dt(struct platform_device *pdev,
  199. + struct ocp8178_backlight *gbl)
  200. +{
  201. + struct device *dev = &pdev->dev;
  202. + struct device_node *np = dev->of_node;
  203. + enum gpiod_flags flags;
  204. + int ret = 0;
  205. + u32 value32;
  206. +
  207. + of_property_read_u32(np, "default-brightness", &value32);
  208. + if(value32 > MAX_BRIGHTNESS_VALUE)
  209. + gbl->def_value = MAX_BRIGHTNESS_VALUE;
  210. + else
  211. + gbl->def_value = value32;
  212. + flags = gbl->def_value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
  213. +
  214. + gbl->gpiod = devm_gpiod_get(dev, "backlight-control", flags);
  215. + if (IS_ERR(gbl->gpiod)) {
  216. + ret = PTR_ERR(gbl->gpiod);
  217. +
  218. + if (ret != -EPROBE_DEFER) {
  219. + dev_err(dev,
  220. + "Error: The gpios parameter is missing or invalid.\n");
  221. + }
  222. + }
  223. +
  224. + return ret;
  225. +}
  226. +
  227. +static struct backlight_device *backlight;
  228. +
  229. +static int ocp8178_probe(struct platform_device *pdev)
  230. +{
  231. + struct backlight_properties props;
  232. + struct backlight_device *bl;
  233. + struct ocp8178_backlight *gbl;
  234. + struct device_node *np = pdev->dev.of_node;
  235. + int ret;
  236. +
  237. + if ( !np) {
  238. + dev_err(&pdev->dev,
  239. + "failed to find platform data or device tree node.\n");
  240. + return -ENODEV;
  241. + }
  242. +
  243. + gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
  244. + if (gbl == NULL)
  245. + return -ENOMEM;
  246. +
  247. + gbl->dev = &pdev->dev;
  248. +
  249. + ret = ocp8178_probe_dt(pdev, gbl);
  250. + if (ret)
  251. + return ret;
  252. +
  253. + gbl->current_value = gbl->def_value;
  254. +
  255. + memset(&props, 0, sizeof(props));
  256. + props.type = BACKLIGHT_RAW;
  257. + props.max_brightness = MAX_BRIGHTNESS_VALUE;
  258. + bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
  259. + &pdev->dev, gbl, &ocp8178_backlight_ops,
  260. + &props);
  261. + if (IS_ERR(bl)) {
  262. + dev_err(&pdev->dev, "failed to register backlight\n");
  263. + return PTR_ERR(bl);
  264. + }
  265. +
  266. +// entry_1wire_mode(gbl);
  267. +
  268. + bl->props.brightness = gbl->def_value;
  269. + backlight_update_status(bl);
  270. +
  271. + platform_set_drvdata(pdev, bl);
  272. +
  273. + backlight = bl;
  274. + return 0;
  275. +}
  276. +
  277. +static int ocp8178_suspend(struct platform_device *pdev, pm_message_t state)
  278. +{
  279. + return 0;
  280. +}
  281. +
  282. +static int ocp8178_resume(struct platform_device *pdev)
  283. +{
  284. + return 0;
  285. +}
  286. +
  287. +static struct of_device_id ocp8178_of_match[] = {
  288. + { .compatible = "ocp8178-backlight" },
  289. + { /* sentinel */ }
  290. +};
  291. +
  292. +MODULE_DEVICE_TABLE(of, ocp8178_of_match);
  293. +
  294. +static struct platform_driver ocp8178_driver = {
  295. + .driver = {
  296. + .name = "ocp8178-backlight",
  297. + .of_match_table = of_match_ptr(ocp8178_of_match),
  298. + },
  299. + .probe = ocp8178_probe,
  300. + .suspend = ocp8178_suspend,
  301. + .resume = ocp8178_resume,
  302. +};
  303. +
  304. +module_platform_driver(ocp8178_driver);
  305. +
  306. +MODULE_DESCRIPTION("OCP8178 Driver");
  307. +MODULE_LICENSE("GPL");