brintos

brintos / linux-shallow public Read only

0
0
Text · 18.0 KiB · e942908 Raw
709 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Simple PWM based backlight control, board code has to setup4 * 1) pin configuration so PWM waveforms can output5 * 2) platform_data being correctly configured6 */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	else83		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 the114		 * inactive state. If we have an enable GPIO and/or a regulator115		 * we assume that this isn't relevant and we can disable the PWM116		 * to save power. If however there is neither an enable GPIO nor117		 * a regulator keep the PWM on be sure to get a constant118		 * 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_OF135#define PWM_LUMINANCE_SHIFT	16136#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 perceive142 * light:143 *          Y = (L* / 903.3)           if L* ≤ 8144 *          Y = ((L* + 16) / 116)^3    if L* > 8145 *146 * Where Y is the luminance, the amount of light coming out of the screen, and147 * is a number between 0.0 and 1.0; and L* is the lightness, how bright a human148 * 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 the151 * 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, expressed159	 * as a fixed-point number in scale160	 * PWM_LUMINANCE_SCALE. Convert to a percentage, still161	 * expressed as a fixed-point number, so the above formulas162	 * 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 brightness179 * for LED based backlights using the CIE1931 algorithm.180 */181static182int 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 having192	 * 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 values237	 * 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 not245	 * 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 linear275		 * interpolation between each of the values of brightness levels276		 * 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 the283		 * brightness-levels table, otherwise we can't interpolate284		 * 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, now300			 * taking in consideration the number of interpolated301			 * 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 the309			 * 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] = y317			 * 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 current337			 * brightness levels table and replace for the338			 * 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#else357static int pwm_backlight_parse_dt(struct device *dev,358				  struct platform_pwm_backlight_data *data)359{360	return -ENODEV;361}362 363static364int pwm_backlight_brightness_default(struct device *dev,365				     struct platform_pwm_backlight_data *data,366				     unsigned int period)367{368	return -ENODEV;369}370#endif371 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 such379	 * as (max_val - min_val) == nlevels the error at max_val is less380	 * 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 input404	 * 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 the417	 * hardware.418	 */419	gpiod_direction_output(pb->enable_gpio, active);420 421	/*422	 * Do not change pb->enabled here! pb->enabled essentially423	 * tells us if we own one of the regulator's use counts and424	 * 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 a433	 * phandle link pointing to the backlight node, it is safe to434	 * assume that another driver will enable the backlight at the435	 * 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 the514	 * 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 set516	 * 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 defined535		 * data->levels is filled. For the non-DT case, data->levels536		 * 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		else545			props.scale = BACKLIGHT_SCALE_NON_LINEAR;546	} else if (!data->max_brightness) {547		/*548		 * If no brightness levels are provided and max_brightness is549		 * not set, use the default brightness table. For the DT case,550		 * max_brightness is set to 0 when brightness levels is not551		 * specified. For the non-DT case, max_brightness is usually552		 * 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 data577		 * 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_SLEEP646static 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 stays659	 * at its inactive state. However without the PWM disabled, the PWM660	 * driver refuses to suspend. So disable here even though this might661	 * 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#endif683 684static const struct dev_pm_ops pwm_backlight_pm_ops = {685#ifdef CONFIG_PM_SLEEP686	.suspend = pwm_backlight_suspend,687	.resume = pwm_backlight_resume,688	.poweroff = pwm_backlight_suspend,689	.restore = pwm_backlight_resume,690#endif691};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_new	= 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");709