Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * gpio_backlight.c - Simple GPIO-controlled backlight
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     /* Set the initial power state */
0086     if (!of_node || !of_node->phandle)
0087         /* Not booted with device tree or no phandle link to the node */
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     { /* sentinel */ }
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");