brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 327b4ee Raw
225 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Backlight driver for the Kinetic KTD2534 * Based on code and know-how from the Samsung GT-S77105 * Gareth Phillips <gareth.phillips@samsung.com>6 */7#include <linux/backlight.h>8#include <linux/delay.h>9#include <linux/err.h>10#include <linux/gpio/consumer.h>11#include <linux/init.h>12#include <linux/kernel.h>13#include <linux/limits.h>14#include <linux/module.h>15#include <linux/of.h>16#include <linux/platform_device.h>17#include <linux/property.h>18#include <linux/slab.h>19 20/* Current ratio is n/32 from 1/32 to 32/32 */21#define KTD253_MIN_RATIO 122#define KTD253_MAX_RATIO 3223#define KTD253_DEFAULT_RATIO 1324 25#define KTD253_T_LOW_NS (200 + 10) /* Additional 10ns as safety factor */26#define KTD253_T_HIGH_NS (200 + 10) /* Additional 10ns as safety factor */27#define KTD253_T_OFF_CRIT_NS 100000 /* 100 us, now it doesn't look good */28#define KTD253_T_OFF_MS 329 30struct ktd253_backlight {31	struct device *dev;32	struct backlight_device *bl;33	struct gpio_desc *gpiod;34	u16 ratio;35};36 37static void ktd253_backlight_set_max_ratio(struct ktd253_backlight *ktd253)38{39	gpiod_set_value_cansleep(ktd253->gpiod, 1);40	ndelay(KTD253_T_HIGH_NS);41	/* We always fall back to this when we power on */42}43 44static int ktd253_backlight_stepdown(struct ktd253_backlight *ktd253)45{46	/*47	 * These GPIO operations absolutely can NOT sleep so no _cansleep48	 * suffixes, and no using GPIO expanders on slow buses for this!49	 *50	 * The maximum number of cycles of the loop is 32  so the time taken51	 * should nominally be:52	 * (T_LOW_NS + T_HIGH_NS + loop_time) * 3253	 *54	 * Architectures do not always support ndelay() and we will get a few us55	 * instead. If we get to a critical time limit an interrupt has likely56	 * occured in the low part of the loop and we need to restart from the57	 * top so we have the backlight in a known state.58	 */59	u64 ns;60 61	ns = ktime_get_ns();62	gpiod_set_value(ktd253->gpiod, 0);63	ndelay(KTD253_T_LOW_NS);64	gpiod_set_value(ktd253->gpiod, 1);65	ns = ktime_get_ns() - ns;66	if (ns >= KTD253_T_OFF_CRIT_NS) {67		dev_err(ktd253->dev, "PCM on backlight took too long (%llu ns)\n", ns);68		return -EAGAIN;69	}70	ndelay(KTD253_T_HIGH_NS);71	return 0;72}73 74static int ktd253_backlight_update_status(struct backlight_device *bl)75{76	struct ktd253_backlight *ktd253 = bl_get_data(bl);77	int brightness = backlight_get_brightness(bl);78	u16 target_ratio;79	u16 current_ratio = ktd253->ratio;80	int ret;81 82	dev_dbg(ktd253->dev, "new brightness/ratio: %d/32\n", brightness);83 84	target_ratio = brightness;85 86	if (target_ratio == current_ratio)87		/* This is already right */88		return 0;89 90	if (target_ratio == 0) {91		gpiod_set_value_cansleep(ktd253->gpiod, 0);92		/*93		 * We need to keep the GPIO low for at least this long94		 * to actually switch the KTD253 off.95		 */96		msleep(KTD253_T_OFF_MS);97		ktd253->ratio = 0;98		return 0;99	}100 101	if (current_ratio == 0) {102		ktd253_backlight_set_max_ratio(ktd253);103		current_ratio = KTD253_MAX_RATIO;104	}105 106	while (current_ratio != target_ratio) {107		/*108		 * These GPIO operations absolutely can NOT sleep so no109		 * _cansleep suffixes, and no using GPIO expanders on110		 * slow buses for this!111		 */112		ret = ktd253_backlight_stepdown(ktd253);113		if (ret == -EAGAIN) {114			/*115			 * Something disturbed the backlight setting code when116			 * running so we need to bring the PWM back to a known117			 * state. This shouldn't happen too much.118			 */119			gpiod_set_value_cansleep(ktd253->gpiod, 0);120			msleep(KTD253_T_OFF_MS);121			ktd253_backlight_set_max_ratio(ktd253);122			current_ratio = KTD253_MAX_RATIO;123		} else if (current_ratio == KTD253_MIN_RATIO) {124			/* After 1/32 we loop back to 32/32 */125			current_ratio = KTD253_MAX_RATIO;126		} else {127			current_ratio--;128		}129	}130	ktd253->ratio = current_ratio;131 132	dev_dbg(ktd253->dev, "new ratio set to %d/32\n", target_ratio);133 134	return 0;135}136 137static const struct backlight_ops ktd253_backlight_ops = {138	.options	= BL_CORE_SUSPENDRESUME,139	.update_status	= ktd253_backlight_update_status,140};141 142static int ktd253_backlight_probe(struct platform_device *pdev)143{144	struct device *dev = &pdev->dev;145	struct backlight_device *bl;146	struct ktd253_backlight *ktd253;147	u32 max_brightness;148	u32 brightness;149	int ret;150 151	ktd253 = devm_kzalloc(dev, sizeof(*ktd253), GFP_KERNEL);152	if (!ktd253)153		return -ENOMEM;154	ktd253->dev = dev;155 156	ret = device_property_read_u32(dev, "max-brightness", &max_brightness);157	if (ret)158		max_brightness = KTD253_MAX_RATIO;159	if (max_brightness > KTD253_MAX_RATIO) {160		/* Clamp brightness to hardware max */161		dev_err(dev, "illegal max brightness specified\n");162		max_brightness = KTD253_MAX_RATIO;163	}164 165	ret = device_property_read_u32(dev, "default-brightness", &brightness);166	if (ret)167		brightness = KTD253_DEFAULT_RATIO;168	if (brightness > max_brightness) {169		/* Clamp default brightness to max brightness */170		dev_err(dev, "default brightness exceeds max brightness\n");171		brightness = max_brightness;172	}173 174	ktd253->gpiod = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);175	if (IS_ERR(ktd253->gpiod))176		return dev_err_probe(dev, PTR_ERR(ktd253->gpiod),177				     "gpio line missing or invalid.\n");178	gpiod_set_consumer_name(ktd253->gpiod, dev_name(dev));179	/* Bring backlight to a known off state */180	msleep(KTD253_T_OFF_MS);181 182	bl = devm_backlight_device_register(dev, dev_name(dev), dev, ktd253,183					    &ktd253_backlight_ops, NULL);184	if (IS_ERR(bl)) {185		dev_err(dev, "failed to register backlight\n");186		return PTR_ERR(bl);187	}188	bl->props.max_brightness = max_brightness;189	/* When we just enable the GPIO line we set max brightness */190	if (brightness) {191		bl->props.brightness = brightness;192		bl->props.power = BACKLIGHT_POWER_ON;193	} else {194		bl->props.brightness = 0;195		bl->props.power = BACKLIGHT_POWER_OFF;196	}197 198	ktd253->bl = bl;199	platform_set_drvdata(pdev, bl);200	backlight_update_status(bl);201 202	return 0;203}204 205static const struct of_device_id ktd253_backlight_of_match[] = {206	{ .compatible = "kinetic,ktd253" },207	{ .compatible = "kinetic,ktd259" },208	{ /* sentinel */ }209};210MODULE_DEVICE_TABLE(of, ktd253_backlight_of_match);211 212static struct platform_driver ktd253_backlight_driver = {213	.driver = {214		.name = "ktd253-backlight",215		.of_match_table = ktd253_backlight_of_match,216	},217	.probe		= ktd253_backlight_probe,218};219module_platform_driver(ktd253_backlight_driver);220 221MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");222MODULE_DESCRIPTION("Kinetic KTD253 Backlight Driver");223MODULE_LICENSE("GPL");224MODULE_ALIAS("platform:ktd253-backlight");225