mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-04 04:04:19 +00:00
- New Drivers
- Add support for Kinetic KTD2801 Backlight - Fix-ups - Fix include lists; alphabetise, remove unused, explicitly add used - Device Tree binding adaptions/conversions/creation - Use dev_err_probe() to clean-up error paths - Use/convert to new/better APIs/helpers/MACROs instead of hand-rolling implementations - Bug Fixes - Fix changes of NULL pointer dereference - Remedy a bunch of logic errors - Initialise (zero) Backlight properties data structures -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAmXzCwMACgkQUa+KL4f8 d2Ej3g//SVxd1ZF4OVe8VcfdeviormwL2cOvhsBNQHVtsPKYMSjH37Bf9O99GrL4 IBrOza/6SQUTxuzZwkcn6Ryl9O2KalTIJahgTxpdwm4Yrd3TEUAyizbaMy+rG49s aW+bAbl+y4d6ag6XSrafrTVbDWESR8NsaU4pozbNS8HLjfCoT5RR0K6N5jPSTXhE /oxk1LoCdFFBAOfl6z0NRmyjCTy495bftACXMdpx+68P/jySHemwo2z10lei0Sai ucj89Q4SGvk/PMNTAYKpn+jPRzd+5OV3NZk79U0RaJvTaUwXDMw01ypFXPb3wacL 5t6TKwMKeZLXtVbA9OIDi7eRUiJwLIm+fb2rWZEdrsLDFRoe6U6uSa7BmFOwhX+T 6XznFtBbbRng+/VFE1Xaczm6uQAt5MuySWq/Wf+4tRH+MfsoFvoShSDok+KxRyo0 8YKaH6GcmGtwwAnL+7rp6vjvNYNhO8/ui6rErXoeiFQlXoNF43DBmG82jeUfiOWJ 9l/JaqbQnsYy5e2vUGR0GeJl+a5krR86yCoNzIkMBdRkcJqK6A1we7YPt8CMyUTy rLJzbF6zjqKK7uniXbSCsEM9VleR+Ex3zwTmKTR10rybU1eWbtYk/5ZrDjoX62xl CK/9N9f7vYhBh+xnHbchPQOLK6g7pZ227Y9ks4b54q6u042n2Zo= =SaGM -----END PGP SIGNATURE----- Merge tag 'backlight-next-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight Pull backlight updates from Lee Jones: "New Drivers: - Add support for Kinetic KTD2801 Backlight Fix-ups: - Fix include lists; alphabetise, remove unused, explicitly add used - Device Tree binding adaptions/conversions/creation - Use dev_err_probe() to clean-up error paths - Use/convert to new/better APIs/helpers/MACROs instead of hand-rolling implementations Bug Fixes: - Fix changes of NULL pointer dereference - Remedy a bunch of logic errors - Initialise (zero) Backlight properties data structures" * tag 'backlight-next-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight: (32 commits) backlight: pandora_bl: Drop unneeded ENOMEM error message backlight: lm3630a_bl: Simplify probe return on gpio request error backlight: lm3630a_bl: Handle deferred probe backlight: as3711_bl: Handle deferred probe backlight: bd6107: Handle deferred probe backlight: l4f00242t03: Simplify with dev_err_probe() backlight: gpio: Simplify with dev_err_probe() backlight: lp8788: Fully initialize backlight_properties during probe backlight: lm3639: Fully initialize backlight_properties during probe backlight: da9052: Fully initialize backlight_properties during probe backlight: lm3630a: Use backlight_get_brightness helper in update_status backlight: lm3630a: Don't set bl->props.brightness in get_brightness backlight: lm3630a: Initialize backlight_properties on init backlight: mp3309c: Fully initialize backlight_properties during probe backlight: mp3309c: Utilise temporary variable for struct device backlight: mp3309c: Use dev_err_probe() instead of dev_err() backlight: mp3309c: Make use of device properties dt-bindings: backlight: qcom-wled: Fix bouncing email addresses backlight: hx8357: Utilise temporary variable for struct device backlight: hx8357: Make use of dev_err_probe() ...
This commit is contained in:
commit
f3d8f29d1f
@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/leds/backlight/kinetic,ktd2801.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Kinetic Technologies KTD2801 one-wire backlight
|
||||
|
||||
maintainers:
|
||||
- Duje Mihanović <duje.mihanovic@skole.hr>
|
||||
|
||||
description: |
|
||||
The Kinetic Technologies KTD2801 is a LED backlight driver controlled
|
||||
by a single GPIO line. The driver can be controlled with a PWM signal
|
||||
or by pulsing the GPIO line to set the backlight level. This is called
|
||||
"ExpressWire".
|
||||
|
||||
allOf:
|
||||
- $ref: common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: kinetic,ktd2801
|
||||
|
||||
ctrl-gpios:
|
||||
maxItems: 1
|
||||
|
||||
default-brightness: true
|
||||
max-brightness: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- ctrl-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
backlight {
|
||||
compatible = "kinetic,ktd2801";
|
||||
ctrl-gpios = <&gpio 97 GPIO_ACTIVE_HIGH>;
|
||||
max-brightness = <210>;
|
||||
default-brightness = <100>;
|
||||
};
|
@ -7,8 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Technologies, Inc. WLED driver
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
- Kiran Gunda <kgunda@codeaurora.org>
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
- Kiran Gunda <quic_kgunda@quicinc.com>
|
||||
|
||||
description: |
|
||||
WLED (White Light Emitting Diode) driver is used for controlling display
|
||||
|
13
MAINTAINERS
13
MAINTAINERS
@ -8039,6 +8039,13 @@ S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat.git
|
||||
F: fs/exfat/
|
||||
|
||||
EXPRESSWIRE PROTOCOL LIBRARY
|
||||
M: Duje Mihanović <duje.mihanovic@skole.hr>
|
||||
L: linux-leds@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/leds/leds-expresswire.c
|
||||
F: include/linux/leds-expresswire.h
|
||||
|
||||
EXT2 FILE SYSTEM
|
||||
M: Jan Kara <jack@suse.com>
|
||||
L: linux-ext4@vger.kernel.org
|
||||
@ -12103,6 +12110,12 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/leds/backlight/kinetic,ktd253.yaml
|
||||
F: drivers/video/backlight/ktd253-backlight.c
|
||||
|
||||
KTD2801 BACKLIGHT DRIVER
|
||||
M: Duje Mihanović <duje.mihanovic@skole.hr>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/leds/backlight/kinetic,ktd2801.yaml
|
||||
F: drivers/video/backlight/ktd2801-backlight.c
|
||||
|
||||
KTEST
|
||||
M: Steven Rostedt <rostedt@goodmis.org>
|
||||
M: John Hawley <warthog9@eaglescrag.net>
|
||||
|
@ -186,6 +186,10 @@ config LEDS_EL15203000
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called leds-el15203000.
|
||||
|
||||
config LEDS_EXPRESSWIRE
|
||||
bool
|
||||
depends on GPIOLIB
|
||||
|
||||
config LEDS_TURRIS_OMNIA
|
||||
tristate "LED support for CZ.NIC's Turris Omnia"
|
||||
depends on LEDS_CLASS_MULTICOLOR
|
||||
|
@ -91,6 +91,9 @@ obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
|
||||
obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
|
||||
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
|
||||
|
||||
# Kinetic ExpressWire Protocol
|
||||
obj-$(CONFIG_LEDS_EXPRESSWIRE) += leds-expresswire.o
|
||||
|
||||
# LED SPI Drivers
|
||||
obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
|
||||
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
|
||||
|
@ -23,7 +23,8 @@ config LEDS_AS3645A
|
||||
config LEDS_KTD2692
|
||||
tristate "LED support for Kinetic KTD2692 flash LED controller"
|
||||
depends on OF
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
depends on GPIOLIB
|
||||
select LEDS_EXPRESSWIRE
|
||||
help
|
||||
This option enables support for Kinetic KTD2692 LED flash connected
|
||||
through ExpressWire interface.
|
||||
|
@ -6,9 +6,9 @@
|
||||
* Ingi Kim <ingi2.kim@samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/leds-expresswire.h>
|
||||
#include <linux/led-class-flash.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
@ -37,22 +37,9 @@
|
||||
#define KTD2692_REG_FLASH_CURRENT_BASE 0x80
|
||||
#define KTD2692_REG_MODE_BASE 0xA0
|
||||
|
||||
/* Set bit coding time for expresswire interface */
|
||||
#define KTD2692_TIME_RESET_US 700
|
||||
#define KTD2692_TIME_DATA_START_TIME_US 10
|
||||
#define KTD2692_TIME_HIGH_END_OF_DATA_US 350
|
||||
#define KTD2692_TIME_LOW_END_OF_DATA_US 10
|
||||
#define KTD2692_TIME_SHORT_BITSET_US 4
|
||||
#define KTD2692_TIME_LONG_BITSET_US 12
|
||||
|
||||
/* KTD2692 default length of name */
|
||||
#define KTD2692_NAME_LENGTH 20
|
||||
|
||||
enum ktd2692_bitset {
|
||||
KTD2692_LOW = 0,
|
||||
KTD2692_HIGH,
|
||||
};
|
||||
|
||||
/* Movie / Flash Mode Control */
|
||||
enum ktd2692_led_mode {
|
||||
KTD2692_MODE_DISABLE = 0, /* default */
|
||||
@ -71,7 +58,19 @@ struct ktd2692_led_config_data {
|
||||
enum led_brightness max_brightness;
|
||||
};
|
||||
|
||||
const struct expresswire_timing ktd2692_timing = {
|
||||
.poweroff_us = 700,
|
||||
.data_start_us = 10,
|
||||
.end_of_data_low_us = 10,
|
||||
.end_of_data_high_us = 350,
|
||||
.short_bitset_us = 4,
|
||||
.long_bitset_us = 12
|
||||
};
|
||||
|
||||
struct ktd2692_context {
|
||||
/* Common ExpressWire properties (ctrl GPIO and timing) */
|
||||
struct expresswire_common_props props;
|
||||
|
||||
/* Related LED Flash class device */
|
||||
struct led_classdev_flash fled_cdev;
|
||||
|
||||
@ -80,7 +79,6 @@ struct ktd2692_context {
|
||||
struct regulator *regulator;
|
||||
|
||||
struct gpio_desc *aux_gpio;
|
||||
struct gpio_desc *ctrl_gpio;
|
||||
|
||||
enum ktd2692_led_mode mode;
|
||||
enum led_brightness torch_brightness;
|
||||
@ -92,67 +90,6 @@ static struct ktd2692_context *fled_cdev_to_led(
|
||||
return container_of(fled_cdev, struct ktd2692_context, fled_cdev);
|
||||
}
|
||||
|
||||
static void ktd2692_expresswire_start(struct ktd2692_context *led)
|
||||
{
|
||||
gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
|
||||
udelay(KTD2692_TIME_DATA_START_TIME_US);
|
||||
}
|
||||
|
||||
static void ktd2692_expresswire_reset(struct ktd2692_context *led)
|
||||
{
|
||||
gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
|
||||
udelay(KTD2692_TIME_RESET_US);
|
||||
}
|
||||
|
||||
static void ktd2692_expresswire_end(struct ktd2692_context *led)
|
||||
{
|
||||
gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
|
||||
udelay(KTD2692_TIME_LOW_END_OF_DATA_US);
|
||||
gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
|
||||
udelay(KTD2692_TIME_HIGH_END_OF_DATA_US);
|
||||
}
|
||||
|
||||
static void ktd2692_expresswire_set_bit(struct ktd2692_context *led, bool bit)
|
||||
{
|
||||
/*
|
||||
* The Low Bit(0) and High Bit(1) is based on a time detection
|
||||
* algorithm between time low and time high
|
||||
* Time_(L_LB) : Low time of the Low Bit(0)
|
||||
* Time_(H_LB) : High time of the LOW Bit(0)
|
||||
* Time_(L_HB) : Low time of the High Bit(1)
|
||||
* Time_(H_HB) : High time of the High Bit(1)
|
||||
*
|
||||
* It can be simplified to:
|
||||
* Low Bit(0) : 2 * Time_(H_LB) < Time_(L_LB)
|
||||
* High Bit(1) : 2 * Time_(L_HB) < Time_(H_HB)
|
||||
* HIGH ___ ____ _.. _________ ___
|
||||
* |_________| |_.. |____| |__|
|
||||
* LOW <L_LB> <H_LB> <L_HB> <H_HB>
|
||||
* [ Low Bit (0) ] [ High Bit(1) ]
|
||||
*/
|
||||
if (bit) {
|
||||
gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
|
||||
udelay(KTD2692_TIME_SHORT_BITSET_US);
|
||||
gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
|
||||
udelay(KTD2692_TIME_LONG_BITSET_US);
|
||||
} else {
|
||||
gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
|
||||
udelay(KTD2692_TIME_LONG_BITSET_US);
|
||||
gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
|
||||
udelay(KTD2692_TIME_SHORT_BITSET_US);
|
||||
}
|
||||
}
|
||||
|
||||
static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value)
|
||||
{
|
||||
int i;
|
||||
|
||||
ktd2692_expresswire_start(led);
|
||||
for (i = 7; i >= 0; i--)
|
||||
ktd2692_expresswire_set_bit(led, value & BIT(i));
|
||||
ktd2692_expresswire_end(led);
|
||||
}
|
||||
|
||||
static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
@ -163,14 +100,14 @@ static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
|
||||
|
||||
if (brightness == LED_OFF) {
|
||||
led->mode = KTD2692_MODE_DISABLE;
|
||||
gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
|
||||
gpiod_direction_output(led->aux_gpio, 0);
|
||||
} else {
|
||||
ktd2692_expresswire_write(led, brightness |
|
||||
expresswire_write_u8(&led->props, brightness |
|
||||
KTD2692_REG_MOVIE_CURRENT_BASE);
|
||||
led->mode = KTD2692_MODE_MOVIE;
|
||||
}
|
||||
|
||||
ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
|
||||
expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE);
|
||||
mutex_unlock(&led->lock);
|
||||
|
||||
return 0;
|
||||
@ -187,17 +124,17 @@ static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev,
|
||||
|
||||
if (state) {
|
||||
flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step);
|
||||
ktd2692_expresswire_write(led, flash_tm_reg
|
||||
expresswire_write_u8(&led->props, flash_tm_reg
|
||||
| KTD2692_REG_FLASH_TIMEOUT_BASE);
|
||||
|
||||
led->mode = KTD2692_MODE_FLASH;
|
||||
gpiod_direction_output(led->aux_gpio, KTD2692_HIGH);
|
||||
gpiod_direction_output(led->aux_gpio, 1);
|
||||
} else {
|
||||
led->mode = KTD2692_MODE_DISABLE;
|
||||
gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
|
||||
gpiod_direction_output(led->aux_gpio, 0);
|
||||
}
|
||||
|
||||
ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
|
||||
expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE);
|
||||
|
||||
fled_cdev->led_cdev.brightness = LED_OFF;
|
||||
led->mode = KTD2692_MODE_DISABLE;
|
||||
@ -247,12 +184,12 @@ static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev,
|
||||
static void ktd2692_setup(struct ktd2692_context *led)
|
||||
{
|
||||
led->mode = KTD2692_MODE_DISABLE;
|
||||
ktd2692_expresswire_reset(led);
|
||||
gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
|
||||
expresswire_power_off(&led->props);
|
||||
gpiod_direction_output(led->aux_gpio, 0);
|
||||
|
||||
ktd2692_expresswire_write(led, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1)
|
||||
expresswire_write_u8(&led->props, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1)
|
||||
| KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE);
|
||||
ktd2692_expresswire_write(led, KTD2692_FLASH_MODE_CURR_PERCENT(45)
|
||||
expresswire_write_u8(&led->props, KTD2692_FLASH_MODE_CURR_PERCENT(45)
|
||||
| KTD2692_REG_FLASH_CURRENT_BASE);
|
||||
}
|
||||
|
||||
@ -277,8 +214,8 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
|
||||
if (!np)
|
||||
return -ENXIO;
|
||||
|
||||
led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
|
||||
ret = PTR_ERR_OR_ZERO(led->ctrl_gpio);
|
||||
led->props.ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
|
||||
ret = PTR_ERR_OR_ZERO(led->props.ctrl_gpio);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "cannot get ctrl-gpios\n");
|
||||
|
||||
@ -412,6 +349,7 @@ static struct platform_driver ktd2692_driver = {
|
||||
|
||||
module_platform_driver(ktd2692_driver);
|
||||
|
||||
MODULE_IMPORT_NS(EXPRESSWIRE);
|
||||
MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Kinetic KTD2692 LED driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
72
drivers/leds/leds-expresswire.c
Normal file
72
drivers/leds/leds-expresswire.c
Normal file
@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Shared library for Kinetic's ExpressWire protocol.
|
||||
* This protocol works by pulsing the ExpressWire IC's control GPIO.
|
||||
* ktd2692 and ktd2801 are known to use this protocol.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/leds-expresswire.h>
|
||||
|
||||
void expresswire_power_off(struct expresswire_common_props *props)
|
||||
{
|
||||
gpiod_set_value_cansleep(props->ctrl_gpio, 0);
|
||||
usleep_range(props->timing.poweroff_us, props->timing.poweroff_us * 2);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(expresswire_power_off, EXPRESSWIRE);
|
||||
|
||||
void expresswire_enable(struct expresswire_common_props *props)
|
||||
{
|
||||
gpiod_set_value(props->ctrl_gpio, 1);
|
||||
udelay(props->timing.detect_delay_us);
|
||||
gpiod_set_value(props->ctrl_gpio, 0);
|
||||
udelay(props->timing.detect_us);
|
||||
gpiod_set_value(props->ctrl_gpio, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(expresswire_enable, EXPRESSWIRE);
|
||||
|
||||
void expresswire_start(struct expresswire_common_props *props)
|
||||
{
|
||||
gpiod_set_value(props->ctrl_gpio, 1);
|
||||
udelay(props->timing.data_start_us);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(expresswire_start, EXPRESSWIRE);
|
||||
|
||||
void expresswire_end(struct expresswire_common_props *props)
|
||||
{
|
||||
gpiod_set_value(props->ctrl_gpio, 0);
|
||||
udelay(props->timing.end_of_data_low_us);
|
||||
gpiod_set_value(props->ctrl_gpio, 1);
|
||||
udelay(props->timing.end_of_data_high_us);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(expresswire_end, EXPRESSWIRE);
|
||||
|
||||
void expresswire_set_bit(struct expresswire_common_props *props, bool bit)
|
||||
{
|
||||
if (bit) {
|
||||
gpiod_set_value(props->ctrl_gpio, 0);
|
||||
udelay(props->timing.short_bitset_us);
|
||||
gpiod_set_value(props->ctrl_gpio, 1);
|
||||
udelay(props->timing.long_bitset_us);
|
||||
} else {
|
||||
gpiod_set_value(props->ctrl_gpio, 0);
|
||||
udelay(props->timing.long_bitset_us);
|
||||
gpiod_set_value(props->ctrl_gpio, 1);
|
||||
udelay(props->timing.short_bitset_us);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(expresswire_set_bit, EXPRESSWIRE);
|
||||
|
||||
void expresswire_write_u8(struct expresswire_common_props *props, u8 val)
|
||||
{
|
||||
expresswire_start(props);
|
||||
for (int i = 7; i >= 0; i--)
|
||||
expresswire_set_bit(props, val & BIT(i));
|
||||
expresswire_end(props);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(expresswire_write_u8, EXPRESSWIRE);
|
@ -183,6 +183,13 @@ config BACKLIGHT_KTD253
|
||||
which is a 1-wire GPIO-controlled backlight found in some mobile
|
||||
phones.
|
||||
|
||||
config BACKLIGHT_KTD2801
|
||||
tristate "Backlight Driver for Kinetic KTD2801"
|
||||
select LEDS_EXPRESSWIRE
|
||||
help
|
||||
Say Y to enable the backlight driver for the Kinetic KTD2801 1-wire
|
||||
GPIO-controlled backlight found in Samsung Galaxy Core Prime VE LTE.
|
||||
|
||||
config BACKLIGHT_KTZ8866
|
||||
tristate "Backlight Driver for Kinetic KTZ8866"
|
||||
depends on I2C
|
||||
|
@ -34,6 +34,7 @@ obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO) += ipaq_micro_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_KTD253) += ktd253-backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_KTD2801) += ktd2801-backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_KTZ8866) += ktz8866.o
|
||||
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
|
||||
|
@ -383,10 +383,8 @@ static int as3711_backlight_probe(struct platform_device *pdev)
|
||||
|
||||
if (pdev->dev.parent->of_node) {
|
||||
ret = as3711_backlight_parse_dt(&pdev->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "DT parsing failed\n");
|
||||
}
|
||||
|
||||
if (!pdata->su1_fb && !pdata->su2_fb) {
|
||||
|
@ -119,7 +119,6 @@ static int bd6107_probe(struct i2c_client *client)
|
||||
struct backlight_device *backlight;
|
||||
struct backlight_properties props;
|
||||
struct bd6107 *bd;
|
||||
int ret;
|
||||
|
||||
if (pdata == NULL) {
|
||||
dev_err(&client->dev, "No platform data\n");
|
||||
@ -147,11 +146,9 @@ static int bd6107_probe(struct i2c_client *client)
|
||||
* the reset.
|
||||
*/
|
||||
bd->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(bd->reset)) {
|
||||
dev_err(&client->dev, "unable to request reset GPIO\n");
|
||||
ret = PTR_ERR(bd->reset);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(bd->reset))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(bd->reset),
|
||||
"unable to request reset GPIO\n");
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
|
@ -117,6 +117,7 @@ static int da9052_backlight_probe(struct platform_device *pdev)
|
||||
wleds->led_reg = platform_get_device_id(pdev)->driver_data;
|
||||
wleds->state = DA9052_WLEDS_OFF;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.max_brightness = DA9052_MAX_BRIGHTNESS;
|
||||
|
||||
|
@ -64,13 +64,9 @@ static int gpio_backlight_probe(struct platform_device *pdev)
|
||||
def_value = device_property_read_bool(dev, "default-on");
|
||||
|
||||
gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS);
|
||||
if (IS_ERR(gbl->gpiod)) {
|
||||
ret = PTR_ERR(gbl->gpiod);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev,
|
||||
"Error: The gpios parameter is missing or invalid.\n");
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(gbl->gpiod))
|
||||
return dev_err_probe(dev, PTR_ERR(gbl->gpiod),
|
||||
"The gpios parameter is missing or invalid\n");
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
|
@ -8,9 +8,9 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/lcd.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define HX8357_NUM_IM_PINS 3
|
||||
@ -564,41 +564,28 @@ static struct lcd_ops hx8357_ops = {
|
||||
.get_power = hx8357_get_power,
|
||||
};
|
||||
|
||||
static const struct of_device_id hx8357_dt_ids[] = {
|
||||
{
|
||||
.compatible = "himax,hx8357",
|
||||
.data = hx8357_lcd_init,
|
||||
},
|
||||
{
|
||||
.compatible = "himax,hx8369",
|
||||
.data = hx8369_lcd_init,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
|
||||
typedef int (*hx8357_init_fn)(struct lcd_device *);
|
||||
|
||||
static int hx8357_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct lcd_device *lcdev;
|
||||
struct hx8357_data *lcd;
|
||||
const struct of_device_id *match;
|
||||
hx8357_init_fn init_fn;
|
||||
int i, ret;
|
||||
|
||||
lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
|
||||
lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);
|
||||
if (!lcd)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = spi_setup(spi);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "SPI setup failed.\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "SPI setup failed.\n");
|
||||
|
||||
lcd->spi = spi;
|
||||
|
||||
match = of_match_device(hx8357_dt_ids, &spi->dev);
|
||||
if (!match || !match->data)
|
||||
init_fn = device_get_match_data(dev);
|
||||
if (!init_fn)
|
||||
return -EINVAL;
|
||||
|
||||
lcd->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
@ -609,14 +596,15 @@ static int hx8357_probe(struct spi_device *spi)
|
||||
lcd->im_pins = devm_gpiod_get_array_optional(dev, "im", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(lcd->im_pins))
|
||||
return dev_err_probe(dev, PTR_ERR(lcd->im_pins), "failed to request im GPIOs\n");
|
||||
if (lcd->im_pins->ndescs < HX8357_NUM_IM_PINS)
|
||||
return dev_err_probe(dev, -EINVAL, "not enough im GPIOs\n");
|
||||
if (lcd->im_pins) {
|
||||
if (lcd->im_pins->ndescs < HX8357_NUM_IM_PINS)
|
||||
return dev_err_probe(dev, -EINVAL, "not enough im GPIOs\n");
|
||||
|
||||
for (i = 0; i < HX8357_NUM_IM_PINS; i++)
|
||||
gpiod_set_consumer_name(lcd->im_pins->desc[i], "im_pins");
|
||||
for (i = 0; i < HX8357_NUM_IM_PINS; i++)
|
||||
gpiod_set_consumer_name(lcd->im_pins->desc[i], "im_pins");
|
||||
}
|
||||
|
||||
lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd,
|
||||
&hx8357_ops);
|
||||
lcdev = devm_lcd_device_register(dev, "mxsfb", dev, lcd, &hx8357_ops);
|
||||
if (IS_ERR(lcdev)) {
|
||||
ret = PTR_ERR(lcdev);
|
||||
return ret;
|
||||
@ -625,17 +613,28 @@ static int hx8357_probe(struct spi_device *spi)
|
||||
|
||||
hx8357_lcd_reset(lcdev);
|
||||
|
||||
ret = ((int (*)(struct lcd_device *))match->data)(lcdev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Couldn't initialize panel\n");
|
||||
return ret;
|
||||
}
|
||||
ret = init_fn(lcdev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Couldn't initialize panel\n");
|
||||
|
||||
dev_info(&spi->dev, "Panel probed\n");
|
||||
dev_info(dev, "Panel probed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id hx8357_dt_ids[] = {
|
||||
{
|
||||
.compatible = "himax,hx8357",
|
||||
.data = hx8357_lcd_init,
|
||||
},
|
||||
{
|
||||
.compatible = "himax,hx8369",
|
||||
.data = hx8369_lcd_init,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
|
||||
|
||||
static struct spi_driver hx8357_driver = {
|
||||
.probe = hx8357_probe,
|
||||
.driver = {
|
||||
|
128
drivers/video/backlight/ktd2801-backlight.c
Normal file
128
drivers/video/backlight/ktd2801-backlight.c
Normal file
@ -0,0 +1,128 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Datasheet:
|
||||
* https://www.kinet-ic.com/uploads/web/KTD2801/KTD2801-04b.pdf
|
||||
*/
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/leds-expresswire.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#define KTD2801_DEFAULT_BRIGHTNESS 100
|
||||
#define KTD2801_MAX_BRIGHTNESS 255
|
||||
|
||||
/* These values have been extracted from Samsung's driver. */
|
||||
static const struct expresswire_timing ktd2801_timing = {
|
||||
.poweroff_us = 2600,
|
||||
.detect_delay_us = 150,
|
||||
.detect_us = 270,
|
||||
.data_start_us = 5,
|
||||
.short_bitset_us = 5,
|
||||
.long_bitset_us = 15,
|
||||
.end_of_data_low_us = 10,
|
||||
.end_of_data_high_us = 350
|
||||
};
|
||||
|
||||
struct ktd2801_backlight {
|
||||
struct expresswire_common_props props;
|
||||
struct backlight_device *bd;
|
||||
bool was_on;
|
||||
};
|
||||
|
||||
static int ktd2801_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct ktd2801_backlight *ktd2801 = bl_get_data(bd);
|
||||
u8 brightness = (u8) backlight_get_brightness(bd);
|
||||
|
||||
if (backlight_is_blank(bd)) {
|
||||
expresswire_power_off(&ktd2801->props);
|
||||
ktd2801->was_on = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ktd2801->was_on) {
|
||||
expresswire_enable(&ktd2801->props);
|
||||
ktd2801->was_on = true;
|
||||
}
|
||||
|
||||
expresswire_write_u8(&ktd2801->props, brightness);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct backlight_ops ktd2801_backlight_ops = {
|
||||
.update_status = ktd2801_update_status,
|
||||
};
|
||||
|
||||
static int ktd2801_backlight_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct backlight_device *bd;
|
||||
struct ktd2801_backlight *ktd2801;
|
||||
u32 brightness, max_brightness;
|
||||
int ret;
|
||||
|
||||
ktd2801 = devm_kzalloc(dev, sizeof(*ktd2801), GFP_KERNEL);
|
||||
if (!ktd2801)
|
||||
return -ENOMEM;
|
||||
ktd2801->was_on = true;
|
||||
ktd2801->props.timing = ktd2801_timing;
|
||||
|
||||
ret = device_property_read_u32(dev, "max-brightness", &max_brightness);
|
||||
if (ret)
|
||||
max_brightness = KTD2801_MAX_BRIGHTNESS;
|
||||
if (max_brightness > KTD2801_MAX_BRIGHTNESS) {
|
||||
dev_err(dev, "illegal max brightness specified\n");
|
||||
max_brightness = KTD2801_MAX_BRIGHTNESS;
|
||||
}
|
||||
|
||||
ret = device_property_read_u32(dev, "default-brightness", &brightness);
|
||||
if (ret)
|
||||
brightness = KTD2801_DEFAULT_BRIGHTNESS;
|
||||
if (brightness > max_brightness) {
|
||||
dev_err(dev, "default brightness exceeds max\n");
|
||||
brightness = max_brightness;
|
||||
}
|
||||
|
||||
ktd2801->props.ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(ktd2801->props.ctrl_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(ktd2801->props.ctrl_gpio),
|
||||
"failed to get backlight GPIO");
|
||||
gpiod_set_consumer_name(ktd2801->props.ctrl_gpio, dev_name(dev));
|
||||
|
||||
bd = devm_backlight_device_register(dev, dev_name(dev), dev, ktd2801,
|
||||
&ktd2801_backlight_ops, NULL);
|
||||
if (IS_ERR(bd))
|
||||
return dev_err_probe(dev, PTR_ERR(bd),
|
||||
"failed to register backlight");
|
||||
|
||||
bd->props.max_brightness = max_brightness;
|
||||
bd->props.brightness = brightness;
|
||||
|
||||
ktd2801->bd = bd;
|
||||
platform_set_drvdata(pdev, bd);
|
||||
backlight_update_status(bd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ktd2801_of_match[] = {
|
||||
{ .compatible = "kinetic,ktd2801" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ktd2801_of_match);
|
||||
|
||||
static struct platform_driver ktd2801_backlight_driver = {
|
||||
.driver = {
|
||||
.name = "ktd2801-backlight",
|
||||
.of_match_table = ktd2801_of_match,
|
||||
},
|
||||
.probe = ktd2801_backlight_probe,
|
||||
};
|
||||
module_platform_driver(ktd2801_backlight_driver);
|
||||
|
||||
MODULE_IMPORT_NS(EXPRESSWIRE);
|
||||
MODULE_AUTHOR("Duje Mihanović <duje.mihanovic@skole.hr>");
|
||||
MODULE_DESCRIPTION("Kinetic KTD2801 Backlight Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -97,20 +97,20 @@ static void ktz8866_init(struct ktz8866 *ktz)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
if (of_property_read_u32(ktz->client->dev.of_node, "current-num-sinks", &val))
|
||||
if (!of_property_read_u32(ktz->client->dev.of_node, "current-num-sinks", &val))
|
||||
ktz8866_write(ktz, BL_EN, BIT(val) - 1);
|
||||
else
|
||||
/* Enable all 6 current sinks if the number of current sinks isn't specified. */
|
||||
ktz8866_write(ktz, BL_EN, BIT(6) - 1);
|
||||
|
||||
if (of_property_read_u32(ktz->client->dev.of_node, "kinetic,current-ramp-delay-ms", &val)) {
|
||||
if (!of_property_read_u32(ktz->client->dev.of_node, "kinetic,current-ramp-delay-ms", &val)) {
|
||||
if (val <= 128)
|
||||
ktz8866_write(ktz, BL_CFG2, BIT(7) | (ilog2(val) << 3) | PWM_HYST);
|
||||
else
|
||||
ktz8866_write(ktz, BL_CFG2, BIT(7) | ((5 + val / 64) << 3) | PWM_HYST);
|
||||
}
|
||||
|
||||
if (of_property_read_u32(ktz->client->dev.of_node, "kinetic,led-enable-ramp-delay-ms", &val)) {
|
||||
if (!of_property_read_u32(ktz->client->dev.of_node, "kinetic,led-enable-ramp-delay-ms", &val)) {
|
||||
if (val == 0)
|
||||
ktz8866_write(ktz, BL_DIMMING, 0);
|
||||
else {
|
||||
|
@ -179,34 +179,28 @@ static int l4f00242t03_probe(struct spi_device *spi)
|
||||
priv->spi = spi;
|
||||
|
||||
priv->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(priv->reset)) {
|
||||
dev_err(&spi->dev,
|
||||
"Unable to get the lcd l4f00242t03 reset gpio.\n");
|
||||
return PTR_ERR(priv->reset);
|
||||
}
|
||||
if (IS_ERR(priv->reset))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(priv->reset),
|
||||
"Unable to get the lcd l4f00242t03 reset gpio.\n");
|
||||
gpiod_set_consumer_name(priv->reset, "lcd l4f00242t03 reset");
|
||||
|
||||
priv->enable = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(priv->enable)) {
|
||||
dev_err(&spi->dev,
|
||||
"Unable to get the lcd l4f00242t03 data en gpio.\n");
|
||||
return PTR_ERR(priv->enable);
|
||||
}
|
||||
if (IS_ERR(priv->enable))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(priv->enable),
|
||||
"Unable to get the lcd l4f00242t03 data en gpio.\n");
|
||||
gpiod_set_consumer_name(priv->enable, "lcd l4f00242t03 data enable");
|
||||
|
||||
priv->io_reg = devm_regulator_get(&spi->dev, "vdd");
|
||||
if (IS_ERR(priv->io_reg)) {
|
||||
dev_err(&spi->dev, "%s: Unable to get the IO regulator\n",
|
||||
__func__);
|
||||
return PTR_ERR(priv->io_reg);
|
||||
}
|
||||
if (IS_ERR(priv->io_reg))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(priv->io_reg),
|
||||
"%s: Unable to get the IO regulator\n",
|
||||
__func__);
|
||||
|
||||
priv->core_reg = devm_regulator_get(&spi->dev, "vcore");
|
||||
if (IS_ERR(priv->core_reg)) {
|
||||
dev_err(&spi->dev, "%s: Unable to get the core regulator\n",
|
||||
__func__);
|
||||
return PTR_ERR(priv->core_reg);
|
||||
}
|
||||
if (IS_ERR(priv->core_reg))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(priv->core_reg),
|
||||
"%s: Unable to get the core regulator\n",
|
||||
__func__);
|
||||
|
||||
priv->ld = devm_lcd_device_register(&spi->dev, "l4f00242t03", &spi->dev,
|
||||
priv, &l4f_ops);
|
||||
|
@ -189,10 +189,11 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
|
||||
int ret;
|
||||
struct lm3630a_chip *pchip = bl_get_data(bl);
|
||||
enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
|
||||
int brightness = backlight_get_brightness(bl);
|
||||
|
||||
/* pwm control */
|
||||
if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0)
|
||||
return lm3630a_pwm_ctrl(pchip, bl->props.brightness,
|
||||
return lm3630a_pwm_ctrl(pchip, brightness,
|
||||
bl->props.max_brightness);
|
||||
|
||||
/* disable sleep */
|
||||
@ -201,9 +202,9 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
|
||||
goto out_i2c_err;
|
||||
usleep_range(1000, 2000);
|
||||
/* minimum brightness is 0x04 */
|
||||
ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness);
|
||||
ret = lm3630a_write(pchip, REG_BRT_A, brightness);
|
||||
|
||||
if (backlight_is_blank(bl) || (backlight_get_brightness(bl) < 0x4))
|
||||
if (brightness < 0x4)
|
||||
/* turn the string off */
|
||||
ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0);
|
||||
else
|
||||
@ -233,7 +234,7 @@ static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
|
||||
if (rval < 0)
|
||||
goto out_i2c_err;
|
||||
brightness |= rval;
|
||||
goto out;
|
||||
return brightness;
|
||||
}
|
||||
|
||||
/* disable sleep */
|
||||
@ -244,11 +245,8 @@ static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
|
||||
rval = lm3630a_read(pchip, REG_BRT_A);
|
||||
if (rval < 0)
|
||||
goto out_i2c_err;
|
||||
brightness = rval;
|
||||
return rval;
|
||||
|
||||
out:
|
||||
bl->props.brightness = brightness;
|
||||
return bl->props.brightness;
|
||||
out_i2c_err:
|
||||
dev_err(pchip->dev, "i2c failed to access register\n");
|
||||
return 0;
|
||||
@ -266,10 +264,11 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
|
||||
int ret;
|
||||
struct lm3630a_chip *pchip = bl_get_data(bl);
|
||||
enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
|
||||
int brightness = backlight_get_brightness(bl);
|
||||
|
||||
/* pwm control */
|
||||
if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0)
|
||||
return lm3630a_pwm_ctrl(pchip, bl->props.brightness,
|
||||
return lm3630a_pwm_ctrl(pchip, brightness,
|
||||
bl->props.max_brightness);
|
||||
|
||||
/* disable sleep */
|
||||
@ -278,9 +277,9 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
|
||||
goto out_i2c_err;
|
||||
usleep_range(1000, 2000);
|
||||
/* minimum brightness is 0x04 */
|
||||
ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness);
|
||||
ret = lm3630a_write(pchip, REG_BRT_B, brightness);
|
||||
|
||||
if (backlight_is_blank(bl) || (backlight_get_brightness(bl) < 0x4))
|
||||
if (brightness < 0x4)
|
||||
/* turn the string off */
|
||||
ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0);
|
||||
else
|
||||
@ -310,7 +309,7 @@ static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
|
||||
if (rval < 0)
|
||||
goto out_i2c_err;
|
||||
brightness |= rval;
|
||||
goto out;
|
||||
return brightness;
|
||||
}
|
||||
|
||||
/* disable sleep */
|
||||
@ -321,11 +320,8 @@ static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
|
||||
rval = lm3630a_read(pchip, REG_BRT_B);
|
||||
if (rval < 0)
|
||||
goto out_i2c_err;
|
||||
brightness = rval;
|
||||
return rval;
|
||||
|
||||
out:
|
||||
bl->props.brightness = brightness;
|
||||
return bl->props.brightness;
|
||||
out_i2c_err:
|
||||
dev_err(pchip->dev, "i2c failed to access register\n");
|
||||
return 0;
|
||||
@ -343,6 +339,7 @@ static int lm3630a_backlight_register(struct lm3630a_chip *pchip)
|
||||
struct backlight_properties props;
|
||||
const char *label;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {
|
||||
props.brightness = pdata->leda_init_brt;
|
||||
@ -543,10 +540,8 @@ static int lm3630a_probe(struct i2c_client *client)
|
||||
|
||||
pchip->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pchip->enable_gpio)) {
|
||||
rval = PTR_ERR(pchip->enable_gpio);
|
||||
return rval;
|
||||
}
|
||||
if (IS_ERR(pchip->enable_gpio))
|
||||
return PTR_ERR(pchip->enable_gpio);
|
||||
|
||||
/* chip initialize */
|
||||
rval = lm3630a_chip_init(pchip);
|
||||
@ -563,10 +558,9 @@ static int lm3630a_probe(struct i2c_client *client)
|
||||
/* pwm */
|
||||
if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) {
|
||||
pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm");
|
||||
if (IS_ERR(pchip->pwmd)) {
|
||||
dev_err(&client->dev, "fail : get pwm device\n");
|
||||
return PTR_ERR(pchip->pwmd);
|
||||
}
|
||||
if (IS_ERR(pchip->pwmd))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(pchip->pwmd),
|
||||
"fail : get pwm device\n");
|
||||
|
||||
pwm_init_state(pchip->pwmd, &pchip->pwmd_state);
|
||||
}
|
||||
|
@ -338,6 +338,7 @@ static int lm3639_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
/* backlight */
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.brightness = pdata->init_brt_led;
|
||||
props.max_brightness = pdata->max_brt_led;
|
||||
|
@ -191,6 +191,7 @@ static int lp8788_backlight_register(struct lp8788_bl *bl)
|
||||
int init_brt;
|
||||
char *name;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.max_brightness = MAX_BRIGHTNESS;
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
@ -131,7 +133,7 @@ static int mp3309c_bl_update_status(struct backlight_device *bl)
|
||||
chip->pdata->levels[brightness],
|
||||
chip->pdata->levels[chip->pdata->max_brightness]);
|
||||
pwmstate.enabled = true;
|
||||
ret = pwm_apply_state(chip->pwmd, &pwmstate);
|
||||
ret = pwm_apply_might_sleep(chip->pwmd, &pwmstate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -199,20 +201,15 @@ static const struct backlight_ops mp3309c_bl_ops = {
|
||||
.update_status = mp3309c_bl_update_status,
|
||||
};
|
||||
|
||||
static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
|
||||
struct mp3309c_platform_data *pdata)
|
||||
static int mp3309c_parse_fwnode(struct mp3309c_chip *chip,
|
||||
struct mp3309c_platform_data *pdata)
|
||||
{
|
||||
struct device_node *node = chip->dev->of_node;
|
||||
struct property *prop_pwms;
|
||||
struct property *prop_levels = NULL;
|
||||
int length = 0;
|
||||
int ret, i;
|
||||
unsigned int num_levels, tmp_value;
|
||||
struct device *dev = chip->dev;
|
||||
|
||||
if (!node) {
|
||||
dev_err(chip->dev, "failed to get DT node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!dev_fwnode(dev))
|
||||
return dev_err_probe(dev, -ENODEV, "failed to get firmware node\n");
|
||||
|
||||
/*
|
||||
* Dimming mode: the MP3309C provides two dimming control mode:
|
||||
@ -224,12 +221,10 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
|
||||
* found in the backlight node, the mode switches to PWM mode.
|
||||
*/
|
||||
pdata->dimming_mode = DIMMING_ANALOG_I2C;
|
||||
prop_pwms = of_find_property(node, "pwms", &length);
|
||||
if (prop_pwms) {
|
||||
chip->pwmd = devm_pwm_get(chip->dev, NULL);
|
||||
if (device_property_present(dev, "pwms")) {
|
||||
chip->pwmd = devm_pwm_get(dev, NULL);
|
||||
if (IS_ERR(chip->pwmd))
|
||||
return dev_err_probe(chip->dev, PTR_ERR(chip->pwmd),
|
||||
"error getting pwm data\n");
|
||||
return dev_err_probe(dev, PTR_ERR(chip->pwmd), "error getting pwm data\n");
|
||||
pdata->dimming_mode = DIMMING_PWM;
|
||||
pwm_apply_args(chip->pwmd);
|
||||
}
|
||||
@ -247,21 +242,17 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
|
||||
num_levels = ANALOG_I2C_NUM_LEVELS;
|
||||
|
||||
/* Enable GPIO used in I2C dimming mode only */
|
||||
chip->enable_gpio = devm_gpiod_get(chip->dev, "enable",
|
||||
GPIOD_OUT_HIGH);
|
||||
chip->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(chip->enable_gpio))
|
||||
return dev_err_probe(chip->dev,
|
||||
PTR_ERR(chip->enable_gpio),
|
||||
return dev_err_probe(dev, PTR_ERR(chip->enable_gpio),
|
||||
"error getting enable gpio\n");
|
||||
} else {
|
||||
/*
|
||||
* PWM control mode: check for brightness level in DT
|
||||
*/
|
||||
prop_levels = of_find_property(node, "brightness-levels",
|
||||
&length);
|
||||
if (prop_levels) {
|
||||
if (device_property_present(dev, "brightness-levels")) {
|
||||
/* Read brightness levels from DT */
|
||||
num_levels = length / sizeof(u32);
|
||||
num_levels = device_property_count_u32(dev, "brightness-levels");
|
||||
if (num_levels < 2)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
@ -271,14 +262,12 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
|
||||
}
|
||||
|
||||
/* Fill brightness levels array */
|
||||
pdata->levels = devm_kcalloc(chip->dev, num_levels,
|
||||
sizeof(*pdata->levels), GFP_KERNEL);
|
||||
pdata->levels = devm_kcalloc(dev, num_levels, sizeof(*pdata->levels), GFP_KERNEL);
|
||||
if (!pdata->levels)
|
||||
return -ENOMEM;
|
||||
if (prop_levels) {
|
||||
ret = of_property_read_u32_array(node, "brightness-levels",
|
||||
pdata->levels,
|
||||
num_levels);
|
||||
if (device_property_present(dev, "brightness-levels")) {
|
||||
ret = device_property_read_u32_array(dev, "brightness-levels",
|
||||
pdata->levels, num_levels);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
@ -288,13 +277,11 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
|
||||
|
||||
pdata->max_brightness = num_levels - 1;
|
||||
|
||||
ret = of_property_read_u32(node, "default-brightness",
|
||||
&pdata->default_brightness);
|
||||
ret = device_property_read_u32(dev, "default-brightness", &pdata->default_brightness);
|
||||
if (ret)
|
||||
pdata->default_brightness = pdata->max_brightness;
|
||||
if (pdata->default_brightness > pdata->max_brightness) {
|
||||
dev_err(chip->dev,
|
||||
"default brightness exceeds max brightness\n");
|
||||
dev_err_probe(dev, -ERANGE, "default brightness exceeds max brightness\n");
|
||||
pdata->default_brightness = pdata->max_brightness;
|
||||
}
|
||||
|
||||
@ -310,8 +297,8 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
|
||||
* If missing, the default value for OVP is 35.5V
|
||||
*/
|
||||
pdata->over_voltage_protection = REG_I2C_1_OVP1;
|
||||
if (!of_property_read_u32(node, "mps,overvoltage-protection-microvolt",
|
||||
&tmp_value)) {
|
||||
ret = device_property_read_u32(dev, "mps,overvoltage-protection-microvolt", &tmp_value);
|
||||
if (!ret) {
|
||||
switch (tmp_value) {
|
||||
case 13500000:
|
||||
pdata->over_voltage_protection = 0x00;
|
||||
@ -328,62 +315,59 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
|
||||
}
|
||||
|
||||
/* Synchronous (default) and non-synchronous mode */
|
||||
pdata->sync_mode = true;
|
||||
if (of_property_read_bool(node, "mps,no-sync-mode"))
|
||||
pdata->sync_mode = false;
|
||||
pdata->sync_mode = !device_property_read_bool(dev, "mps,no-sync-mode");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mp3309c_probe(struct i2c_client *client)
|
||||
{
|
||||
struct mp3309c_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct device *dev = &client->dev;
|
||||
struct mp3309c_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct mp3309c_chip *chip;
|
||||
struct backlight_properties props;
|
||||
struct pwm_state pwmstate;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "failed to check i2c functionality\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
return dev_err_probe(dev, -EOPNOTSUPP, "failed to check i2c functionality\n");
|
||||
|
||||
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->dev = &client->dev;
|
||||
chip->dev = dev;
|
||||
|
||||
chip->regmap = devm_regmap_init_i2c(client, &mp3309c_regmap);
|
||||
if (IS_ERR(chip->regmap))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(chip->regmap),
|
||||
return dev_err_probe(dev, PTR_ERR(chip->regmap),
|
||||
"failed to allocate register map\n");
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
|
||||
if (!pdata) {
|
||||
pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pm3309c_parse_dt_node(chip, pdata);
|
||||
ret = mp3309c_parse_fwnode(chip, pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
chip->pdata = pdata;
|
||||
|
||||
/* Backlight properties */
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
props.brightness = pdata->default_brightness;
|
||||
props.max_brightness = pdata->max_brightness;
|
||||
props.scale = BACKLIGHT_SCALE_LINEAR;
|
||||
props.type = BACKLIGHT_RAW;
|
||||
props.power = FB_BLANK_UNBLANK;
|
||||
props.fb_blank = FB_BLANK_UNBLANK;
|
||||
chip->bl = devm_backlight_device_register(chip->dev, "mp3309c",
|
||||
chip->dev, chip,
|
||||
chip->bl = devm_backlight_device_register(dev, "mp3309c", dev, chip,
|
||||
&mp3309c_bl_ops, &props);
|
||||
if (IS_ERR(chip->bl))
|
||||
return dev_err_probe(chip->dev, PTR_ERR(chip->bl),
|
||||
return dev_err_probe(dev, PTR_ERR(chip->bl),
|
||||
"error registering backlight device\n");
|
||||
|
||||
/* In PWM dimming mode, enable pwm device */
|
||||
@ -393,10 +377,9 @@ static int mp3309c_probe(struct i2c_client *client)
|
||||
chip->pdata->default_brightness,
|
||||
chip->pdata->max_brightness);
|
||||
pwmstate.enabled = true;
|
||||
ret = pwm_apply_state(chip->pwmd, &pwmstate);
|
||||
ret = pwm_apply_might_sleep(chip->pwmd, &pwmstate);
|
||||
if (ret)
|
||||
return dev_err_probe(chip->dev, ret,
|
||||
"error setting pwm device\n");
|
||||
return dev_err_probe(dev, ret, "error setting pwm device\n");
|
||||
}
|
||||
|
||||
chip->pdata->status = FIRST_POWER_ON;
|
||||
|
@ -114,10 +114,8 @@ static int pandora_backlight_probe(struct platform_device *pdev)
|
||||
u8 r;
|
||||
|
||||
priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver private data\n");
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.max_brightness = MAX_USER_VALUE;
|
||||
|
38
include/linux/leds-expresswire.h
Normal file
38
include/linux/leds-expresswire.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Shared library for Kinetic's ExpressWire protocol.
|
||||
* This protocol works by pulsing the ExpressWire IC's control GPIO.
|
||||
* ktd2692 and ktd2801 are known to use this protocol.
|
||||
*/
|
||||
|
||||
#ifndef _LEDS_EXPRESSWIRE_H
|
||||
#define _LEDS_EXPRESSWIRE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct gpio_desc;
|
||||
|
||||
struct expresswire_timing {
|
||||
unsigned long poweroff_us;
|
||||
unsigned long detect_delay_us;
|
||||
unsigned long detect_us;
|
||||
unsigned long data_start_us;
|
||||
unsigned long end_of_data_low_us;
|
||||
unsigned long end_of_data_high_us;
|
||||
unsigned long short_bitset_us;
|
||||
unsigned long long_bitset_us;
|
||||
};
|
||||
|
||||
struct expresswire_common_props {
|
||||
struct gpio_desc *ctrl_gpio;
|
||||
struct expresswire_timing timing;
|
||||
};
|
||||
|
||||
void expresswire_power_off(struct expresswire_common_props *props);
|
||||
void expresswire_enable(struct expresswire_common_props *props);
|
||||
void expresswire_start(struct expresswire_common_props *props);
|
||||
void expresswire_end(struct expresswire_common_props *props);
|
||||
void expresswire_set_bit(struct expresswire_common_props *props, bool bit);
|
||||
void expresswire_write_u8(struct expresswire_common_props *props, u8 val);
|
||||
|
||||
#endif /* _LEDS_EXPRESSWIRE_H */
|
Loading…
Reference in New Issue
Block a user