- Fix-ups
- Improve bootloader/kernel device handover - Bug Fixes - Stabilise backlight -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAmE3brsACgkQUa+KL4f8 d2Fpvg//WqnzzpoAhhJpsqOvThvptAFinlVH9ql7gsivCBXsY8Fu0RsynlEy3E4o DZzhBT/gE1UPkv2HbntuCikZdza1vcyIZrYkUnGb9yAokd0apX2Iss6K50Z7H3U1 Bvot6MgG9VdgbPD3gcIPO/SEyODl6YhDByUU7kWDgmmi2IM/chcd1+SMK0GtAgfb NYcgLPi5nZ8j2zhfhA19H9tdr01Kz0dhBEjfVxDfC2l9bhAl1E7Uj96Ugz9b5oSk /J5yhogfFhNuK0kfw1bQ0IUNpDxtg9hh8Q8uk45AX+6w9XyQ3/hkoNhTWbiEpawz IZaFI7mTBYmtdwJkcbZ3dP5n4zYSzXloayCHRfbwqUfn6n62EwhGgKOpEkSjbgMD 825WWjvjUctgjJSOJuWcJftJvf8s+xViycwSP4sbssbCC22QT019dcpsAaHS471Z wJJoOxYAMylVIFfG2NOZGkDpVdlYfTGef1RoBrrwWibZPcUOQYi6UNBxxJNlzxHN B3xE6r19M91ER9y7qKJ7TD2v5P3hfyFaweetoMaYe6HilEQBj9iaQfvsnqlx/4EC qiyf5N72NTm+gUU2gOKoZHkTUILizP89t2blkzrcbwTFnKR1WHHHinJ3nkVguXmB 17sywI3qaJJb4KaMlRzist9qIDxjbrUjDXC7cMYNXqyEfS6aRXo= =wi80 -----END PGP SIGNATURE----- Merge tag 'backlight-next-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight Pull backlight updates from Lee Jones: "Fix-ups: - Improve bootloader/kernel device handover Bug Fixes: - Stabilise backlight in ktd253 driver" * tag 'backlight-next-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight: backlight: pwm_bl: Improve bootloader/kernel device handover backlight: ktd253: Stabilize backlight
This commit is contained in:
commit
2d7b4cdbb5
drivers/video/backlight
@ -25,6 +25,7 @@
|
||||
|
||||
#define KTD253_T_LOW_NS (200 + 10) /* Additional 10ns as safety factor */
|
||||
#define KTD253_T_HIGH_NS (200 + 10) /* Additional 10ns as safety factor */
|
||||
#define KTD253_T_OFF_CRIT_NS 100000 /* 100 us, now it doesn't look good */
|
||||
#define KTD253_T_OFF_MS 3
|
||||
|
||||
struct ktd253_backlight {
|
||||
@ -34,13 +35,50 @@ struct ktd253_backlight {
|
||||
u16 ratio;
|
||||
};
|
||||
|
||||
static void ktd253_backlight_set_max_ratio(struct ktd253_backlight *ktd253)
|
||||
{
|
||||
gpiod_set_value_cansleep(ktd253->gpiod, 1);
|
||||
ndelay(KTD253_T_HIGH_NS);
|
||||
/* We always fall back to this when we power on */
|
||||
}
|
||||
|
||||
static int ktd253_backlight_stepdown(struct ktd253_backlight *ktd253)
|
||||
{
|
||||
/*
|
||||
* These GPIO operations absolutely can NOT sleep so no _cansleep
|
||||
* suffixes, and no using GPIO expanders on slow buses for this!
|
||||
*
|
||||
* The maximum number of cycles of the loop is 32 so the time taken
|
||||
* should nominally be:
|
||||
* (T_LOW_NS + T_HIGH_NS + loop_time) * 32
|
||||
*
|
||||
* Architectures do not always support ndelay() and we will get a few us
|
||||
* instead. If we get to a critical time limit an interrupt has likely
|
||||
* occured in the low part of the loop and we need to restart from the
|
||||
* top so we have the backlight in a known state.
|
||||
*/
|
||||
u64 ns;
|
||||
|
||||
ns = ktime_get_ns();
|
||||
gpiod_set_value(ktd253->gpiod, 0);
|
||||
ndelay(KTD253_T_LOW_NS);
|
||||
gpiod_set_value(ktd253->gpiod, 1);
|
||||
ns = ktime_get_ns() - ns;
|
||||
if (ns >= KTD253_T_OFF_CRIT_NS) {
|
||||
dev_err(ktd253->dev, "PCM on backlight took too long (%llu ns)\n", ns);
|
||||
return -EAGAIN;
|
||||
}
|
||||
ndelay(KTD253_T_HIGH_NS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ktd253_backlight_update_status(struct backlight_device *bl)
|
||||
{
|
||||
struct ktd253_backlight *ktd253 = bl_get_data(bl);
|
||||
int brightness = backlight_get_brightness(bl);
|
||||
u16 target_ratio;
|
||||
u16 current_ratio = ktd253->ratio;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dev_dbg(ktd253->dev, "new brightness/ratio: %d/32\n", brightness);
|
||||
|
||||
@ -62,37 +100,34 @@ static int ktd253_backlight_update_status(struct backlight_device *bl)
|
||||
}
|
||||
|
||||
if (current_ratio == 0) {
|
||||
gpiod_set_value_cansleep(ktd253->gpiod, 1);
|
||||
ndelay(KTD253_T_HIGH_NS);
|
||||
/* We always fall back to this when we power on */
|
||||
ktd253_backlight_set_max_ratio(ktd253);
|
||||
current_ratio = KTD253_MAX_RATIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING:
|
||||
* The loop to set the correct current level is performed
|
||||
* with interrupts disabled as it is timing critical.
|
||||
* The maximum number of cycles of the loop is 32
|
||||
* so the time taken will be (T_LOW_NS + T_HIGH_NS + loop_time) * 32,
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
while (current_ratio != target_ratio) {
|
||||
/*
|
||||
* These GPIO operations absolutely can NOT sleep so no
|
||||
* _cansleep suffixes, and no using GPIO expanders on
|
||||
* slow buses for this!
|
||||
*/
|
||||
gpiod_set_value(ktd253->gpiod, 0);
|
||||
ndelay(KTD253_T_LOW_NS);
|
||||
gpiod_set_value(ktd253->gpiod, 1);
|
||||
ndelay(KTD253_T_HIGH_NS);
|
||||
/* After 1/32 we loop back to 32/32 */
|
||||
if (current_ratio == KTD253_MIN_RATIO)
|
||||
ret = ktd253_backlight_stepdown(ktd253);
|
||||
if (ret == -EAGAIN) {
|
||||
/*
|
||||
* Something disturbed the backlight setting code when
|
||||
* running so we need to bring the PWM back to a known
|
||||
* state. This shouldn't happen too much.
|
||||
*/
|
||||
gpiod_set_value_cansleep(ktd253->gpiod, 0);
|
||||
msleep(KTD253_T_OFF_MS);
|
||||
ktd253_backlight_set_max_ratio(ktd253);
|
||||
current_ratio = KTD253_MAX_RATIO;
|
||||
else
|
||||
} else if (current_ratio == KTD253_MIN_RATIO) {
|
||||
/* After 1/32 we loop back to 32/32 */
|
||||
current_ratio = KTD253_MAX_RATIO;
|
||||
} else {
|
||||
current_ratio--;
|
||||
}
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
ktd253->ratio = current_ratio;
|
||||
|
||||
dev_dbg(ktd253->dev, "new ratio set to %d/32\n", target_ratio);
|
||||
|
@ -409,6 +409,33 @@ static bool pwm_backlight_is_linear(struct platform_pwm_backlight_data *data)
|
||||
static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
|
||||
{
|
||||
struct device_node *node = pb->dev->of_node;
|
||||
bool active = true;
|
||||
|
||||
/*
|
||||
* If the enable GPIO is present, observable (either as input
|
||||
* or output) and off then the backlight is not currently active.
|
||||
* */
|
||||
if (pb->enable_gpio && gpiod_get_value_cansleep(pb->enable_gpio) == 0)
|
||||
active = false;
|
||||
|
||||
if (!regulator_is_enabled(pb->power_supply))
|
||||
active = false;
|
||||
|
||||
if (!pwm_is_enabled(pb->pwm))
|
||||
active = false;
|
||||
|
||||
/*
|
||||
* Synchronize the enable_gpio with the observed state of the
|
||||
* hardware.
|
||||
*/
|
||||
if (pb->enable_gpio)
|
||||
gpiod_direction_output(pb->enable_gpio, active);
|
||||
|
||||
/*
|
||||
* Do not change pb->enabled here! pb->enabled essentially
|
||||
* tells us if we own one of the regulator's use counts and
|
||||
* right now we do not.
|
||||
*/
|
||||
|
||||
/* Not booted with device tree or no phandle link to the node */
|
||||
if (!node || !node->phandle)
|
||||
@ -420,20 +447,7 @@ static int pwm_backlight_initial_power_state(const struct pwm_bl_data *pb)
|
||||
* assume that another driver will enable the backlight at the
|
||||
* appropriate time. Therefore, if it is disabled, keep it so.
|
||||
*/
|
||||
|
||||
/* if the enable GPIO is disabled, do not enable the backlight */
|
||||
if (pb->enable_gpio && gpiod_get_value_cansleep(pb->enable_gpio) == 0)
|
||||
return FB_BLANK_POWERDOWN;
|
||||
|
||||
/* The regulator is disabled, do not enable the backlight */
|
||||
if (!regulator_is_enabled(pb->power_supply))
|
||||
return FB_BLANK_POWERDOWN;
|
||||
|
||||
/* The PWM is disabled, keep it like this */
|
||||
if (!pwm_is_enabled(pb->pwm))
|
||||
return FB_BLANK_POWERDOWN;
|
||||
|
||||
return FB_BLANK_UNBLANK;
|
||||
return active ? FB_BLANK_UNBLANK: FB_BLANK_POWERDOWN;
|
||||
}
|
||||
|
||||
static int pwm_backlight_probe(struct platform_device *pdev)
|
||||
@ -486,18 +500,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the GPIO is not known to be already configured as output, that
|
||||
* is, if gpiod_get_direction returns either 1 or -EINVAL, change the
|
||||
* direction to output and set the GPIO as active.
|
||||
* Do not force the GPIO to active when it was already output as it
|
||||
* could cause backlight flickering or we would enable the backlight too
|
||||
* early. Leave the decision of the initial backlight state for later.
|
||||
*/
|
||||
if (pb->enable_gpio &&
|
||||
gpiod_get_direction(pb->enable_gpio) != 0)
|
||||
gpiod_direction_output(pb->enable_gpio, 1);
|
||||
|
||||
pb->power_supply = devm_regulator_get(&pdev->dev, "power");
|
||||
if (IS_ERR(pb->power_supply)) {
|
||||
ret = PTR_ERR(pb->power_supply);
|
||||
|
Loading…
Reference in New Issue
Block a user