]>
Commit | Line | Data |
---|---|---|
8b770e3c LP |
1 | /* |
2 | * gpio_backlight.c - Simple GPIO-controlled backlight | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | */ | |
8 | ||
9 | #include <linux/backlight.h> | |
10 | #include <linux/err.h> | |
11 | #include <linux/fb.h> | |
de738900 LW |
12 | #include <linux/gpio.h> /* Only for legacy support */ |
13 | #include <linux/gpio/consumer.h> | |
8b770e3c LP |
14 | #include <linux/init.h> |
15 | #include <linux/kernel.h> | |
16 | #include <linux/module.h> | |
9a6adb33 DC |
17 | #include <linux/of.h> |
18 | #include <linux/of_gpio.h> | |
8b770e3c LP |
19 | #include <linux/platform_data/gpio_backlight.h> |
20 | #include <linux/platform_device.h> | |
21 | #include <linux/slab.h> | |
22 | ||
23 | struct gpio_backlight { | |
24 | struct device *dev; | |
25 | struct device *fbdev; | |
26 | ||
de738900 | 27 | struct gpio_desc *gpiod; |
9a6adb33 | 28 | int def_value; |
8b770e3c LP |
29 | }; |
30 | ||
31 | static int gpio_backlight_update_status(struct backlight_device *bl) | |
32 | { | |
33 | struct gpio_backlight *gbl = bl_get_data(bl); | |
34 | int brightness = bl->props.brightness; | |
35 | ||
36 | if (bl->props.power != FB_BLANK_UNBLANK || | |
37 | bl->props.fb_blank != FB_BLANK_UNBLANK || | |
38 | bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) | |
39 | brightness = 0; | |
40 | ||
2606706e | 41 | gpiod_set_value_cansleep(gbl->gpiod, brightness); |
8b770e3c LP |
42 | |
43 | return 0; | |
44 | } | |
45 | ||
8b770e3c LP |
46 | static int gpio_backlight_check_fb(struct backlight_device *bl, |
47 | struct fb_info *info) | |
48 | { | |
49 | struct gpio_backlight *gbl = bl_get_data(bl); | |
50 | ||
51 | return gbl->fbdev == NULL || gbl->fbdev == info->dev; | |
52 | } | |
53 | ||
54 | static const struct backlight_ops gpio_backlight_ops = { | |
55 | .options = BL_CORE_SUSPENDRESUME, | |
56 | .update_status = gpio_backlight_update_status, | |
8b770e3c LP |
57 | .check_fb = gpio_backlight_check_fb, |
58 | }; | |
59 | ||
9a6adb33 DC |
60 | static int gpio_backlight_probe_dt(struct platform_device *pdev, |
61 | struct gpio_backlight *gbl) | |
62 | { | |
de738900 LW |
63 | struct device *dev = &pdev->dev; |
64 | struct device_node *np = dev->of_node; | |
65 | enum gpiod_flags flags; | |
66 | int ret; | |
67 | ||
68 | gbl->def_value = of_property_read_bool(np, "default-on"); | |
69 | flags = gbl->def_value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; | |
9a6adb33 | 70 | |
de738900 LW |
71 | gbl->gpiod = devm_gpiod_get(dev, NULL, flags); |
72 | if (IS_ERR(gbl->gpiod)) { | |
73 | ret = PTR_ERR(gbl->gpiod); | |
9a6adb33 | 74 | |
de738900 LW |
75 | if (ret != -EPROBE_DEFER) { |
76 | dev_err(dev, | |
9a6adb33 DC |
77 | "Error: The gpios parameter is missing or invalid.\n"); |
78 | } | |
de738900 | 79 | return ret; |
9a6adb33 DC |
80 | } |
81 | ||
9a6adb33 DC |
82 | return 0; |
83 | } | |
84 | ||
8b770e3c LP |
85 | static int gpio_backlight_probe(struct platform_device *pdev) |
86 | { | |
c512794c JH |
87 | struct gpio_backlight_platform_data *pdata = |
88 | dev_get_platdata(&pdev->dev); | |
8b770e3c LP |
89 | struct backlight_properties props; |
90 | struct backlight_device *bl; | |
91 | struct gpio_backlight *gbl; | |
9a6adb33 | 92 | struct device_node *np = pdev->dev.of_node; |
8b770e3c LP |
93 | int ret; |
94 | ||
9a6adb33 DC |
95 | if (!pdata && !np) { |
96 | dev_err(&pdev->dev, | |
97 | "failed to find platform data or device tree node.\n"); | |
8b770e3c LP |
98 | return -ENODEV; |
99 | } | |
100 | ||
101 | gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL); | |
102 | if (gbl == NULL) | |
103 | return -ENOMEM; | |
104 | ||
105 | gbl->dev = &pdev->dev; | |
9a6adb33 DC |
106 | |
107 | if (np) { | |
108 | ret = gpio_backlight_probe_dt(pdev, gbl); | |
109 | if (ret) | |
110 | return ret; | |
111 | } else { | |
de738900 LW |
112 | /* |
113 | * Legacy platform data GPIO retrieveal. Do not expand | |
114 | * the use of this code path, currently only used by one | |
115 | * SH board. | |
116 | */ | |
117 | unsigned long flags = GPIOF_DIR_OUT; | |
118 | ||
9a6adb33 | 119 | gbl->fbdev = pdata->fbdev; |
9a6adb33 | 120 | gbl->def_value = pdata->def_value; |
2606706e | 121 | flags |= gbl->def_value ? GPIOF_INIT_HIGH : GPIOF_INIT_LOW; |
de738900 LW |
122 | |
123 | ret = devm_gpio_request_one(gbl->dev, pdata->gpio, flags, | |
124 | pdata ? pdata->name : "backlight"); | |
125 | if (ret < 0) { | |
126 | dev_err(&pdev->dev, "unable to request GPIO\n"); | |
127 | return ret; | |
128 | } | |
129 | gbl->gpiod = gpio_to_desc(pdata->gpio); | |
130 | if (!gbl->gpiod) | |
131 | return -EINVAL; | |
8b770e3c LP |
132 | } |
133 | ||
134 | memset(&props, 0, sizeof(props)); | |
135 | props.type = BACKLIGHT_RAW; | |
136 | props.max_brightness = 1; | |
ff472015 JH |
137 | bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev), |
138 | &pdev->dev, gbl, &gpio_backlight_ops, | |
139 | &props); | |
8b770e3c LP |
140 | if (IS_ERR(bl)) { |
141 | dev_err(&pdev->dev, "failed to register backlight\n"); | |
142 | return PTR_ERR(bl); | |
143 | } | |
144 | ||
9a6adb33 | 145 | bl->props.brightness = gbl->def_value; |
8b770e3c LP |
146 | backlight_update_status(bl); |
147 | ||
148 | platform_set_drvdata(pdev, bl); | |
149 | return 0; | |
150 | } | |
151 | ||
9a6adb33 DC |
152 | #ifdef CONFIG_OF |
153 | static struct of_device_id gpio_backlight_of_match[] = { | |
154 | { .compatible = "gpio-backlight" }, | |
155 | { /* sentinel */ } | |
156 | }; | |
4d866723 AB |
157 | |
158 | MODULE_DEVICE_TABLE(of, gpio_backlight_of_match); | |
9a6adb33 DC |
159 | #endif |
160 | ||
8b770e3c LP |
161 | static struct platform_driver gpio_backlight_driver = { |
162 | .driver = { | |
163 | .name = "gpio-backlight", | |
9a6adb33 | 164 | .of_match_table = of_match_ptr(gpio_backlight_of_match), |
8b770e3c LP |
165 | }, |
166 | .probe = gpio_backlight_probe, | |
8b770e3c LP |
167 | }; |
168 | ||
169 | module_platform_driver(gpio_backlight_driver); | |
170 | ||
171 | MODULE_AUTHOR("Laurent Pinchart <[email protected]>"); | |
172 | MODULE_DESCRIPTION("GPIO-based Backlight Driver"); | |
173 | MODULE_LICENSE("GPL"); | |
174 | MODULE_ALIAS("platform:gpio-backlight"); |