rockchip: video: Convert to use APIs which support live DT
[oweals/u-boot.git] / drivers / video / pwm_backlight.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2016 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6
7 #define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
8
9 #include <common.h>
10 #include <dm.h>
11 #include <backlight.h>
12 #include <malloc.h>
13 #include <pwm.h>
14 #include <asm/gpio.h>
15 #include <power/regulator.h>
16
17 /**
18  * Private information for the PWM backlight
19  *
20  * If @num_levels is 0 then the levels are simple values with the backlight
21  * value going between the minimum (default 0) and the maximum (default 255).
22  * Otherwise the levels are an index into @levels (0..n-1).
23  *
24  * @reg: Regulator to enable to turn the backlight on (NULL if none)
25  * @enable, GPIO to set to enable the backlight (can be missing)
26  * @pwm: PWM to use to change the backlight brightness
27  * @channel: PWM channel to use
28  * @period_ns: Period of the backlight in nanoseconds
29  * @levels: Levels for the backlight, or NULL if not using indexed levels
30  * @num_levels: Number of levels
31  * @cur_level: Current level for the backlight (index or value)
32  * @default_level: Default level for the backlight (index or value)
33  * @min_level: Minimum level of the backlight (full off)
34  * @min_level: Maximum level of the backlight (full on)
35  * @enabled: true if backlight is enabled
36  */
37 struct pwm_backlight_priv {
38         struct udevice *reg;
39         struct gpio_desc enable;
40         struct udevice *pwm;
41         uint channel;
42         uint period_ns;
43         /*
44          * the polarity of one PWM
45          * 0: normal polarity
46          * 1: inverted polarity
47          */
48         bool polarity;
49         u32 *levels;
50         int num_levels;
51         uint default_level;
52         int cur_level;
53         uint min_level;
54         uint max_level;
55         bool enabled;
56 };
57
58 static int set_pwm(struct pwm_backlight_priv *priv)
59 {
60         uint duty_cycle;
61         int ret;
62
63         duty_cycle = priv->period_ns * (priv->cur_level - priv->min_level) /
64                 (priv->max_level - priv->min_level + 1);
65         ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns,
66                              duty_cycle);
67         if (ret)
68                 return log_ret(ret);
69
70         ret = pwm_set_invert(priv->pwm, priv->channel, priv->polarity);
71         if (ret == -ENOSYS && !priv->polarity)
72                 ret = 0;
73
74         return log_ret(ret);
75 }
76
77 static int enable_sequence(struct udevice *dev, int seq)
78 {
79         struct pwm_backlight_priv *priv = dev_get_priv(dev);
80         int ret;
81
82         switch (seq) {
83         case 0:
84                 if (priv->reg) {
85                         __maybe_unused struct dm_regulator_uclass_platdata
86                                 *plat;
87
88                         plat = dev_get_uclass_platdata(priv->reg);
89                         log_debug("Enable '%s', regulator '%s'/'%s'\n",
90                                   dev->name, priv->reg->name, plat->name);
91                         ret = regulator_set_enable(priv->reg, true);
92                         if (ret) {
93                                 log_debug("Cannot enable regulator for PWM '%s'\n",
94                                           dev->name);
95                                 return log_ret(ret);
96                         }
97                         mdelay(120);
98                 }
99                 break;
100         case 1:
101                 mdelay(10);
102                 dm_gpio_set_value(&priv->enable, 1);
103                 break;
104         }
105
106         return 0;
107 }
108
109 static int pwm_backlight_enable(struct udevice *dev)
110 {
111         struct pwm_backlight_priv *priv = dev_get_priv(dev);
112         int ret;
113
114         ret = enable_sequence(dev, 0);
115         if (ret)
116                 return log_ret(ret);
117         ret = set_pwm(priv);
118         if (ret)
119                 return log_ret(ret);
120         ret = pwm_set_enable(priv->pwm, priv->channel, true);
121         if (ret)
122                 return log_ret(ret);
123         ret = enable_sequence(dev, 1);
124         if (ret)
125                 return log_ret(ret);
126         priv->enabled = true;
127
128         return 0;
129 }
130
131 static int pwm_backlight_set_brightness(struct udevice *dev, int percent)
132 {
133         struct pwm_backlight_priv *priv = dev_get_priv(dev);
134         bool disable = false;
135         int level;
136         int ret;
137
138         if (!priv->enabled) {
139                 ret = enable_sequence(dev, 0);
140                 if (ret)
141                         return log_ret(ret);
142         }
143         if (percent == BACKLIGHT_OFF) {
144                 disable = true;
145                 percent = 0;
146         }
147         if (percent == BACKLIGHT_DEFAULT) {
148                 level = priv->default_level;
149         } else {
150                 if (priv->levels) {
151                         level = priv->levels[percent * (priv->num_levels - 1)
152                                 / 100];
153                 } else {
154                         level = priv->min_level +
155                                 (priv->max_level - priv->min_level) *
156                                 percent / 100;
157                 }
158         }
159         priv->cur_level = level;
160
161         ret = set_pwm(priv);
162         if (ret)
163                 return log_ret(ret);
164         if (!priv->enabled) {
165                 ret = enable_sequence(dev, 1);
166                 if (ret)
167                         return log_ret(ret);
168                 priv->enabled = true;
169         }
170         if (disable) {
171                 dm_gpio_set_value(&priv->enable, 0);
172                 if (priv->reg) {
173                         ret = regulator_set_enable(priv->reg, false);
174                         if (ret)
175                                 return log_ret(ret);
176                 }
177                 priv->enabled = false;
178         }
179
180         return 0;
181 }
182
183 static int pwm_backlight_ofdata_to_platdata(struct udevice *dev)
184 {
185         struct pwm_backlight_priv *priv = dev_get_priv(dev);
186         struct ofnode_phandle_args args;
187         int index, ret, count, len;
188         const u32 *cell;
189
190         log_debug("start\n");
191         ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
192                                            "power-supply", &priv->reg);
193         if (ret)
194                 log_debug("Cannot get power supply: ret=%d\n", ret);
195         ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable,
196                                    GPIOD_IS_OUT);
197         if (ret) {
198                 log_debug("Warning: cannot get enable GPIO: ret=%d\n", ret);
199                 if (ret != -ENOENT)
200                         return log_ret(ret);
201         }
202         ret = dev_read_phandle_with_args(dev, "pwms", "#pwm-cells", 0, 0,
203                                          &args);
204         if (ret) {
205                 log_debug("Cannot get PWM phandle: ret=%d\n", ret);
206                 return log_ret(ret);
207         }
208
209         ret = uclass_get_device_by_ofnode(UCLASS_PWM, args.node, &priv->pwm);
210         if (ret) {
211                 log_debug("Cannot get PWM: ret=%d\n", ret);
212                 return log_ret(ret);
213         }
214         if (args.args_count < 2)
215                 return log_msg_ret("Not enough arguments to pwm\n", -EINVAL);
216         priv->channel = args.args[0];
217         priv->period_ns = args.args[1];
218         if (args.args_count > 2)
219                 priv->polarity = args.args[2];
220
221         index = dev_read_u32_default(dev, "default-brightness-level", 255);
222         cell = dev_read_prop(dev, "brightness-levels", &len);
223         count = len / sizeof(u32);
224         if (cell && count > index) {
225                 priv->levels = malloc(len);
226                 if (!priv->levels)
227                         return log_ret(-ENOMEM);
228                 dev_read_u32_array(dev, "brightness-levels", priv->levels,
229                                    count);
230                 priv->num_levels = count;
231                 priv->default_level = priv->levels[index];
232                 priv->max_level = priv->levels[count - 1];
233         } else {
234                 priv->default_level = index;
235                 priv->max_level = 255;
236         }
237         priv->cur_level = priv->default_level;
238         log_debug("done\n");
239
240
241         return 0;
242 }
243
244 static int pwm_backlight_probe(struct udevice *dev)
245 {
246         return 0;
247 }
248
249 static const struct backlight_ops pwm_backlight_ops = {
250         .enable         = pwm_backlight_enable,
251         .set_brightness = pwm_backlight_set_brightness,
252 };
253
254 static const struct udevice_id pwm_backlight_ids[] = {
255         { .compatible = "pwm-backlight" },
256         { }
257 };
258
259 U_BOOT_DRIVER(pwm_backlight) = {
260         .name   = "pwm_backlight",
261         .id     = UCLASS_PANEL_BACKLIGHT,
262         .of_match = pwm_backlight_ids,
263         .ops    = &pwm_backlight_ops,
264         .ofdata_to_platdata     = pwm_backlight_ofdata_to_platdata,
265         .probe          = pwm_backlight_probe,
266         .priv_auto_alloc_size   = sizeof(struct pwm_backlight_priv),
267 };