0001
0002
0003
0004
0005
0006 #include <linux/backlight.h>
0007 #include <linux/err.h>
0008 #include <linux/fb.h>
0009 #include <linux/gpio/consumer.h>
0010 #include <linux/init.h>
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/platform_data/gpio_backlight.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/property.h>
0017 #include <linux/slab.h>
0018
0019 struct gpio_backlight {
0020 struct device *fbdev;
0021 struct gpio_desc *gpiod;
0022 };
0023
0024 static int gpio_backlight_update_status(struct backlight_device *bl)
0025 {
0026 struct gpio_backlight *gbl = bl_get_data(bl);
0027
0028 gpiod_set_value_cansleep(gbl->gpiod, backlight_get_brightness(bl));
0029
0030 return 0;
0031 }
0032
0033 static int gpio_backlight_check_fb(struct backlight_device *bl,
0034 struct fb_info *info)
0035 {
0036 struct gpio_backlight *gbl = bl_get_data(bl);
0037
0038 return gbl->fbdev == NULL || gbl->fbdev == info->dev;
0039 }
0040
0041 static const struct backlight_ops gpio_backlight_ops = {
0042 .options = BL_CORE_SUSPENDRESUME,
0043 .update_status = gpio_backlight_update_status,
0044 .check_fb = gpio_backlight_check_fb,
0045 };
0046
0047 static int gpio_backlight_probe(struct platform_device *pdev)
0048 {
0049 struct device *dev = &pdev->dev;
0050 struct gpio_backlight_platform_data *pdata = dev_get_platdata(dev);
0051 struct device_node *of_node = dev->of_node;
0052 struct backlight_properties props;
0053 struct backlight_device *bl;
0054 struct gpio_backlight *gbl;
0055 int ret, init_brightness, def_value;
0056
0057 gbl = devm_kzalloc(dev, sizeof(*gbl), GFP_KERNEL);
0058 if (gbl == NULL)
0059 return -ENOMEM;
0060
0061 if (pdata)
0062 gbl->fbdev = pdata->fbdev;
0063
0064 def_value = device_property_read_bool(dev, "default-on");
0065
0066 gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS);
0067 if (IS_ERR(gbl->gpiod)) {
0068 ret = PTR_ERR(gbl->gpiod);
0069 if (ret != -EPROBE_DEFER)
0070 dev_err(dev,
0071 "Error: The gpios parameter is missing or invalid.\n");
0072 return ret;
0073 }
0074
0075 memset(&props, 0, sizeof(props));
0076 props.type = BACKLIGHT_RAW;
0077 props.max_brightness = 1;
0078 bl = devm_backlight_device_register(dev, dev_name(dev), dev, gbl,
0079 &gpio_backlight_ops, &props);
0080 if (IS_ERR(bl)) {
0081 dev_err(dev, "failed to register backlight\n");
0082 return PTR_ERR(bl);
0083 }
0084
0085
0086 if (!of_node || !of_node->phandle)
0087
0088 bl->props.power = def_value ? FB_BLANK_UNBLANK
0089 : FB_BLANK_POWERDOWN;
0090 else if (gpiod_get_direction(gbl->gpiod) == 0 &&
0091 gpiod_get_value_cansleep(gbl->gpiod) == 0)
0092 bl->props.power = FB_BLANK_POWERDOWN;
0093 else
0094 bl->props.power = FB_BLANK_UNBLANK;
0095
0096 bl->props.brightness = 1;
0097
0098 init_brightness = backlight_get_brightness(bl);
0099 ret = gpiod_direction_output(gbl->gpiod, init_brightness);
0100 if (ret) {
0101 dev_err(dev, "failed to set initial brightness\n");
0102 return ret;
0103 }
0104
0105 platform_set_drvdata(pdev, bl);
0106 return 0;
0107 }
0108
0109 static struct of_device_id gpio_backlight_of_match[] = {
0110 { .compatible = "gpio-backlight" },
0111 { }
0112 };
0113
0114 MODULE_DEVICE_TABLE(of, gpio_backlight_of_match);
0115
0116 static struct platform_driver gpio_backlight_driver = {
0117 .driver = {
0118 .name = "gpio-backlight",
0119 .of_match_table = gpio_backlight_of_match,
0120 },
0121 .probe = gpio_backlight_probe,
0122 };
0123
0124 module_platform_driver(gpio_backlight_driver);
0125
0126 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
0127 MODULE_DESCRIPTION("GPIO-based Backlight Driver");
0128 MODULE_LICENSE("GPL");
0129 MODULE_ALIAS("platform:gpio-backlight");