15317f37eSLinus Walleij // SPDX-License-Identifier: GPL-2.0-only 25317f37eSLinus Walleij /* 35317f37eSLinus Walleij * Backlight driver for the Kinetic KTD253 45317f37eSLinus Walleij * Based on code and know-how from the Samsung GT-S7710 55317f37eSLinus Walleij * Gareth Phillips <gareth.phillips@samsung.com> 65317f37eSLinus Walleij */ 75317f37eSLinus Walleij #include <linux/backlight.h> 85317f37eSLinus Walleij #include <linux/delay.h> 95317f37eSLinus Walleij #include <linux/err.h> 105317f37eSLinus Walleij #include <linux/fb.h> 115317f37eSLinus Walleij #include <linux/gpio/consumer.h> 125317f37eSLinus Walleij #include <linux/init.h> 135317f37eSLinus Walleij #include <linux/kernel.h> 145317f37eSLinus Walleij #include <linux/limits.h> 155317f37eSLinus Walleij #include <linux/module.h> 165317f37eSLinus Walleij #include <linux/of.h> 175317f37eSLinus Walleij #include <linux/platform_device.h> 185317f37eSLinus Walleij #include <linux/property.h> 195317f37eSLinus Walleij #include <linux/slab.h> 205317f37eSLinus Walleij 215317f37eSLinus Walleij /* Current ratio is n/32 from 1/32 to 32/32 */ 225317f37eSLinus Walleij #define KTD253_MIN_RATIO 1 235317f37eSLinus Walleij #define KTD253_MAX_RATIO 32 245317f37eSLinus Walleij #define KTD253_DEFAULT_RATIO 13 255317f37eSLinus Walleij 265317f37eSLinus Walleij #define KTD253_T_LOW_NS (200 + 10) /* Additional 10ns as safety factor */ 275317f37eSLinus Walleij #define KTD253_T_HIGH_NS (200 + 10) /* Additional 10ns as safety factor */ 28*daa37361SLinus Walleij #define KTD253_T_OFF_CRIT_NS 100000 /* 100 us, now it doesn't look good */ 295317f37eSLinus Walleij #define KTD253_T_OFF_MS 3 305317f37eSLinus Walleij 315317f37eSLinus Walleij struct ktd253_backlight { 325317f37eSLinus Walleij struct device *dev; 335317f37eSLinus Walleij struct backlight_device *bl; 345317f37eSLinus Walleij struct gpio_desc *gpiod; 355317f37eSLinus Walleij u16 ratio; 365317f37eSLinus Walleij }; 375317f37eSLinus Walleij 38*daa37361SLinus Walleij static void ktd253_backlight_set_max_ratio(struct ktd253_backlight *ktd253) 39*daa37361SLinus Walleij { 40*daa37361SLinus Walleij gpiod_set_value_cansleep(ktd253->gpiod, 1); 41*daa37361SLinus Walleij ndelay(KTD253_T_HIGH_NS); 42*daa37361SLinus Walleij /* We always fall back to this when we power on */ 43*daa37361SLinus Walleij } 44*daa37361SLinus Walleij 45*daa37361SLinus Walleij static int ktd253_backlight_stepdown(struct ktd253_backlight *ktd253) 46*daa37361SLinus Walleij { 47*daa37361SLinus Walleij /* 48*daa37361SLinus Walleij * These GPIO operations absolutely can NOT sleep so no _cansleep 49*daa37361SLinus Walleij * suffixes, and no using GPIO expanders on slow buses for this! 50*daa37361SLinus Walleij * 51*daa37361SLinus Walleij * The maximum number of cycles of the loop is 32 so the time taken 52*daa37361SLinus Walleij * should nominally be: 53*daa37361SLinus Walleij * (T_LOW_NS + T_HIGH_NS + loop_time) * 32 54*daa37361SLinus Walleij * 55*daa37361SLinus Walleij * Architectures do not always support ndelay() and we will get a few us 56*daa37361SLinus Walleij * instead. If we get to a critical time limit an interrupt has likely 57*daa37361SLinus Walleij * occured in the low part of the loop and we need to restart from the 58*daa37361SLinus Walleij * top so we have the backlight in a known state. 59*daa37361SLinus Walleij */ 60*daa37361SLinus Walleij u64 ns; 61*daa37361SLinus Walleij 62*daa37361SLinus Walleij ns = ktime_get_ns(); 63*daa37361SLinus Walleij gpiod_set_value(ktd253->gpiod, 0); 64*daa37361SLinus Walleij ndelay(KTD253_T_LOW_NS); 65*daa37361SLinus Walleij gpiod_set_value(ktd253->gpiod, 1); 66*daa37361SLinus Walleij ns = ktime_get_ns() - ns; 67*daa37361SLinus Walleij if (ns >= KTD253_T_OFF_CRIT_NS) { 68*daa37361SLinus Walleij dev_err(ktd253->dev, "PCM on backlight took too long (%llu ns)\n", ns); 69*daa37361SLinus Walleij return -EAGAIN; 70*daa37361SLinus Walleij } 71*daa37361SLinus Walleij ndelay(KTD253_T_HIGH_NS); 72*daa37361SLinus Walleij return 0; 73*daa37361SLinus Walleij } 74*daa37361SLinus Walleij 755317f37eSLinus Walleij static int ktd253_backlight_update_status(struct backlight_device *bl) 765317f37eSLinus Walleij { 775317f37eSLinus Walleij struct ktd253_backlight *ktd253 = bl_get_data(bl); 785317f37eSLinus Walleij int brightness = backlight_get_brightness(bl); 795317f37eSLinus Walleij u16 target_ratio; 805317f37eSLinus Walleij u16 current_ratio = ktd253->ratio; 81*daa37361SLinus Walleij int ret; 825317f37eSLinus Walleij 835317f37eSLinus Walleij dev_dbg(ktd253->dev, "new brightness/ratio: %d/32\n", brightness); 845317f37eSLinus Walleij 855317f37eSLinus Walleij target_ratio = brightness; 865317f37eSLinus Walleij 875317f37eSLinus Walleij if (target_ratio == current_ratio) 885317f37eSLinus Walleij /* This is already right */ 895317f37eSLinus Walleij return 0; 905317f37eSLinus Walleij 915317f37eSLinus Walleij if (target_ratio == 0) { 925317f37eSLinus Walleij gpiod_set_value_cansleep(ktd253->gpiod, 0); 935317f37eSLinus Walleij /* 945317f37eSLinus Walleij * We need to keep the GPIO low for at least this long 955317f37eSLinus Walleij * to actually switch the KTD253 off. 965317f37eSLinus Walleij */ 975317f37eSLinus Walleij msleep(KTD253_T_OFF_MS); 985317f37eSLinus Walleij ktd253->ratio = 0; 995317f37eSLinus Walleij return 0; 1005317f37eSLinus Walleij } 1015317f37eSLinus Walleij 1025317f37eSLinus Walleij if (current_ratio == 0) { 103*daa37361SLinus Walleij ktd253_backlight_set_max_ratio(ktd253); 1045317f37eSLinus Walleij current_ratio = KTD253_MAX_RATIO; 1055317f37eSLinus Walleij } 1065317f37eSLinus Walleij 1075317f37eSLinus Walleij while (current_ratio != target_ratio) { 1085317f37eSLinus Walleij /* 1095317f37eSLinus Walleij * These GPIO operations absolutely can NOT sleep so no 1105317f37eSLinus Walleij * _cansleep suffixes, and no using GPIO expanders on 1115317f37eSLinus Walleij * slow buses for this! 1125317f37eSLinus Walleij */ 113*daa37361SLinus Walleij ret = ktd253_backlight_stepdown(ktd253); 114*daa37361SLinus Walleij if (ret == -EAGAIN) { 115*daa37361SLinus Walleij /* 116*daa37361SLinus Walleij * Something disturbed the backlight setting code when 117*daa37361SLinus Walleij * running so we need to bring the PWM back to a known 118*daa37361SLinus Walleij * state. This shouldn't happen too much. 119*daa37361SLinus Walleij */ 120*daa37361SLinus Walleij gpiod_set_value_cansleep(ktd253->gpiod, 0); 121*daa37361SLinus Walleij msleep(KTD253_T_OFF_MS); 122*daa37361SLinus Walleij ktd253_backlight_set_max_ratio(ktd253); 1235317f37eSLinus Walleij current_ratio = KTD253_MAX_RATIO; 124*daa37361SLinus Walleij } else if (current_ratio == KTD253_MIN_RATIO) { 125*daa37361SLinus Walleij /* After 1/32 we loop back to 32/32 */ 126*daa37361SLinus Walleij current_ratio = KTD253_MAX_RATIO; 127*daa37361SLinus Walleij } else { 1285317f37eSLinus Walleij current_ratio--; 1295317f37eSLinus Walleij } 130*daa37361SLinus Walleij } 1315317f37eSLinus Walleij ktd253->ratio = current_ratio; 1325317f37eSLinus Walleij 1335317f37eSLinus Walleij dev_dbg(ktd253->dev, "new ratio set to %d/32\n", target_ratio); 1345317f37eSLinus Walleij 1355317f37eSLinus Walleij return 0; 1365317f37eSLinus Walleij } 1375317f37eSLinus Walleij 1385317f37eSLinus Walleij static const struct backlight_ops ktd253_backlight_ops = { 1395317f37eSLinus Walleij .options = BL_CORE_SUSPENDRESUME, 1405317f37eSLinus Walleij .update_status = ktd253_backlight_update_status, 1415317f37eSLinus Walleij }; 1425317f37eSLinus Walleij 1435317f37eSLinus Walleij static int ktd253_backlight_probe(struct platform_device *pdev) 1445317f37eSLinus Walleij { 1455317f37eSLinus Walleij struct device *dev = &pdev->dev; 1465317f37eSLinus Walleij struct backlight_device *bl; 1475317f37eSLinus Walleij struct ktd253_backlight *ktd253; 1485317f37eSLinus Walleij u32 max_brightness; 1495317f37eSLinus Walleij u32 brightness; 1505317f37eSLinus Walleij int ret; 1515317f37eSLinus Walleij 1525317f37eSLinus Walleij ktd253 = devm_kzalloc(dev, sizeof(*ktd253), GFP_KERNEL); 1535317f37eSLinus Walleij if (!ktd253) 1545317f37eSLinus Walleij return -ENOMEM; 1555317f37eSLinus Walleij ktd253->dev = dev; 1565317f37eSLinus Walleij 1575317f37eSLinus Walleij ret = device_property_read_u32(dev, "max-brightness", &max_brightness); 1585317f37eSLinus Walleij if (ret) 1595317f37eSLinus Walleij max_brightness = KTD253_MAX_RATIO; 1605317f37eSLinus Walleij if (max_brightness > KTD253_MAX_RATIO) { 1615317f37eSLinus Walleij /* Clamp brightness to hardware max */ 1625317f37eSLinus Walleij dev_err(dev, "illegal max brightness specified\n"); 1635317f37eSLinus Walleij max_brightness = KTD253_MAX_RATIO; 1645317f37eSLinus Walleij } 1655317f37eSLinus Walleij 1665317f37eSLinus Walleij ret = device_property_read_u32(dev, "default-brightness", &brightness); 1675317f37eSLinus Walleij if (ret) 1685317f37eSLinus Walleij brightness = KTD253_DEFAULT_RATIO; 1695317f37eSLinus Walleij if (brightness > max_brightness) { 1705317f37eSLinus Walleij /* Clamp default brightness to max brightness */ 1715317f37eSLinus Walleij dev_err(dev, "default brightness exceeds max brightness\n"); 1725317f37eSLinus Walleij brightness = max_brightness; 1735317f37eSLinus Walleij } 1745317f37eSLinus Walleij 17557e0d7b7SLinus Walleij ktd253->gpiod = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 1765317f37eSLinus Walleij if (IS_ERR(ktd253->gpiod)) { 1775317f37eSLinus Walleij ret = PTR_ERR(ktd253->gpiod); 1785317f37eSLinus Walleij if (ret != -EPROBE_DEFER) 1795317f37eSLinus Walleij dev_err(dev, "gpio line missing or invalid.\n"); 1805317f37eSLinus Walleij return ret; 1815317f37eSLinus Walleij } 1825317f37eSLinus Walleij gpiod_set_consumer_name(ktd253->gpiod, dev_name(dev)); 18357e0d7b7SLinus Walleij /* Bring backlight to a known off state */ 18457e0d7b7SLinus Walleij msleep(KTD253_T_OFF_MS); 1855317f37eSLinus Walleij 1865317f37eSLinus Walleij bl = devm_backlight_device_register(dev, dev_name(dev), dev, ktd253, 1875317f37eSLinus Walleij &ktd253_backlight_ops, NULL); 1885317f37eSLinus Walleij if (IS_ERR(bl)) { 1895317f37eSLinus Walleij dev_err(dev, "failed to register backlight\n"); 1905317f37eSLinus Walleij return PTR_ERR(bl); 1915317f37eSLinus Walleij } 1925317f37eSLinus Walleij bl->props.max_brightness = max_brightness; 1935317f37eSLinus Walleij /* When we just enable the GPIO line we set max brightness */ 1945317f37eSLinus Walleij if (brightness) { 1955317f37eSLinus Walleij bl->props.brightness = brightness; 1965317f37eSLinus Walleij bl->props.power = FB_BLANK_UNBLANK; 1975317f37eSLinus Walleij } else { 1985317f37eSLinus Walleij bl->props.brightness = 0; 1995317f37eSLinus Walleij bl->props.power = FB_BLANK_POWERDOWN; 2005317f37eSLinus Walleij } 2015317f37eSLinus Walleij 2025317f37eSLinus Walleij ktd253->bl = bl; 2035317f37eSLinus Walleij platform_set_drvdata(pdev, bl); 2045317f37eSLinus Walleij backlight_update_status(bl); 2055317f37eSLinus Walleij 2065317f37eSLinus Walleij return 0; 2075317f37eSLinus Walleij } 2085317f37eSLinus Walleij 2095317f37eSLinus Walleij static const struct of_device_id ktd253_backlight_of_match[] = { 2105317f37eSLinus Walleij { .compatible = "kinetic,ktd253" }, 211693091d9SLinus Walleij { .compatible = "kinetic,ktd259" }, 2125317f37eSLinus Walleij { /* sentinel */ } 2135317f37eSLinus Walleij }; 2145317f37eSLinus Walleij MODULE_DEVICE_TABLE(of, ktd253_backlight_of_match); 2155317f37eSLinus Walleij 2165317f37eSLinus Walleij static struct platform_driver ktd253_backlight_driver = { 2175317f37eSLinus Walleij .driver = { 2185317f37eSLinus Walleij .name = "ktd253-backlight", 2195317f37eSLinus Walleij .of_match_table = ktd253_backlight_of_match, 2205317f37eSLinus Walleij }, 2215317f37eSLinus Walleij .probe = ktd253_backlight_probe, 2225317f37eSLinus Walleij }; 2235317f37eSLinus Walleij module_platform_driver(ktd253_backlight_driver); 2245317f37eSLinus Walleij 2255317f37eSLinus Walleij MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); 2265317f37eSLinus Walleij MODULE_DESCRIPTION("Kinetic KTD253 Backlight Driver"); 2275317f37eSLinus Walleij MODULE_LICENSE("GPL"); 2285317f37eSLinus Walleij MODULE_ALIAS("platform:ktd253-backlight"); 229