File Index
Files and directories
Sign in
FILE

pwm_bl.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/backlight/pwm_bl.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Simple PWM based backlight control, board code has to setup
  4 * 1) pin configuration so PWM waveforms can output
  5 * 2) platform_data being correctly configured
  6 */
  7
  8#include <linux/delay.h>
  9#include <linux/gpio/consumer.h>
 10#include <linux/module.h>
 11#include <linux/kernel.h>
 12#include <linux/init.h>
 13#include <linux/platform_device.h>
 14#include <linux/backlight.h>
 15#include <linux/err.h>
 16#include <linux/pwm.h>
 17#include <linux/pwm_backlight.h>
 18#include <linux/regulator/consumer.h>
 19#include <linux/slab.h>
 20
 21struct pwm_bl_data {
 22	struct pwm_device	*pwm;
 23	struct device		*dev;
 24	unsigned int		lth_brightness;
 25	unsigned int		*levels;
 26	bool			enabled;
 27	struct regulator	*power_supply;
 28	struct gpio_desc	*enable_gpio;
 29	unsigned int		scale;
 30	unsigned int		post_pwm_on_delay;
 31	unsigned int		pwm_off_delay;
 32	int			(*notify)(struct device *,
 33					  int brightness);
 34	void			(*notify_after)(struct device *,
 35					int brightness);
 36	void			(*exit)(struct device *);
 37};
 38
 39static void pwm_backlight_power_on(struct pwm_bl_data *pb)
 40{
 41	int err;
 42
 43	if (pb->enabled)
 44		return;
 45
 46	if (pb->power_supply) {
 47		err = regulator_enable(pb->power_supply);
 48		if (err < 0)
 49			dev_err(pb->dev, "failed to enable power supply\n");
 50	}
 51
 52	if (pb->post_pwm_on_delay)
 53		msleep(pb->post_pwm_on_delay);
 54
 55	gpiod_set_value_cansleep(pb->enable_gpio, 1);
 56
 57	pb->enabled = true;
 58}
 59
 60static void pwm_backlight_power_off(struct pwm_bl_data *pb)
 61{
 62	if (!pb->enabled)
 63		return;
 64
 65	gpiod_set_value_cansleep(pb->enable_gpio, 0);
 66
 67	if (pb->pwm_off_delay)
 68		msleep(pb->pwm_off_delay);
 69
 70	if (pb->power_supply)
 71		regulator_disable(pb->power_supply);
 72	pb->enabled = false;
 73}
 74
 75static int compute_duty_cycle(struct pwm_bl_data *pb, int brightness, struct pwm_state *state)
 76{
 77	unsigned int lth = pb->lth_brightness;
 78	u64 duty_cycle;
 79
 80	if (pb->levels)
 81		duty_cycle = pb->levels[brightness];
 82	else
 83		duty_cycle = brightness;
 84
 85	duty_cycle *= state->period - lth;
 86	do_div(duty_cycle, pb->scale);
 87
 88	return duty_cycle + lth;
 89}
 90
 91static int pwm_backlight_update_status(struct backlight_device *bl)
 92{
 93	struct pwm_bl_data *pb = bl_get_data(bl);
 94	int brightness = backlight_get_brightness(bl);
 95	struct pwm_state state;
 96
 97	if (pb->notify)
 98		brightness = pb->notify(pb->dev, brightness);
 99
100	if (brightness > 0) {
101		pwm_get_state(pb->pwm, &state);
102		state.duty_cycle = compute_duty_cycle(pb, brightness, &state);
103		state.enabled = true;
104		pwm_apply_might_sleep(pb->pwm, &state);
105
106		pwm_backlight_power_on(pb);
107	} else {
108		pwm_backlight_power_off(pb);
109
110		pwm_get_state(pb->pwm, &state);
111		state.duty_cycle = 0;
112		/*
113		 * We cannot assume a disabled PWM to drive its output to the
114		 * inactive state. If we have an enable GPIO and/or a regulator
115		 * we assume that this isn't relevant and we can disable the PWM
116		 * to save power. If however there is neither an enable GPIO nor
117		 * a regulator keep the PWM on be sure to get a constant
118		 * inactive output.
119		 */
120		state.enabled = !pb->power_supply && !pb->enable_gpio;
121		pwm_apply_might_sleep(pb->pwm, &state);
122	}
123
124	if (pb->notify_after)
125		pb->notify_after(pb->dev, brightness);
126
127	return 0;
128}
129
130static const struct backlight_ops pwm_backlight_ops = {
131	.update_status	= pwm_backlight_update_status,
132};
133
134#ifdef CONFIG_OF
135#define PWM_LUMINANCE_SHIFT	16
136#define PWM_LUMINANCE_SCALE	(1 << PWM_LUMINANCE_SHIFT) /* luminance scale */
137
138/*
139 * CIE lightness to PWM conversion.
140 *
141 * The CIE 1931 lightness formula is what actually describes how we perceive
142 * light:
143 *          Y = (L* / 903.3)           if L* ≤ 8
144 *          Y = ((L* + 16) / 116)^3    if L* > 8
145 *
146 * Where Y is the luminance, the amount of light coming out of the screen, and
147 * is a number between 0.0 and 1.0; and L* is the lightness, how bright a human
148 * perceives the screen to be, and is a number between 0 and 100.
149 *
150 * The following function does the fixed point maths needed to implement the
151 * above formula.
152 */
153static u64 cie1931(unsigned int lightness)
154{
155	u64 retval;
156
157	/*
158	 * @lightness is given as a number between 0 and 1, expressed
159	 * as a fixed-point number in scale
160	 * PWM_LUMINANCE_SCALE. Convert to a percentage, still
161	 * expressed as a fixed-point number, so the above formulas
162	 * can be applied.
163	 */
164	lightness *= 100;
165	if (lightness <= (8 * PWM_LUMINANCE_SCALE)) {
166		retval = DIV_ROUND_CLOSEST(lightness * 10, 9033);
167	} else {
168		retval = (lightness + (16 * PWM_LUMINANCE_SCALE)) / 116;
169		retval *= retval * retval;
170		retval += 1ULL << (2*PWM_LUMINANCE_SHIFT - 1);
171		retval >>= 2*PWM_LUMINANCE_SHIFT;
172	}
173
174	return retval;
175}
176
177/*
178 * Create a default correction table for PWM values to create linear brightness
179 * for LED based backlights using the CIE1931 algorithm.
180 */
181static
182int pwm_backlight_brightness_default(struct device *dev,
183				     struct platform_pwm_backlight_data *data,
184				     unsigned int period)
185{
186	unsigned int i;
187	u64 retval;
188
189	/*
190	 * Once we have 4096 levels there's little point going much higher...
191	 * neither interactive sliders nor animation benefits from having
192	 * more values in the table.
193	 */
194	data->max_brightness =
195		min((int)DIV_ROUND_UP(period, fls(period)), 4096);
196
197	data->levels = devm_kcalloc(dev, data->max_brightness,
198				    sizeof(*data->levels), GFP_KERNEL);
199	if (!data->levels)
200		return -ENOMEM;
201
202	/* Fill the table using the cie1931 algorithm */
203	for (i = 0; i < data->max_brightness; i++) {
204		retval = cie1931((i * PWM_LUMINANCE_SCALE) /
205				 data->max_brightness) * period;
206		retval = DIV_ROUND_CLOSEST_ULL(retval, PWM_LUMINANCE_SCALE);
207		if (retval > UINT_MAX)
208			return -EINVAL;
209		data->levels[i] = (unsigned int)retval;
210	}
211
212	data->dft_brightness = data->max_brightness / 2;
213	data->max_brightness--;
214
215	return 0;
216}
217
218static int pwm_backlight_parse_dt(struct device *dev,
219				  struct platform_pwm_backlight_data *data)
220{
221	struct device_node *node = dev->of_node;
222	unsigned int num_levels;
223	unsigned int num_steps = 0;
224	struct property *prop;
225	unsigned int *table;
226	int length;
227	u32 value;
228	int ret;
229
230	if (!node)
231		return -ENODEV;
232
233	memset(data, 0, sizeof(*data));
234
235	/*
236	 * These values are optional and set as 0 by default, the out values
237	 * are modified only if a valid u32 value can be decoded.
238	 */
239	of_property_read_u32(node, "post-pwm-on-delay-ms",
240			     &data->post_pwm_on_delay);
241	of_property_read_u32(node, "pwm-off-delay-ms", &data->pwm_off_delay);
242
243	/*
244	 * Determine the number of brightness levels, if this property is not
245	 * set a default table of brightness levels will be used.
246	 */
247	prop = of_find_property(node, "brightness-levels", &length);
248	if (!prop)
249		return 0;
250
251	num_levels = length / sizeof(u32);
252
253	/* read brightness levels from DT property */
254	if (num_levels > 0) {
255		data->levels = devm_kcalloc(dev, num_levels,
256					    sizeof(*data->levels), GFP_KERNEL);
257		if (!data->levels)
258			return -ENOMEM;
259
260		ret = of_property_read_u32_array(node, "brightness-levels",
261						 data->levels,
262						 num_levels);
263		if (ret < 0)
264			return ret;
265
266		ret = of_property_read_u32(node, "default-brightness-level",
267					   &value);
268		if (ret < 0)
269			return ret;
270
271		data->dft_brightness = value;
272
273		/*
274		 * This property is optional, if is set enables linear
275		 * interpolation between each of the values of brightness levels
276		 * and creates a new pre-computed table.
277		 */
278		of_property_read_u32(node, "num-interpolated-steps",
279				     &num_steps);
280
281		/*
282		 * Make sure that there is at least two entries in the
283		 * brightness-levels table, otherwise we can't interpolate
284		 * between two points.
285		 */
286		if (num_steps) {
287			unsigned int num_input_levels = num_levels;
288			unsigned int i;
289			u32 x1, x2, x, dx;
290			u32 y1, y2;
291			s64 dy;
292
293			if (num_input_levels < 2) {
294				dev_err(dev, "can't interpolate\n");
295				return -EINVAL;
296			}
297
298			/*
299			 * Recalculate the number of brightness levels, now
300			 * taking in consideration the number of interpolated
301			 * steps between two levels.
302			 */
303			num_levels = (num_input_levels - 1) * num_steps + 1;
304			dev_dbg(dev, "new number of brightness levels: %d\n",
305				num_levels);
306
307			/*
308			 * Create a new table of brightness levels with all the
309			 * interpolated steps.
310			 */
311			table = devm_kcalloc(dev, num_levels, sizeof(*table),
312					     GFP_KERNEL);
313			if (!table)
314				return -ENOMEM;
315			/*
316			 * Fill the interpolated table[x] = y
317			 * by draw lines between each (x1, y1) to (x2, y2).
318			 */
319			dx = num_steps;
320			for (i = 0; i < num_input_levels - 1; i++) {
321				x1 = i * dx;
322				x2 = x1 + dx;
323				y1 = data->levels[i];
324				y2 = data->levels[i + 1];
325				dy = (s64)y2 - y1;
326
327				for (x = x1; x < x2; x++) {
328					table[x] = y1 +
329						div_s64(dy * (x - x1), dx);
330				}
331			}
332			/* Fill in the last point, since no line starts here. */
333			table[x2] = y2;
334
335			/*
336			 * As we use interpolation lets remove current
337			 * brightness levels table and replace for the
338			 * new interpolated table.
339			 */
340			devm_kfree(dev, data->levels);
341			data->levels = table;
342		}
343
344		data->max_brightness = num_levels - 1;
345	}
346
347	return 0;
348}
349
350static const struct of_device_id pwm_backlight_of_match[] = {
351	{ .compatible = "pwm-backlight" },
352	{ }
353};
354
355MODULE_DEVICE_TABLE(of, pwm_backlight_of_match);
356#else
357static int pwm_backlight_parse_dt(struct device *dev,
358				  struct platform_pwm_backlight_data *data)
359{
360	return -ENODEV;
361}
362
363static
364int pwm_backlight_brightness_default(struct device *dev,
365				     struct platform_pwm_backlight_data *data,
366				     unsigned int period)
367{
368	return -ENODEV;
369}
370#endif
371
372static bool pwm_backlight_is_linear(struct platform_pwm_backlight_data *data)
373{
374	unsigned int nlevels = data->max_brightness + 1;
375	unsigned int min_val = data->levels[0];
376	unsigned int max_val = data->levels[nlevels - 1];
377	/*
378	 * Multiplying by 128 means that even in pathological cases such
379	 * as (max_val - min_val) == nlevels the error at max_val is less
380	 * than 1%.
381	 */
382	unsigned int slope = (128 * (max_val - min_val)) / nlevels;
383	unsigned int margin = (max_val - min_val) / 20; /* 5% */
384	int i;
385
386	for (i = 1; i < nlevels; i++) {
387		unsigned int linear_value = min_val + ((i * slope) / 128);
388		unsigned int delta = abs(linear_value - data->levels[i]);
389
390		if (delta > margin)
391			return false;
392	}
393
394	return true;
395}
396
397static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
398{
399	struct device_node *node = pb->dev->of_node;
400	bool active = true;
401
402	/*
403	 * If the enable GPIO is present, observable (either as input
404	 * or output) and off then the backlight is not currently active.
405	 * */
406	if (pb->enable_gpio && gpiod_get_value_cansleep(pb->enable_gpio) == 0)
407		active = false;
408
409	if (pb->power_supply && !regulator_is_enabled(pb->power_supply))
410		active = false;
411
412	if (!pwm_is_enabled(pb->pwm))
413		active = false;
414
415	/*
416	 * Synchronize the enable_gpio with the observed state of the
417	 * hardware.
418	 */
419	gpiod_direction_output(pb->enable_gpio, active);
420
421	/*
422	 * Do not change pb->enabled here! pb->enabled essentially
423	 * tells us if we own one of the regulator's use counts and
424	 * right now we do not.
425	 */
426
427	/* Not booted with device tree or no phandle link to the node */
428	if (!node || !node->phandle)
429		return BACKLIGHT_POWER_ON;
430
431	/*
432	 * If the driver is probed from the device tree and there is a
433	 * phandle link pointing to the backlight node, it is safe to
434	 * assume that another driver will enable the backlight at the
435	 * appropriate time. Therefore, if it is disabled, keep it so.
436	 */
437	return active ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF;
438}
439
440static int pwm_backlight_probe(struct platform_device *pdev)
441{
442	struct platform_pwm_backlight_data *data = dev_get_platdata(&pdev->dev);
443	struct platform_pwm_backlight_data defdata;
444	struct backlight_properties props;
445	struct backlight_device *bl;
446	struct pwm_bl_data *pb;
447	struct pwm_state state;
448	unsigned int i;
449	int ret;
450
451	if (!data) {
452		ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
453		if (ret < 0)
454			return dev_err_probe(&pdev->dev, ret,
455					     "failed to find platform data\n");
456
457		data = &defdata;
458	}
459
460	if (data->init) {
461		ret = data->init(&pdev->dev);
462		if (ret < 0)
463			return ret;
464	}
465
466	pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
467	if (!pb) {
468		ret = -ENOMEM;
469		goto err_alloc;
470	}
471
472	pb->notify = data->notify;
473	pb->notify_after = data->notify_after;
474	pb->exit = data->exit;
475	pb->dev = &pdev->dev;
476	pb->enabled = false;
477	pb->post_pwm_on_delay = data->post_pwm_on_delay;
478	pb->pwm_off_delay = data->pwm_off_delay;
479
480	pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
481						  GPIOD_ASIS);
482	if (IS_ERR(pb->enable_gpio)) {
483		ret = dev_err_probe(&pdev->dev, PTR_ERR(pb->enable_gpio),
484				    "failed to acquire enable GPIO\n");
485		goto err_alloc;
486	}
487
488	pb->power_supply = devm_regulator_get_optional(&pdev->dev, "power");
489	if (IS_ERR(pb->power_supply)) {
490		ret = PTR_ERR(pb->power_supply);
491		if (ret == -ENODEV) {
492			pb->power_supply = NULL;
493		} else {
494			dev_err_probe(&pdev->dev, ret,
495				      "failed to acquire power regulator\n");
496			goto err_alloc;
497		}
498	}
499
500	pb->pwm = devm_pwm_get(&pdev->dev, NULL);
501	if (IS_ERR(pb->pwm)) {
502		ret = dev_err_probe(&pdev->dev, PTR_ERR(pb->pwm),
503				    "unable to request PWM\n");
504		goto err_alloc;
505	}
506
507	dev_dbg(&pdev->dev, "got pwm for backlight\n");
508
509	/* Sync up PWM state. */
510	pwm_init_state(pb->pwm, &state);
511
512	/*
513	 * The DT case will set the pwm_period_ns field to 0 and store the
514	 * period, parsed from the DT, in the PWM device. For the non-DT case,
515	 * set the period from platform data if it has not already been set
516	 * via the PWM lookup table.
517	 */
518	if (!state.period && (data->pwm_period_ns > 0))
519		state.period = data->pwm_period_ns;
520
521	ret = pwm_apply_might_sleep(pb->pwm, &state);
522	if (ret) {
523		dev_err_probe(&pdev->dev, ret,
524			      "failed to apply initial PWM state");
525		goto err_alloc;
526	}
527
528	memset(&props, 0, sizeof(struct backlight_properties));
529
530	if (data->levels) {
531		pb->levels = data->levels;
532
533		/*
534		 * For the DT case, only when brightness levels is defined
535		 * data->levels is filled. For the non-DT case, data->levels
536		 * can come from platform data, however is not usual.
537		 */
538		for (i = 0; i <= data->max_brightness; i++)
539			if (data->levels[i] > pb->scale)
540				pb->scale = data->levels[i];
541
542		if (pwm_backlight_is_linear(data))
543			props.scale = BACKLIGHT_SCALE_LINEAR;
544		else
545			props.scale = BACKLIGHT_SCALE_NON_LINEAR;
546	} else if (!data->max_brightness) {
547		/*
548		 * If no brightness levels are provided and max_brightness is
549		 * not set, use the default brightness table. For the DT case,
550		 * max_brightness is set to 0 when brightness levels is not
551		 * specified. For the non-DT case, max_brightness is usually
552		 * set to some value.
553		 */
554
555		/* Get the PWM period (in nanoseconds) */
556		pwm_get_state(pb->pwm, &state);
557
558		ret = pwm_backlight_brightness_default(&pdev->dev, data,
559						       state.period);
560		if (ret < 0) {
561			dev_err_probe(&pdev->dev, ret,
562				      "failed to setup default brightness table\n");
563			goto err_alloc;
564		}
565
566		for (i = 0; i <= data->max_brightness; i++) {
567			if (data->levels[i] > pb->scale)
568				pb->scale = data->levels[i];
569
570			pb->levels = data->levels;
571		}
572
573		props.scale = BACKLIGHT_SCALE_NON_LINEAR;
574	} else {
575		/*
576		 * That only happens for the non-DT case, where platform data
577		 * sets the max_brightness value.
578		 */
579		pb->scale = data->max_brightness;
580	}
581
582	pb->lth_brightness = data->lth_brightness * (div_u64(state.period,
583				pb->scale));
584
585	props.type = BACKLIGHT_RAW;
586	props.max_brightness = data->max_brightness;
587	bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
588				       &pwm_backlight_ops, &props);
589	if (IS_ERR(bl)) {
590		ret = dev_err_probe(&pdev->dev, PTR_ERR(bl),
591				    "failed to register backlight\n");
592		goto err_alloc;
593	}
594
595	if (data->dft_brightness > data->max_brightness) {
596		dev_warn(&pdev->dev,
597			 "invalid default brightness level: %u, using %u\n",
598			 data->dft_brightness, data->max_brightness);
599		data->dft_brightness = data->max_brightness;
600	}
601
602	bl->props.brightness = data->dft_brightness;
603	bl->props.power = pwm_backlight_initial_power_state(pb);
604	backlight_update_status(bl);
605
606	platform_set_drvdata(pdev, bl);
607	return 0;
608
609err_alloc:
610	if (data->exit)
611		data->exit(&pdev->dev);
612	return ret;
613}
614
615static void pwm_backlight_remove(struct platform_device *pdev)
616{
617	struct backlight_device *bl = platform_get_drvdata(pdev);
618	struct pwm_bl_data *pb = bl_get_data(bl);
619	struct pwm_state state;
620
621	backlight_device_unregister(bl);
622	pwm_backlight_power_off(pb);
623	pwm_get_state(pb->pwm, &state);
624	state.duty_cycle = 0;
625	state.enabled = false;
626	pwm_apply_might_sleep(pb->pwm, &state);
627
628	if (pb->exit)
629		pb->exit(&pdev->dev);
630}
631
632static void pwm_backlight_shutdown(struct platform_device *pdev)
633{
634	struct backlight_device *bl = platform_get_drvdata(pdev);
635	struct pwm_bl_data *pb = bl_get_data(bl);
636	struct pwm_state state;
637
638	pwm_backlight_power_off(pb);
639	pwm_get_state(pb->pwm, &state);
640	state.duty_cycle = 0;
641	state.enabled = false;
642	pwm_apply_might_sleep(pb->pwm, &state);
643}
644
645#ifdef CONFIG_PM_SLEEP
646static int pwm_backlight_suspend(struct device *dev)
647{
648	struct backlight_device *bl = dev_get_drvdata(dev);
649	struct pwm_bl_data *pb = bl_get_data(bl);
650	struct pwm_state state;
651
652	if (pb->notify)
653		pb->notify(pb->dev, 0);
654
655	pwm_backlight_power_off(pb);
656
657	/*
658	 * Note that disabling the PWM doesn't guarantee that the output stays
659	 * at its inactive state. However without the PWM disabled, the PWM
660	 * driver refuses to suspend. So disable here even though this might
661	 * enable the backlight on poorly designed boards.
662	 */
663	pwm_get_state(pb->pwm, &state);
664	state.duty_cycle = 0;
665	state.enabled = false;
666	pwm_apply_might_sleep(pb->pwm, &state);
667
668	if (pb->notify_after)
669		pb->notify_after(pb->dev, 0);
670
671	return 0;
672}
673
674static int pwm_backlight_resume(struct device *dev)
675{
676	struct backlight_device *bl = dev_get_drvdata(dev);
677
678	backlight_update_status(bl);
679
680	return 0;
681}
682#endif
683
684static const struct dev_pm_ops pwm_backlight_pm_ops = {
685#ifdef CONFIG_PM_SLEEP
686	.suspend = pwm_backlight_suspend,
687	.resume = pwm_backlight_resume,
688	.poweroff = pwm_backlight_suspend,
689	.restore = pwm_backlight_resume,
690#endif
691};
692
693static struct platform_driver pwm_backlight_driver = {
694	.driver		= {
695		.name		= "pwm-backlight",
696		.pm		= &pwm_backlight_pm_ops,
697		.of_match_table	= of_match_ptr(pwm_backlight_of_match),
698	},
699	.probe		= pwm_backlight_probe,
700	.remove		= pwm_backlight_remove,
701	.shutdown	= pwm_backlight_shutdown,
702};
703
704module_platform_driver(pwm_backlight_driver);
705
706MODULE_DESCRIPTION("PWM based Backlight Driver");
707MODULE_LICENSE("GPL v2");
708MODULE_ALIAS("platform:pwm-backlight");
~/ Read-only file preview.