xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/rockchip/rockchip_drm_backlight.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3*4882a593Smuzhiyun  * Author:Mark Yao <mark.yao@rock-chips.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This software is licensed under the terms of the GNU General Public
6*4882a593Smuzhiyun  * License version 2, as published by the Free Software Foundation, and
7*4882a593Smuzhiyun  * may be copied, distributed, and modified under those terms.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
10*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*4882a593Smuzhiyun  * GNU General Public License for more details.
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <drm/drm.h>
16*4882a593Smuzhiyun #include <drm/drmP.h>
17*4882a593Smuzhiyun #include <drm/drm_panel.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <linux/device.h>
20*4882a593Smuzhiyun #include <linux/kernel.h>
21*4882a593Smuzhiyun #include <linux/module.h>
22*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
23*4882a593Smuzhiyun #include <linux/gpio.h>
24*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
25*4882a593Smuzhiyun #include <linux/of.h>
26*4882a593Smuzhiyun #include <linux/of_device.h>
27*4882a593Smuzhiyun #include <linux/pinctrl/consumer.h>
28*4882a593Smuzhiyun #include <linux/platform_device.h>
29*4882a593Smuzhiyun #include <linux/pwm.h>
30*4882a593Smuzhiyun #include <linux/pwm_backlight.h>
31*4882a593Smuzhiyun #include <uapi/drm/rockchip_drm.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include "rockchip_drm_drv.h"
34*4882a593Smuzhiyun #include "rockchip_drm_backlight.h"
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun struct sub_backlight {
37*4882a593Smuzhiyun 	struct pwm_device *pwm;
38*4882a593Smuzhiyun 	struct pinctrl *pinctrl;
39*4882a593Smuzhiyun 	struct pinctrl_state *dummy_state;
40*4882a593Smuzhiyun 	struct pinctrl_state *active_state;
41*4882a593Smuzhiyun 	struct drm_crtc *crtc;
42*4882a593Smuzhiyun 	struct device *dev;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	const struct rockchip_sub_backlight_ops *ops;
45*4882a593Smuzhiyun 	struct list_head list;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #define to_rockchip_backlight_device(x) \
49*4882a593Smuzhiyun 		container_of((x), struct rockchip_drm_backlight, pwm_pdev)
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun static LIST_HEAD(backlight_list);
52*4882a593Smuzhiyun 
compute_duty_cycle(struct rockchip_drm_backlight * bl,int brightness,int period)53*4882a593Smuzhiyun static int compute_duty_cycle(struct rockchip_drm_backlight *bl,
54*4882a593Smuzhiyun 			      int brightness, int period)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	unsigned int lth = bl->lth_brightness;
57*4882a593Smuzhiyun 	int duty_cycle;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	duty_cycle = bl->levels[brightness];
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	return (duty_cycle * (period - lth) / bl->scale) + lth;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
rockchip_pwm_power_on(struct rockchip_drm_backlight * bl,struct pwm_device * pwm,int brightness)64*4882a593Smuzhiyun static void rockchip_pwm_power_on(struct rockchip_drm_backlight *bl,
65*4882a593Smuzhiyun 				  struct pwm_device *pwm, int brightness)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	struct pwm_args pargs;
68*4882a593Smuzhiyun 	int duty_cycle;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	pwm_get_args(pwm, &pargs);
71*4882a593Smuzhiyun 	duty_cycle = compute_duty_cycle(bl, brightness, pargs.period);
72*4882a593Smuzhiyun 	pwm_config(pwm, duty_cycle, pargs.period);
73*4882a593Smuzhiyun 	pwm_enable(pwm);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
rockchip_pwm_power_off(struct rockchip_drm_backlight * bl,struct pwm_device * pwm)76*4882a593Smuzhiyun static void rockchip_pwm_power_off(struct rockchip_drm_backlight *bl,
77*4882a593Smuzhiyun 				   struct pwm_device *pwm)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	struct pwm_args pargs;
80*4882a593Smuzhiyun 	struct pwm_state state;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	pwm_get_state(pwm, &state);
83*4882a593Smuzhiyun 	if (!state.enabled)
84*4882a593Smuzhiyun 		return;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	pwm_get_args(pwm, &pargs);
87*4882a593Smuzhiyun 	pwm_config(pwm, 0, pargs.period);
88*4882a593Smuzhiyun 	pwm_disable(pwm);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
rockchip_backlight_power_on(struct rockchip_drm_backlight * bl)91*4882a593Smuzhiyun static void rockchip_backlight_power_on(struct rockchip_drm_backlight *bl)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	int err;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	if (bl->enabled)
96*4882a593Smuzhiyun 		return;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	err = regulator_enable(bl->power_supply);
99*4882a593Smuzhiyun 	if (err < 0)
100*4882a593Smuzhiyun 		dev_err(bl->dev, "failed to enable power supply\n");
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	if (bl->enable_gpio)
103*4882a593Smuzhiyun 		gpiod_set_value(bl->enable_gpio, 1);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	bl->enabled = true;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
rockchip_backlight_power_off(struct rockchip_drm_backlight * bl)108*4882a593Smuzhiyun static void rockchip_backlight_power_off(struct rockchip_drm_backlight *bl)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	if (!bl->enabled)
111*4882a593Smuzhiyun 		return;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	if (bl->enable_gpio)
114*4882a593Smuzhiyun 		gpiod_set_value(bl->enable_gpio, 0);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	regulator_disable(bl->power_supply);
117*4882a593Smuzhiyun 	bl->enabled = false;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
backlight_parse_dt(struct rockchip_drm_backlight * bl)120*4882a593Smuzhiyun static int backlight_parse_dt(struct rockchip_drm_backlight *bl)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	struct device_node *node = bl->dev->of_node;
123*4882a593Smuzhiyun 	struct device *dev = bl->dev;
124*4882a593Smuzhiyun 	struct property *prop;
125*4882a593Smuzhiyun 	size_t size;
126*4882a593Smuzhiyun 	int length;
127*4882a593Smuzhiyun 	u32 value;
128*4882a593Smuzhiyun 	int ret, i;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (!node)
131*4882a593Smuzhiyun 		return -ENODEV;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	bl->pwm = devm_pwm_get(dev, NULL);
134*4882a593Smuzhiyun 	if (IS_ERR(bl->pwm)) {
135*4882a593Smuzhiyun 		dev_err(dev, "unable to request PWM: %ld\n",
136*4882a593Smuzhiyun 			PTR_ERR(bl->pwm));
137*4882a593Smuzhiyun 		return PTR_ERR(bl->pwm);
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	if (!bl->pwm->chip->dev->pins) {
141*4882a593Smuzhiyun 		dev_err(dev, "failed to find pwm pinctrl\n");
142*4882a593Smuzhiyun 		return -ENODEV;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 	bl->dummy_state = pinctrl_lookup_state(bl->pwm->chip->dev->pins->p,
145*4882a593Smuzhiyun 					       "dummy");
146*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(bl->dummy_state)) {
147*4882a593Smuzhiyun 		dev_err(dev, "failed to find pwm dummy state\n");
148*4882a593Smuzhiyun 		return -ENODEV;
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	bl->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS);
152*4882a593Smuzhiyun 	if (IS_ERR(bl->enable_gpio)) {
153*4882a593Smuzhiyun 		dev_err(dev, "unable to request enable gpio: %ld\n",
154*4882a593Smuzhiyun 			PTR_ERR(bl->enable_gpio));
155*4882a593Smuzhiyun 		return PTR_ERR(bl->enable_gpio);
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	bl->power_supply = devm_regulator_get(dev, "power");
159*4882a593Smuzhiyun 	if (IS_ERR(bl->power_supply)) {
160*4882a593Smuzhiyun 		dev_err(dev, "unable to request power supply: %ld\n",
161*4882a593Smuzhiyun 			PTR_ERR(bl->power_supply));
162*4882a593Smuzhiyun 		return PTR_ERR(bl->power_supply);
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* determine the number of brightness levels */
166*4882a593Smuzhiyun 	prop = of_find_property(node, "brightness-levels", &length);
167*4882a593Smuzhiyun 	if (!prop)
168*4882a593Smuzhiyun 		return -EINVAL;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	bl->max_brightness = length / sizeof(u32);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	if (bl->max_brightness <= 0)
173*4882a593Smuzhiyun 		return -EINVAL;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	/* read brightness levels from DT property */
176*4882a593Smuzhiyun 	size = sizeof(*bl->levels) * bl->max_brightness;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	bl->levels = devm_kzalloc(dev, size, GFP_KERNEL);
179*4882a593Smuzhiyun 	if (!bl->levels)
180*4882a593Smuzhiyun 		return -ENOMEM;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	ret = of_property_read_u32_array(node, "brightness-levels",
183*4882a593Smuzhiyun 					 bl->levels,
184*4882a593Smuzhiyun 					 bl->max_brightness);
185*4882a593Smuzhiyun 	if (ret < 0)
186*4882a593Smuzhiyun 		return ret;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	ret = of_property_read_u32(node, "default-brightness-level", &value);
189*4882a593Smuzhiyun 	if (ret < 0)
190*4882a593Smuzhiyun 		return ret;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	bl->dft_brightness = value;
193*4882a593Smuzhiyun 	bl->max_brightness--;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	for (i = 0; i <= bl->max_brightness; i++)
196*4882a593Smuzhiyun 		if (bl->levels[i] > bl->scale)
197*4882a593Smuzhiyun 			bl->scale = bl->levels[i];
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	return 0;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
rockchip_drm_backlight_update(struct drm_device * drm)202*4882a593Smuzhiyun void rockchip_drm_backlight_update(struct drm_device *drm)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct rockchip_drm_private *private = drm->dev_private;
205*4882a593Smuzhiyun 	struct rockchip_drm_backlight *bl = private->backlight;
206*4882a593Smuzhiyun 	struct drm_connector *connector;
207*4882a593Smuzhiyun 	struct sub_backlight *sub;
208*4882a593Smuzhiyun 	struct rockchip_crtc_state *s;
209*4882a593Smuzhiyun 	struct drm_crtc *crtc;
210*4882a593Smuzhiyun 	bool backlight_changed = false;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	if (!bl || !bl->connector)
213*4882a593Smuzhiyun 		return;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	sub = bl->sub;
216*4882a593Smuzhiyun 	connector = bl->connector;
217*4882a593Smuzhiyun 	crtc = connector->state->crtc;
218*4882a593Smuzhiyun 	if (!crtc) {
219*4882a593Smuzhiyun 		if (sub) {
220*4882a593Smuzhiyun 			bl->sub = NULL;
221*4882a593Smuzhiyun 			backlight_changed = true;
222*4882a593Smuzhiyun 		}
223*4882a593Smuzhiyun 	} else if (!sub || sub->dev->of_node != crtc->port) {
224*4882a593Smuzhiyun 		s = to_rockchip_crtc_state(crtc->state);
225*4882a593Smuzhiyun 		if (s->cabc_mode != ROCKCHIP_DRM_CABC_MODE_DISABLE) {
226*4882a593Smuzhiyun 			list_for_each_entry(sub, &backlight_list, list) {
227*4882a593Smuzhiyun 				if (sub->crtc == crtc) {
228*4882a593Smuzhiyun 					bl->sub = sub;
229*4882a593Smuzhiyun 					backlight_changed = true;
230*4882a593Smuzhiyun 					break;
231*4882a593Smuzhiyun 				}
232*4882a593Smuzhiyun 			}
233*4882a593Smuzhiyun 		} else if (bl->sub) {
234*4882a593Smuzhiyun 			bl->sub = NULL;
235*4882a593Smuzhiyun 			backlight_changed = true;
236*4882a593Smuzhiyun 		}
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (backlight_changed)
240*4882a593Smuzhiyun 		backlight_update_status(bl->bd);
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun EXPORT_SYMBOL(rockchip_drm_backlight_update);
243*4882a593Smuzhiyun 
of_rockchip_drm_sub_backlight_register(struct device * dev,struct drm_crtc * crtc,const struct rockchip_sub_backlight_ops * ops)244*4882a593Smuzhiyun int of_rockchip_drm_sub_backlight_register(struct device *dev,
245*4882a593Smuzhiyun 				struct drm_crtc *crtc,
246*4882a593Smuzhiyun 				const struct rockchip_sub_backlight_ops *ops)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	struct sub_backlight *sub;
249*4882a593Smuzhiyun 	struct pwm_device *pwm;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	pwm = devm_pwm_get(dev, NULL);
252*4882a593Smuzhiyun 	if (IS_ERR(pwm)) {
253*4882a593Smuzhiyun 		dev_dbg(dev, "unable to request PWM\n");
254*4882a593Smuzhiyun 		return PTR_ERR(pwm);
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	sub = devm_kzalloc(dev, sizeof(*sub), GFP_KERNEL);
258*4882a593Smuzhiyun 	if (!sub)
259*4882a593Smuzhiyun 		return -ENOMEM;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	sub->pinctrl = devm_pinctrl_get(pwm->chip->dev);
262*4882a593Smuzhiyun 	if (IS_ERR(sub->pinctrl)) {
263*4882a593Smuzhiyun 		dev_err(dev, "failed to find pwm pinctrl\n");
264*4882a593Smuzhiyun 		return PTR_ERR(sub->pinctrl);
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	sub->dummy_state = pinctrl_lookup_state(sub->pinctrl, "dummy");
268*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(sub->dummy_state)) {
269*4882a593Smuzhiyun 		dev_err(dev, "failed to find pwm dummy state\n");
270*4882a593Smuzhiyun 		return -ENODEV;
271*4882a593Smuzhiyun 	}
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	sub->active_state = pinctrl_lookup_state(sub->pinctrl, "active");
274*4882a593Smuzhiyun 	if (IS_ERR_OR_NULL(sub->active_state)) {
275*4882a593Smuzhiyun 		dev_err(dev, "failed to find pwm active state\n");
276*4882a593Smuzhiyun 		return -ENODEV;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	pwm_adjust_config(pwm);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	sub->pwm = pwm;
282*4882a593Smuzhiyun 	sub->dev = dev;
283*4882a593Smuzhiyun 	sub->crtc = crtc;
284*4882a593Smuzhiyun 	sub->ops = ops;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	INIT_LIST_HEAD(&sub->list);
287*4882a593Smuzhiyun 	list_add_tail(&sub->list, &backlight_list);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun EXPORT_SYMBOL(of_rockchip_drm_sub_backlight_register);
292*4882a593Smuzhiyun 
rockchip_drm_backlight_bind(struct device * dev,struct device * master,void * data)293*4882a593Smuzhiyun static int rockchip_drm_backlight_bind(struct device *dev,
294*4882a593Smuzhiyun 				       struct device *master, void *data)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct drm_device *drm_dev = data;
297*4882a593Smuzhiyun 	struct rockchip_drm_private *private = drm_dev->dev_private;
298*4882a593Smuzhiyun 	struct rockchip_drm_backlight *bl = dev_get_drvdata(dev);
299*4882a593Smuzhiyun 	struct drm_connector *connector;
300*4882a593Smuzhiyun 	struct drm_panel *panel;
301*4882a593Smuzhiyun 	struct device_node *backlight_np;
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	private->backlight = bl;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	mutex_lock(&drm_dev->mode_config.mutex);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	drm_for_each_connector(connector, drm_dev) {
308*4882a593Smuzhiyun 		panel = drm_find_panel_by_connector(connector);
309*4882a593Smuzhiyun 		if (!panel || !panel->dev)
310*4882a593Smuzhiyun 			continue;
311*4882a593Smuzhiyun 		backlight_np = of_parse_phandle(panel->dev->of_node,
312*4882a593Smuzhiyun 						"backlight", 0);
313*4882a593Smuzhiyun 		if (backlight_np == dev->of_node) {
314*4882a593Smuzhiyun 			bl->connector = connector;
315*4882a593Smuzhiyun 			break;
316*4882a593Smuzhiyun 		}
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	mutex_unlock(&drm_dev->mode_config.mutex);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	if (!bl->connector) {
322*4882a593Smuzhiyun 		dev_warn(dev, "failed to bind drm backlight\n");
323*4882a593Smuzhiyun 		return -ENODEV;
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return 0;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
rockchip_drm_backlight_unbind(struct device * dev,struct device * master,void * data)329*4882a593Smuzhiyun static void rockchip_drm_backlight_unbind(struct device *dev,
330*4882a593Smuzhiyun 					  struct device *master, void *data)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	struct drm_device *drm_dev = data;
333*4882a593Smuzhiyun 	struct rockchip_drm_private *private = drm_dev->dev_private;
334*4882a593Smuzhiyun 	struct rockchip_drm_backlight *bl = dev_get_drvdata(dev);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	private->backlight = NULL;
337*4882a593Smuzhiyun 	bl->connector = NULL;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun static const struct component_ops rockchip_drm_backlight_component_ops = {
341*4882a593Smuzhiyun 	.bind = rockchip_drm_backlight_bind,
342*4882a593Smuzhiyun 	.unbind = rockchip_drm_backlight_unbind,
343*4882a593Smuzhiyun };
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun static int
rockchip_drm_backlight_update_status(struct backlight_device * backlight)346*4882a593Smuzhiyun rockchip_drm_backlight_update_status(struct backlight_device *backlight)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	int brightness = backlight->props.brightness;
349*4882a593Smuzhiyun 	struct rockchip_drm_backlight *bl = bl_get_data(backlight);
350*4882a593Smuzhiyun 	struct sub_backlight *sub = bl->sub;
351*4882a593Smuzhiyun 	struct sub_backlight *current_sub = bl->current_sub;
352*4882a593Smuzhiyun 	bool async;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (backlight->props.power != FB_BLANK_UNBLANK ||
355*4882a593Smuzhiyun 	    backlight->props.fb_blank != FB_BLANK_UNBLANK ||
356*4882a593Smuzhiyun 	    backlight->props.state & BL_CORE_FBBLANK)
357*4882a593Smuzhiyun 		brightness = 0;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	if (!sub || brightness <= 0) {
360*4882a593Smuzhiyun 		if (current_sub)
361*4882a593Smuzhiyun 			pinctrl_select_state(current_sub->pinctrl,
362*4882a593Smuzhiyun 					     current_sub->dummy_state);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		if (brightness > 0) {
365*4882a593Smuzhiyun 			rockchip_pwm_power_on(bl, bl->pwm, brightness);
366*4882a593Smuzhiyun 			rockchip_backlight_power_on(bl);
367*4882a593Smuzhiyun 		} else {
368*4882a593Smuzhiyun 			rockchip_backlight_power_off(bl);
369*4882a593Smuzhiyun 			rockchip_pwm_power_off(bl, bl->pwm);
370*4882a593Smuzhiyun 		}
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 		pinctrl_pm_select_default_state(bl->pwm->chip->dev);
373*4882a593Smuzhiyun 		if (current_sub) {
374*4882a593Smuzhiyun 			rockchip_pwm_power_off(bl, current_sub->pwm);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 			if (current_sub->ops->config_done)
377*4882a593Smuzhiyun 				current_sub->ops->config_done(current_sub->dev,
378*4882a593Smuzhiyun 							      true);
379*4882a593Smuzhiyun 		}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 		return 0;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	pinctrl_select_state(bl->pwm->chip->dev->pins->p, bl->dummy_state);
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	async = !!current_sub;
387*4882a593Smuzhiyun 	if (current_sub && sub != current_sub) {
388*4882a593Smuzhiyun 		pinctrl_select_state(current_sub->pinctrl,
389*4882a593Smuzhiyun 				     current_sub->dummy_state);
390*4882a593Smuzhiyun 		async = false;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	rockchip_pwm_power_on(bl, sub->pwm, brightness);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (current_sub && sub != current_sub) {
396*4882a593Smuzhiyun 		rockchip_pwm_power_on(bl, current_sub->pwm, brightness);
397*4882a593Smuzhiyun 		if (current_sub->ops->config_done)
398*4882a593Smuzhiyun 			current_sub->ops->config_done(current_sub->dev, true);
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (sub->ops->config_done)
402*4882a593Smuzhiyun 		sub->ops->config_done(sub->dev, async);
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	pinctrl_select_state(sub->pinctrl, sub->active_state);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	rockchip_backlight_power_on(bl);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	bl->current_sub = sub;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	return 0;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun static const struct backlight_ops rockchip_drm_backlight_ops = {
414*4882a593Smuzhiyun 	.update_status = rockchip_drm_backlight_update_status,
415*4882a593Smuzhiyun };
416*4882a593Smuzhiyun 
rockchip_drm_backlight_probe(struct platform_device * pdev)417*4882a593Smuzhiyun static int rockchip_drm_backlight_probe(struct platform_device *pdev)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun 	struct rockchip_drm_backlight *bl;
420*4882a593Smuzhiyun 	struct backlight_properties props;
421*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
422*4882a593Smuzhiyun 	struct device_node *node = dev->of_node;
423*4882a593Smuzhiyun 	int initial_blank = FB_BLANK_UNBLANK;
424*4882a593Smuzhiyun 	int ret;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	bl = devm_kzalloc(dev, sizeof(*bl), GFP_KERNEL);
427*4882a593Smuzhiyun 	if (!bl)
428*4882a593Smuzhiyun 		return -ENOMEM;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	bl->dev = dev;
431*4882a593Smuzhiyun 	ret = backlight_parse_dt(bl);
432*4882a593Smuzhiyun 	if (ret < 0) {
433*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to find parse backlight dts\n");
434*4882a593Smuzhiyun 		return ret;
435*4882a593Smuzhiyun 	}
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	bl->enabled = false;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	if (bl->enable_gpio) {
440*4882a593Smuzhiyun 		/*
441*4882a593Smuzhiyun 		 * If the driver is probed from the device tree and there is a
442*4882a593Smuzhiyun 		 * phandle link pointing to the backlight node, it is safe to
443*4882a593Smuzhiyun 		 * assume that another driver will enable the backlight at the
444*4882a593Smuzhiyun 		 * appropriate time. Therefore, if it is disabled, keep it so.
445*4882a593Smuzhiyun 		 */
446*4882a593Smuzhiyun 		if (node && node->phandle &&
447*4882a593Smuzhiyun 		    gpiod_get_direction(bl->enable_gpio) == GPIOF_DIR_OUT &&
448*4882a593Smuzhiyun 		    gpiod_get_value(bl->enable_gpio) == 0)
449*4882a593Smuzhiyun 			initial_blank = FB_BLANK_POWERDOWN;
450*4882a593Smuzhiyun 		else
451*4882a593Smuzhiyun 			gpiod_direction_output(bl->enable_gpio, 1);
452*4882a593Smuzhiyun 	}
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (node && node->phandle && !regulator_is_enabled(bl->power_supply))
455*4882a593Smuzhiyun 		initial_blank = FB_BLANK_POWERDOWN;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	pwm_adjust_config(bl->pwm);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	memset(&props, 0, sizeof(props));
460*4882a593Smuzhiyun 	props.type = BACKLIGHT_RAW;
461*4882a593Smuzhiyun 	props.max_brightness = bl->max_brightness;
462*4882a593Smuzhiyun 	bl->bd = backlight_device_register(dev_name(dev), dev, bl,
463*4882a593Smuzhiyun 					   &rockchip_drm_backlight_ops, &props);
464*4882a593Smuzhiyun 	if (IS_ERR(bl->bd)) {
465*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to register backlight\n");
466*4882a593Smuzhiyun 		ret = PTR_ERR(bl->bd);
467*4882a593Smuzhiyun 		return ret;
468*4882a593Smuzhiyun 	}
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	bl->bd->props.brightness = bl->dft_brightness;
471*4882a593Smuzhiyun 	bl->bd->props.power = initial_blank;
472*4882a593Smuzhiyun 	backlight_update_status(bl->bd);
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	platform_set_drvdata(pdev, bl);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	ret = component_add(dev, &rockchip_drm_backlight_component_ops);
477*4882a593Smuzhiyun 	if (ret)
478*4882a593Smuzhiyun 		backlight_device_unregister(bl->bd);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	return ret;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
rockchip_drm_backlight_remove(struct platform_device * pdev)483*4882a593Smuzhiyun static int rockchip_drm_backlight_remove(struct platform_device *pdev)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	struct rockchip_drm_backlight *bl = platform_get_drvdata(pdev);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	backlight_device_unregister(bl->bd);
488*4882a593Smuzhiyun 	component_del(&pdev->dev, &rockchip_drm_backlight_component_ops);
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	return 0;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun static const struct of_device_id rockchip_drm_backlight_dt_ids[] = {
494*4882a593Smuzhiyun 	{.compatible = "rockchip,drm-backlight",
495*4882a593Smuzhiyun 	 .data = NULL },
496*4882a593Smuzhiyun 	{}
497*4882a593Smuzhiyun };
498*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, rockchip_drm_backlight_dt_ids);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun static struct platform_driver rockchip_drm_backlight_driver = {
501*4882a593Smuzhiyun 	.probe = rockchip_drm_backlight_probe,
502*4882a593Smuzhiyun 	.remove = rockchip_drm_backlight_remove,
503*4882a593Smuzhiyun 	.driver = {
504*4882a593Smuzhiyun 		   .name = "drm-backlight",
505*4882a593Smuzhiyun 		   .of_match_table =
506*4882a593Smuzhiyun 			of_match_ptr(rockchip_drm_backlight_dt_ids),
507*4882a593Smuzhiyun 	},
508*4882a593Smuzhiyun };
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun module_platform_driver(rockchip_drm_backlight_driver);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>");
513*4882a593Smuzhiyun MODULE_DESCRIPTION("Rockchip Drm Backlight Driver");
514*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
515