- 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:
Linus Torvalds 2024-03-14 10:35:46 -07:00
commit f3d8f29d1f
24 changed files with 461 additions and 248 deletions

View File

@ -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>;
};

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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");

View 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);

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 = {

View 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");

View File

@ -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 {

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View 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 */