lv5207lp.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Sanyo LV5207LP LED Driver
  3. *
  4. * Copyright (C) 2013 Ideas on board SPRL
  5. *
  6. * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  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. #include <linux/backlight.h>
  13. #include <linux/err.h>
  14. #include <linux/fb.h>
  15. #include <linux/i2c.h>
  16. #include <linux/module.h>
  17. #include <linux/platform_data/lv5207lp.h>
  18. #include <linux/slab.h>
  19. #define LV5207LP_CTRL1 0x00
  20. #define LV5207LP_CPSW (1 << 7)
  21. #define LV5207LP_SCTEN (1 << 6)
  22. #define LV5207LP_C10 (1 << 5)
  23. #define LV5207LP_CKSW (1 << 4)
  24. #define LV5207LP_RSW (1 << 3)
  25. #define LV5207LP_GSW (1 << 2)
  26. #define LV5207LP_BSW (1 << 1)
  27. #define LV5207LP_CTRL2 0x01
  28. #define LV5207LP_MSW (1 << 7)
  29. #define LV5207LP_MLED4 (1 << 6)
  30. #define LV5207LP_RED 0x02
  31. #define LV5207LP_GREEN 0x03
  32. #define LV5207LP_BLUE 0x04
  33. #define LV5207LP_MAX_BRIGHTNESS 32
  34. struct lv5207lp {
  35. struct i2c_client *client;
  36. struct backlight_device *backlight;
  37. struct lv5207lp_platform_data *pdata;
  38. };
  39. static int lv5207lp_write(struct lv5207lp *lv, u8 reg, u8 data)
  40. {
  41. return i2c_smbus_write_byte_data(lv->client, reg, data);
  42. }
  43. static int lv5207lp_backlight_update_status(struct backlight_device *backlight)
  44. {
  45. struct lv5207lp *lv = bl_get_data(backlight);
  46. int brightness = backlight->props.brightness;
  47. if (backlight->props.power != FB_BLANK_UNBLANK ||
  48. backlight->props.fb_blank != FB_BLANK_UNBLANK ||
  49. backlight->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
  50. brightness = 0;
  51. if (brightness) {
  52. lv5207lp_write(lv, LV5207LP_CTRL1,
  53. LV5207LP_CPSW | LV5207LP_C10 | LV5207LP_CKSW);
  54. lv5207lp_write(lv, LV5207LP_CTRL2,
  55. LV5207LP_MSW | LV5207LP_MLED4 |
  56. (brightness - 1));
  57. } else {
  58. lv5207lp_write(lv, LV5207LP_CTRL1, 0);
  59. lv5207lp_write(lv, LV5207LP_CTRL2, 0);
  60. }
  61. return 0;
  62. }
  63. static int lv5207lp_backlight_get_brightness(struct backlight_device *backlight)
  64. {
  65. return backlight->props.brightness;
  66. }
  67. static int lv5207lp_backlight_check_fb(struct backlight_device *backlight,
  68. struct fb_info *info)
  69. {
  70. struct lv5207lp *lv = bl_get_data(backlight);
  71. return lv->pdata->fbdev == NULL || lv->pdata->fbdev == info->dev;
  72. }
  73. static const struct backlight_ops lv5207lp_backlight_ops = {
  74. .options = BL_CORE_SUSPENDRESUME,
  75. .update_status = lv5207lp_backlight_update_status,
  76. .get_brightness = lv5207lp_backlight_get_brightness,
  77. .check_fb = lv5207lp_backlight_check_fb,
  78. };
  79. static int lv5207lp_probe(struct i2c_client *client,
  80. const struct i2c_device_id *id)
  81. {
  82. struct lv5207lp_platform_data *pdata = client->dev.platform_data;
  83. struct backlight_device *backlight;
  84. struct backlight_properties props;
  85. struct lv5207lp *lv;
  86. if (pdata == NULL) {
  87. dev_err(&client->dev, "No platform data supplied\n");
  88. return -EINVAL;
  89. }
  90. if (!i2c_check_functionality(client->adapter,
  91. I2C_FUNC_SMBUS_BYTE_DATA)) {
  92. dev_warn(&client->dev,
  93. "I2C adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
  94. return -EIO;
  95. }
  96. lv = devm_kzalloc(&client->dev, sizeof(*lv), GFP_KERNEL);
  97. if (!lv)
  98. return -ENOMEM;
  99. lv->client = client;
  100. lv->pdata = pdata;
  101. memset(&props, 0, sizeof(props));
  102. props.type = BACKLIGHT_RAW;
  103. props.max_brightness = min_t(unsigned int, pdata->max_value,
  104. LV5207LP_MAX_BRIGHTNESS);
  105. props.brightness = clamp_t(unsigned int, pdata->def_value, 0,
  106. props.max_brightness);
  107. backlight = backlight_device_register(dev_name(&client->dev),
  108. &lv->client->dev, lv,
  109. &lv5207lp_backlight_ops, &props);
  110. if (IS_ERR(backlight)) {
  111. dev_err(&client->dev, "failed to register backlight\n");
  112. return PTR_ERR(backlight);
  113. }
  114. backlight_update_status(backlight);
  115. i2c_set_clientdata(client, backlight);
  116. return 0;
  117. }
  118. static int lv5207lp_remove(struct i2c_client *client)
  119. {
  120. struct backlight_device *backlight = i2c_get_clientdata(client);
  121. backlight->props.brightness = 0;
  122. backlight_update_status(backlight);
  123. backlight_device_unregister(backlight);
  124. return 0;
  125. }
  126. static const struct i2c_device_id lv5207lp_ids[] = {
  127. { "lv5207lp", 0 },
  128. { }
  129. };
  130. MODULE_DEVICE_TABLE(i2c, lv5207lp_ids);
  131. static struct i2c_driver lv5207lp_driver = {
  132. .driver = {
  133. .name = "lv5207lp",
  134. },
  135. .probe = lv5207lp_probe,
  136. .remove = lv5207lp_remove,
  137. .id_table = lv5207lp_ids,
  138. };
  139. module_i2c_driver(lv5207lp_driver);
  140. MODULE_DESCRIPTION("Sanyo LV5207LP Backlight Driver");
  141. MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
  142. MODULE_LICENSE("GPL");