Commit f3d8f29d authored by Linus Torvalds's avatar Linus Torvalds

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()
  ...
parents 8403ce70 b49c1cac
# 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# ...@@ -7,8 +7,8 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Technologies, Inc. WLED driver title: Qualcomm Technologies, Inc. WLED driver
maintainers: maintainers:
- Bjorn Andersson <bjorn.andersson@linaro.org> - Bjorn Andersson <andersson@kernel.org>
- Kiran Gunda <kgunda@codeaurora.org> - Kiran Gunda <quic_kgunda@quicinc.com>
description: | description: |
WLED (White Light Emitting Diode) driver is used for controlling display WLED (White Light Emitting Diode) driver is used for controlling display
......
...@@ -8039,6 +8039,13 @@ S: Maintained ...@@ -8039,6 +8039,13 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat.git
F: fs/exfat/ 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 EXT2 FILE SYSTEM
M: Jan Kara <jack@suse.com> M: Jan Kara <jack@suse.com>
L: linux-ext4@vger.kernel.org L: linux-ext4@vger.kernel.org
...@@ -12103,6 +12110,12 @@ S: Maintained ...@@ -12103,6 +12110,12 @@ S: Maintained
F: Documentation/devicetree/bindings/leds/backlight/kinetic,ktd253.yaml F: Documentation/devicetree/bindings/leds/backlight/kinetic,ktd253.yaml
F: drivers/video/backlight/ktd253-backlight.c 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 KTEST
M: Steven Rostedt <rostedt@goodmis.org> M: Steven Rostedt <rostedt@goodmis.org>
M: John Hawley <warthog9@eaglescrag.net> M: John Hawley <warthog9@eaglescrag.net>
......
...@@ -186,6 +186,10 @@ config LEDS_EL15203000 ...@@ -186,6 +186,10 @@ config LEDS_EL15203000
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called leds-el15203000. will be called leds-el15203000.
config LEDS_EXPRESSWIRE
bool
depends on GPIOLIB
config LEDS_TURRIS_OMNIA config LEDS_TURRIS_OMNIA
tristate "LED support for CZ.NIC's Turris Omnia" tristate "LED support for CZ.NIC's Turris Omnia"
depends on LEDS_CLASS_MULTICOLOR depends on LEDS_CLASS_MULTICOLOR
......
...@@ -91,6 +91,9 @@ obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o ...@@ -91,6 +91,9 @@ obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o
obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
# Kinetic ExpressWire Protocol
obj-$(CONFIG_LEDS_EXPRESSWIRE) += leds-expresswire.o
# LED SPI Drivers # LED SPI Drivers
obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o obj-$(CONFIG_LEDS_CR0014114) += leds-cr0014114.o
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
......
...@@ -23,7 +23,8 @@ config LEDS_AS3645A ...@@ -23,7 +23,8 @@ config LEDS_AS3645A
config LEDS_KTD2692 config LEDS_KTD2692
tristate "LED support for Kinetic KTD2692 flash LED controller" tristate "LED support for Kinetic KTD2692 flash LED controller"
depends on OF depends on OF
depends on GPIOLIB || COMPILE_TEST depends on GPIOLIB
select LEDS_EXPRESSWIRE
help help
This option enables support for Kinetic KTD2692 LED flash connected This option enables support for Kinetic KTD2692 LED flash connected
through ExpressWire interface. through ExpressWire interface.
......
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
* Ingi Kim <ingi2.kim@samsung.com> * Ingi Kim <ingi2.kim@samsung.com>
*/ */
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/leds-expresswire.h>
#include <linux/led-class-flash.h> #include <linux/led-class-flash.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
...@@ -37,22 +37,9 @@ ...@@ -37,22 +37,9 @@
#define KTD2692_REG_FLASH_CURRENT_BASE 0x80 #define KTD2692_REG_FLASH_CURRENT_BASE 0x80
#define KTD2692_REG_MODE_BASE 0xA0 #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 */ /* KTD2692 default length of name */
#define KTD2692_NAME_LENGTH 20 #define KTD2692_NAME_LENGTH 20
enum ktd2692_bitset {
KTD2692_LOW = 0,
KTD2692_HIGH,
};
/* Movie / Flash Mode Control */ /* Movie / Flash Mode Control */
enum ktd2692_led_mode { enum ktd2692_led_mode {
KTD2692_MODE_DISABLE = 0, /* default */ KTD2692_MODE_DISABLE = 0, /* default */
...@@ -71,7 +58,19 @@ struct ktd2692_led_config_data { ...@@ -71,7 +58,19 @@ struct ktd2692_led_config_data {
enum led_brightness max_brightness; 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 { struct ktd2692_context {
/* Common ExpressWire properties (ctrl GPIO and timing) */
struct expresswire_common_props props;
/* Related LED Flash class device */ /* Related LED Flash class device */
struct led_classdev_flash fled_cdev; struct led_classdev_flash fled_cdev;
...@@ -80,7 +79,6 @@ struct ktd2692_context { ...@@ -80,7 +79,6 @@ struct ktd2692_context {
struct regulator *regulator; struct regulator *regulator;
struct gpio_desc *aux_gpio; struct gpio_desc *aux_gpio;
struct gpio_desc *ctrl_gpio;
enum ktd2692_led_mode mode; enum ktd2692_led_mode mode;
enum led_brightness torch_brightness; enum led_brightness torch_brightness;
...@@ -92,67 +90,6 @@ static struct ktd2692_context *fled_cdev_to_led( ...@@ -92,67 +90,6 @@ static struct ktd2692_context *fled_cdev_to_led(
return container_of(fled_cdev, struct ktd2692_context, fled_cdev); 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, static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness) enum led_brightness brightness)
{ {
...@@ -163,14 +100,14 @@ static int ktd2692_led_brightness_set(struct led_classdev *led_cdev, ...@@ -163,14 +100,14 @@ static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
if (brightness == LED_OFF) { if (brightness == LED_OFF) {
led->mode = KTD2692_MODE_DISABLE; led->mode = KTD2692_MODE_DISABLE;
gpiod_direction_output(led->aux_gpio, KTD2692_LOW); gpiod_direction_output(led->aux_gpio, 0);
} else { } else {
ktd2692_expresswire_write(led, brightness | expresswire_write_u8(&led->props, brightness |
KTD2692_REG_MOVIE_CURRENT_BASE); KTD2692_REG_MOVIE_CURRENT_BASE);
led->mode = KTD2692_MODE_MOVIE; 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); mutex_unlock(&led->lock);
return 0; return 0;
...@@ -187,17 +124,17 @@ static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev, ...@@ -187,17 +124,17 @@ static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev,
if (state) { if (state) {
flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step); 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); | KTD2692_REG_FLASH_TIMEOUT_BASE);
led->mode = KTD2692_MODE_FLASH; led->mode = KTD2692_MODE_FLASH;
gpiod_direction_output(led->aux_gpio, KTD2692_HIGH); gpiod_direction_output(led->aux_gpio, 1);
} else { } else {
led->mode = KTD2692_MODE_DISABLE; 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; fled_cdev->led_cdev.brightness = LED_OFF;
led->mode = KTD2692_MODE_DISABLE; led->mode = KTD2692_MODE_DISABLE;
...@@ -247,12 +184,12 @@ static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev, ...@@ -247,12 +184,12 @@ static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev,
static void ktd2692_setup(struct ktd2692_context *led) static void ktd2692_setup(struct ktd2692_context *led)
{ {
led->mode = KTD2692_MODE_DISABLE; led->mode = KTD2692_MODE_DISABLE;
ktd2692_expresswire_reset(led); expresswire_power_off(&led->props);
gpiod_direction_output(led->aux_gpio, KTD2692_LOW); 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_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); | KTD2692_REG_FLASH_CURRENT_BASE);
} }
...@@ -277,8 +214,8 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, ...@@ -277,8 +214,8 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
if (!np) if (!np)
return -ENXIO; return -ENXIO;
led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS); led->props.ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(led->ctrl_gpio); ret = PTR_ERR_OR_ZERO(led->props.ctrl_gpio);
if (ret) if (ret)
return dev_err_probe(dev, ret, "cannot get ctrl-gpios\n"); return dev_err_probe(dev, ret, "cannot get ctrl-gpios\n");
...@@ -412,6 +349,7 @@ static struct platform_driver ktd2692_driver = { ...@@ -412,6 +349,7 @@ static struct platform_driver ktd2692_driver = {
module_platform_driver(ktd2692_driver); module_platform_driver(ktd2692_driver);
MODULE_IMPORT_NS(EXPRESSWIRE);
MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>"); MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>");
MODULE_DESCRIPTION("Kinetic KTD2692 LED driver"); MODULE_DESCRIPTION("Kinetic KTD2692 LED driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
// 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 ...@@ -183,6 +183,13 @@ config BACKLIGHT_KTD253
which is a 1-wire GPIO-controlled backlight found in some mobile which is a 1-wire GPIO-controlled backlight found in some mobile
phones. 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 config BACKLIGHT_KTZ8866
tristate "Backlight Driver for Kinetic KTZ8866" tristate "Backlight Driver for Kinetic KTZ8866"
depends on I2C depends on I2C
......
...@@ -34,6 +34,7 @@ obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o ...@@ -34,6 +34,7 @@ obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO) += ipaq_micro_bl.o obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO) += ipaq_micro_bl.o
obj-$(CONFIG_BACKLIGHT_KTD253) += ktd253-backlight.o obj-$(CONFIG_BACKLIGHT_KTD253) += ktd253-backlight.o
obj-$(CONFIG_BACKLIGHT_KTD2801) += ktd2801-backlight.o
obj-$(CONFIG_BACKLIGHT_KTZ8866) += ktz8866.o obj-$(CONFIG_BACKLIGHT_KTZ8866) += ktz8866.o
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
......
...@@ -383,10 +383,8 @@ static int as3711_backlight_probe(struct platform_device *pdev) ...@@ -383,10 +383,8 @@ static int as3711_backlight_probe(struct platform_device *pdev)
if (pdev->dev.parent->of_node) { if (pdev->dev.parent->of_node) {
ret = as3711_backlight_parse_dt(&pdev->dev); ret = as3711_backlight_parse_dt(&pdev->dev);
if (ret < 0) { if (ret < 0)
dev_err(&pdev->dev, "DT parsing failed: %d\n", ret); return dev_err_probe(&pdev->dev, ret, "DT parsing failed\n");
return ret;
}
} }
if (!pdata->su1_fb && !pdata->su2_fb) { if (!pdata->su1_fb && !pdata->su2_fb) {
......
...@@ -119,7 +119,6 @@ static int bd6107_probe(struct i2c_client *client) ...@@ -119,7 +119,6 @@ static int bd6107_probe(struct i2c_client *client)
struct backlight_device *backlight; struct backlight_device *backlight;
struct backlight_properties props; struct backlight_properties props;
struct bd6107 *bd; struct bd6107 *bd;
int ret;
if (pdata == NULL) { if (pdata == NULL) {
dev_err(&client->dev, "No platform data\n"); dev_err(&client->dev, "No platform data\n");
...@@ -147,11 +146,9 @@ static int bd6107_probe(struct i2c_client *client) ...@@ -147,11 +146,9 @@ static int bd6107_probe(struct i2c_client *client)
* the reset. * the reset.
*/ */
bd->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); bd->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(bd->reset)) { if (IS_ERR(bd->reset))
dev_err(&client->dev, "unable to request reset GPIO\n"); return dev_err_probe(&client->dev, PTR_ERR(bd->reset),
ret = PTR_ERR(bd->reset); "unable to request reset GPIO\n");
return ret;
}
memset(&props, 0, sizeof(props)); memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
......
...@@ -117,6 +117,7 @@ static int da9052_backlight_probe(struct platform_device *pdev) ...@@ -117,6 +117,7 @@ static int da9052_backlight_probe(struct platform_device *pdev)
wleds->led_reg = platform_get_device_id(pdev)->driver_data; wleds->led_reg = platform_get_device_id(pdev)->driver_data;
wleds->state = DA9052_WLEDS_OFF; wleds->state = DA9052_WLEDS_OFF;
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
props.max_brightness = DA9052_MAX_BRIGHTNESS; props.max_brightness = DA9052_MAX_BRIGHTNESS;
......
...@@ -64,13 +64,9 @@ static int gpio_backlight_probe(struct platform_device *pdev) ...@@ -64,13 +64,9 @@ static int gpio_backlight_probe(struct platform_device *pdev)
def_value = device_property_read_bool(dev, "default-on"); def_value = device_property_read_bool(dev, "default-on");
gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS); gbl->gpiod = devm_gpiod_get(dev, NULL, GPIOD_ASIS);
if (IS_ERR(gbl->gpiod)) { if (IS_ERR(gbl->gpiod))
ret = PTR_ERR(gbl->gpiod); return dev_err_probe(dev, PTR_ERR(gbl->gpiod),
if (ret != -EPROBE_DEFER) "The gpios parameter is missing or invalid\n");
dev_err(dev,
"Error: The gpios parameter is missing or invalid.\n");
return ret;
}
memset(&props, 0, sizeof(props)); memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
......
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/lcd.h> #include <linux/lcd.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/property.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#define HX8357_NUM_IM_PINS 3 #define HX8357_NUM_IM_PINS 3
...@@ -564,41 +564,28 @@ static struct lcd_ops hx8357_ops = { ...@@ -564,41 +564,28 @@ static struct lcd_ops hx8357_ops = {
.get_power = hx8357_get_power, .get_power = hx8357_get_power,
}; };
static const struct of_device_id hx8357_dt_ids[] = { typedef int (*hx8357_init_fn)(struct lcd_device *);
{
.compatible = "himax,hx8357",
.data = hx8357_lcd_init,
},
{
.compatible = "himax,hx8369",
.data = hx8369_lcd_init,
},
{},
};
MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
static int hx8357_probe(struct spi_device *spi) static int hx8357_probe(struct spi_device *spi)
{ {
struct device *dev = &spi->dev; struct device *dev = &spi->dev;
struct lcd_device *lcdev; struct lcd_device *lcdev;
struct hx8357_data *lcd; struct hx8357_data *lcd;
const struct of_device_id *match; hx8357_init_fn init_fn;
int i, ret; int i, ret;
lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); lcd = devm_kzalloc(dev, sizeof(*lcd), GFP_KERNEL);
if (!lcd) if (!lcd)
return -ENOMEM; return -ENOMEM;
ret = spi_setup(spi); ret = spi_setup(spi);
if (ret < 0) { if (ret < 0)
dev_err(&spi->dev, "SPI setup failed.\n"); return dev_err_probe(dev, ret, "SPI setup failed.\n");
return ret;
}
lcd->spi = spi; lcd->spi = spi;
match = of_match_device(hx8357_dt_ids, &spi->dev); init_fn = device_get_match_data(dev);
if (!match || !match->data) if (!init_fn)
return -EINVAL; return -EINVAL;
lcd->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); lcd->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
...@@ -609,14 +596,15 @@ static int hx8357_probe(struct spi_device *spi) ...@@ -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); lcd->im_pins = devm_gpiod_get_array_optional(dev, "im", GPIOD_OUT_LOW);
if (IS_ERR(lcd->im_pins)) if (IS_ERR(lcd->im_pins))
return dev_err_probe(dev, PTR_ERR(lcd->im_pins), "failed to request im GPIOs\n"); 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) if (lcd->im_pins) {
return dev_err_probe(dev, -EINVAL, "not enough im GPIOs\n"); 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++) for (i = 0; i < HX8357_NUM_IM_PINS; i++)
gpiod_set_consumer_name(lcd->im_pins->desc[i], "im_pins"); gpiod_set_consumer_name(lcd->im_pins->desc[i], "im_pins");
}
lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd, lcdev = devm_lcd_device_register(dev, "mxsfb", dev, lcd, &hx8357_ops);
&hx8357_ops);
if (IS_ERR(lcdev)) { if (IS_ERR(lcdev)) {
ret = PTR_ERR(lcdev); ret = PTR_ERR(lcdev);
return ret; return ret;
...@@ -625,17 +613,28 @@ static int hx8357_probe(struct spi_device *spi) ...@@ -625,17 +613,28 @@ static int hx8357_probe(struct spi_device *spi)
hx8357_lcd_reset(lcdev); hx8357_lcd_reset(lcdev);
ret = ((int (*)(struct lcd_device *))match->data)(lcdev); ret = init_fn(lcdev);
if (ret) { if (ret)
dev_err(&spi->dev, "Couldn't initialize panel\n"); return dev_err_probe(dev, ret, "Couldn't initialize panel\n");
return ret;
}
dev_info(&spi->dev, "Panel probed\n"); dev_info(dev, "Panel probed\n");
return 0; 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 = { static struct spi_driver hx8357_driver = {
.probe = hx8357_probe, .probe = hx8357_probe,
.driver = { .driver = {
......
// 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) ...@@ -97,20 +97,20 @@ static void ktz8866_init(struct ktz8866 *ktz)
{ {
unsigned int val = 0; 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); ktz8866_write(ktz, BL_EN, BIT(val) - 1);
else else
/* Enable all 6 current sinks if the number of current sinks isn't specified. */ /* Enable all 6 current sinks if the number of current sinks isn't specified. */
ktz8866_write(ktz, BL_EN, BIT(6) - 1); 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) if (val <= 128)
ktz8866_write(ktz, BL_CFG2, BIT(7) | (ilog2(val) << 3) | PWM_HYST); ktz8866_write(ktz, BL_CFG2, BIT(7) | (ilog2(val) << 3) | PWM_HYST);
else else
ktz8866_write(ktz, BL_CFG2, BIT(7) | ((5 + val / 64) << 3) | PWM_HYST); 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) if (val == 0)
ktz8866_write(ktz, BL_DIMMING, 0); ktz8866_write(ktz, BL_DIMMING, 0);
else { else {
......
...@@ -179,34 +179,28 @@ static int l4f00242t03_probe(struct spi_device *spi) ...@@ -179,34 +179,28 @@ static int l4f00242t03_probe(struct spi_device *spi)
priv->spi = spi; priv->spi = spi;
priv->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH); priv->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(priv->reset)) { if (IS_ERR(priv->reset))
dev_err(&spi->dev, return dev_err_probe(&spi->dev, PTR_ERR(priv->reset),
"Unable to get the lcd l4f00242t03 reset gpio.\n"); "Unable to get the lcd l4f00242t03 reset gpio.\n");
return PTR_ERR(priv->reset);
}
gpiod_set_consumer_name(priv->reset, "lcd l4f00242t03 reset"); gpiod_set_consumer_name(priv->reset, "lcd l4f00242t03 reset");
priv->enable = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW); priv->enable = devm_gpiod_get(&spi->dev, "enable", GPIOD_OUT_LOW);
if (IS_ERR(priv->enable)) { if (IS_ERR(priv->enable))
dev_err(&spi->dev, return dev_err_probe(&spi->dev, PTR_ERR(priv->enable),
"Unable to get the lcd l4f00242t03 data en gpio.\n"); "Unable to get the lcd l4f00242t03 data en gpio.\n");
return PTR_ERR(priv->enable);
}
gpiod_set_consumer_name(priv->enable, "lcd l4f00242t03 data enable"); gpiod_set_consumer_name(priv->enable, "lcd l4f00242t03 data enable");
priv->io_reg = devm_regulator_get(&spi->dev, "vdd"); priv->io_reg = devm_regulator_get(&spi->dev, "vdd");
if (IS_ERR(priv->io_reg)) { if (IS_ERR(priv->io_reg))
dev_err(&spi->dev, "%s: Unable to get the IO regulator\n", return dev_err_probe(&spi->dev, PTR_ERR(priv->io_reg),
__func__); "%s: Unable to get the IO regulator\n",
return PTR_ERR(priv->io_reg); __func__);
}
priv->core_reg = devm_regulator_get(&spi->dev, "vcore"); priv->core_reg = devm_regulator_get(&spi->dev, "vcore");
if (IS_ERR(priv->core_reg)) { if (IS_ERR(priv->core_reg))
dev_err(&spi->dev, "%s: Unable to get the core regulator\n", return dev_err_probe(&spi->dev, PTR_ERR(priv->core_reg),
__func__); "%s: Unable to get the core regulator\n",
return PTR_ERR(priv->core_reg); __func__);
}
priv->ld = devm_lcd_device_register(&spi->dev, "l4f00242t03", &spi->dev, priv->ld = devm_lcd_device_register(&spi->dev, "l4f00242t03", &spi->dev,
priv, &l4f_ops); priv, &l4f_ops);
......
...@@ -189,10 +189,11 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl) ...@@ -189,10 +189,11 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
int ret; int ret;
struct lm3630a_chip *pchip = bl_get_data(bl); struct lm3630a_chip *pchip = bl_get_data(bl);
enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
int brightness = backlight_get_brightness(bl);
/* pwm control */ /* pwm control */
if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) 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); bl->props.max_brightness);
/* disable sleep */ /* disable sleep */
...@@ -201,9 +202,9 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl) ...@@ -201,9 +202,9 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl)
goto out_i2c_err; goto out_i2c_err;
usleep_range(1000, 2000); usleep_range(1000, 2000);
/* minimum brightness is 0x04 */ /* 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 */ /* turn the string off */
ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0); ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0);
else else
...@@ -233,7 +234,7 @@ static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) ...@@ -233,7 +234,7 @@ static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
if (rval < 0) if (rval < 0)
goto out_i2c_err; goto out_i2c_err;
brightness |= rval; brightness |= rval;
goto out; return brightness;
} }
/* disable sleep */ /* disable sleep */
...@@ -244,11 +245,8 @@ static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) ...@@ -244,11 +245,8 @@ static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)
rval = lm3630a_read(pchip, REG_BRT_A); rval = lm3630a_read(pchip, REG_BRT_A);
if (rval < 0) if (rval < 0)
goto out_i2c_err; goto out_i2c_err;
brightness = rval; return rval;
out:
bl->props.brightness = brightness;
return bl->props.brightness;
out_i2c_err: out_i2c_err:
dev_err(pchip->dev, "i2c failed to access register\n"); dev_err(pchip->dev, "i2c failed to access register\n");
return 0; return 0;
...@@ -266,10 +264,11 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl) ...@@ -266,10 +264,11 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
int ret; int ret;
struct lm3630a_chip *pchip = bl_get_data(bl); struct lm3630a_chip *pchip = bl_get_data(bl);
enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
int brightness = backlight_get_brightness(bl);
/* pwm control */ /* pwm control */
if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) 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); bl->props.max_brightness);
/* disable sleep */ /* disable sleep */
...@@ -278,9 +277,9 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl) ...@@ -278,9 +277,9 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl)
goto out_i2c_err; goto out_i2c_err;
usleep_range(1000, 2000); usleep_range(1000, 2000);
/* minimum brightness is 0x04 */ /* 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 */ /* turn the string off */
ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0); ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0);
else else
...@@ -310,7 +309,7 @@ static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) ...@@ -310,7 +309,7 @@ static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
if (rval < 0) if (rval < 0)
goto out_i2c_err; goto out_i2c_err;
brightness |= rval; brightness |= rval;
goto out; return brightness;
} }
/* disable sleep */ /* disable sleep */
...@@ -321,11 +320,8 @@ static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) ...@@ -321,11 +320,8 @@ static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)
rval = lm3630a_read(pchip, REG_BRT_B); rval = lm3630a_read(pchip, REG_BRT_B);
if (rval < 0) if (rval < 0)
goto out_i2c_err; goto out_i2c_err;
brightness = rval; return rval;
out:
bl->props.brightness = brightness;
return bl->props.brightness;
out_i2c_err: out_i2c_err:
dev_err(pchip->dev, "i2c failed to access register\n"); dev_err(pchip->dev, "i2c failed to access register\n");
return 0; return 0;
...@@ -343,6 +339,7 @@ static int lm3630a_backlight_register(struct lm3630a_chip *pchip) ...@@ -343,6 +339,7 @@ static int lm3630a_backlight_register(struct lm3630a_chip *pchip)
struct backlight_properties props; struct backlight_properties props;
const char *label; const char *label;
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) { if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {
props.brightness = pdata->leda_init_brt; props.brightness = pdata->leda_init_brt;
...@@ -543,10 +540,8 @@ static int lm3630a_probe(struct i2c_client *client) ...@@ -543,10 +540,8 @@ static int lm3630a_probe(struct i2c_client *client)
pchip->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", pchip->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
GPIOD_OUT_HIGH); GPIOD_OUT_HIGH);
if (IS_ERR(pchip->enable_gpio)) { if (IS_ERR(pchip->enable_gpio))
rval = PTR_ERR(pchip->enable_gpio); return PTR_ERR(pchip->enable_gpio);
return rval;
}
/* chip initialize */ /* chip initialize */
rval = lm3630a_chip_init(pchip); rval = lm3630a_chip_init(pchip);
...@@ -563,10 +558,9 @@ static int lm3630a_probe(struct i2c_client *client) ...@@ -563,10 +558,9 @@ static int lm3630a_probe(struct i2c_client *client)
/* pwm */ /* pwm */
if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) { if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) {
pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm"); pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm");
if (IS_ERR(pchip->pwmd)) { if (IS_ERR(pchip->pwmd))
dev_err(&client->dev, "fail : get pwm device\n"); return dev_err_probe(&client->dev, PTR_ERR(pchip->pwmd),
return PTR_ERR(pchip->pwmd); "fail : get pwm device\n");
}
pwm_init_state(pchip->pwmd, &pchip->pwmd_state); pwm_init_state(pchip->pwmd, &pchip->pwmd_state);
} }
......
...@@ -338,6 +338,7 @@ static int lm3639_probe(struct i2c_client *client) ...@@ -338,6 +338,7 @@ static int lm3639_probe(struct i2c_client *client)
} }
/* backlight */ /* backlight */
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
props.brightness = pdata->init_brt_led; props.brightness = pdata->init_brt_led;
props.max_brightness = pdata->max_brt_led; props.max_brightness = pdata->max_brt_led;
......
...@@ -191,6 +191,7 @@ static int lp8788_backlight_register(struct lp8788_bl *bl) ...@@ -191,6 +191,7 @@ static int lp8788_backlight_register(struct lp8788_bl *bl)
int init_brt; int init_brt;
char *name; char *name;
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_PLATFORM; props.type = BACKLIGHT_PLATFORM;
props.max_brightness = MAX_BRIGHTNESS; props.max_brightness = MAX_BRIGHTNESS;
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/pwm.h> #include <linux/pwm.h>
#include <linux/regmap.h> #include <linux/regmap.h>
...@@ -131,7 +133,7 @@ static int mp3309c_bl_update_status(struct backlight_device *bl) ...@@ -131,7 +133,7 @@ static int mp3309c_bl_update_status(struct backlight_device *bl)
chip->pdata->levels[brightness], chip->pdata->levels[brightness],
chip->pdata->levels[chip->pdata->max_brightness]); chip->pdata->levels[chip->pdata->max_brightness]);
pwmstate.enabled = true; pwmstate.enabled = true;
ret = pwm_apply_state(chip->pwmd, &pwmstate); ret = pwm_apply_might_sleep(chip->pwmd, &pwmstate);
if (ret) if (ret)
return ret; return ret;
...@@ -199,20 +201,15 @@ static const struct backlight_ops mp3309c_bl_ops = { ...@@ -199,20 +201,15 @@ static const struct backlight_ops mp3309c_bl_ops = {
.update_status = mp3309c_bl_update_status, .update_status = mp3309c_bl_update_status,
}; };
static int pm3309c_parse_dt_node(struct mp3309c_chip *chip, static int mp3309c_parse_fwnode(struct mp3309c_chip *chip,
struct mp3309c_platform_data *pdata) 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; int ret, i;
unsigned int num_levels, tmp_value; unsigned int num_levels, tmp_value;
struct device *dev = chip->dev;
if (!node) { if (!dev_fwnode(dev))
dev_err(chip->dev, "failed to get DT node\n"); return dev_err_probe(dev, -ENODEV, "failed to get firmware node\n");
return -ENODEV;
}
/* /*
* Dimming mode: the MP3309C provides two dimming control mode: * Dimming mode: the MP3309C provides two dimming control mode:
...@@ -224,12 +221,10 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip, ...@@ -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. * found in the backlight node, the mode switches to PWM mode.
*/ */
pdata->dimming_mode = DIMMING_ANALOG_I2C; pdata->dimming_mode = DIMMING_ANALOG_I2C;
prop_pwms = of_find_property(node, "pwms", &length); if (device_property_present(dev, "pwms")) {
if (prop_pwms) { chip->pwmd = devm_pwm_get(dev, NULL);
chip->pwmd = devm_pwm_get(chip->dev, NULL);
if (IS_ERR(chip->pwmd)) if (IS_ERR(chip->pwmd))
return dev_err_probe(chip->dev, PTR_ERR(chip->pwmd), return dev_err_probe(dev, PTR_ERR(chip->pwmd), "error getting pwm data\n");
"error getting pwm data\n");
pdata->dimming_mode = DIMMING_PWM; pdata->dimming_mode = DIMMING_PWM;
pwm_apply_args(chip->pwmd); pwm_apply_args(chip->pwmd);
} }
...@@ -247,21 +242,17 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip, ...@@ -247,21 +242,17 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
num_levels = ANALOG_I2C_NUM_LEVELS; num_levels = ANALOG_I2C_NUM_LEVELS;
/* Enable GPIO used in I2C dimming mode only */ /* Enable GPIO used in I2C dimming mode only */
chip->enable_gpio = devm_gpiod_get(chip->dev, "enable", chip->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
GPIOD_OUT_HIGH);
if (IS_ERR(chip->enable_gpio)) if (IS_ERR(chip->enable_gpio))
return dev_err_probe(chip->dev, return dev_err_probe(dev, PTR_ERR(chip->enable_gpio),
PTR_ERR(chip->enable_gpio),
"error getting enable gpio\n"); "error getting enable gpio\n");
} else { } else {
/* /*
* PWM control mode: check for brightness level in DT * PWM control mode: check for brightness level in DT
*/ */
prop_levels = of_find_property(node, "brightness-levels", if (device_property_present(dev, "brightness-levels")) {
&length);
if (prop_levels) {
/* Read brightness levels from DT */ /* Read brightness levels from DT */
num_levels = length / sizeof(u32); num_levels = device_property_count_u32(dev, "brightness-levels");
if (num_levels < 2) if (num_levels < 2)
return -EINVAL; return -EINVAL;
} else { } else {
...@@ -271,14 +262,12 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip, ...@@ -271,14 +262,12 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
} }
/* Fill brightness levels array */ /* Fill brightness levels array */
pdata->levels = devm_kcalloc(chip->dev, num_levels, pdata->levels = devm_kcalloc(dev, num_levels, sizeof(*pdata->levels), GFP_KERNEL);
sizeof(*pdata->levels), GFP_KERNEL);
if (!pdata->levels) if (!pdata->levels)
return -ENOMEM; return -ENOMEM;
if (prop_levels) { if (device_property_present(dev, "brightness-levels")) {
ret = of_property_read_u32_array(node, "brightness-levels", ret = device_property_read_u32_array(dev, "brightness-levels",
pdata->levels, pdata->levels, num_levels);
num_levels);
if (ret < 0) if (ret < 0)
return ret; return ret;
} else { } else {
...@@ -288,13 +277,11 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip, ...@@ -288,13 +277,11 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
pdata->max_brightness = num_levels - 1; pdata->max_brightness = num_levels - 1;
ret = of_property_read_u32(node, "default-brightness", ret = device_property_read_u32(dev, "default-brightness", &pdata->default_brightness);
&pdata->default_brightness);
if (ret) if (ret)
pdata->default_brightness = pdata->max_brightness; pdata->default_brightness = pdata->max_brightness;
if (pdata->default_brightness > pdata->max_brightness) { if (pdata->default_brightness > pdata->max_brightness) {
dev_err(chip->dev, dev_err_probe(dev, -ERANGE, "default brightness exceeds max brightness\n");
"default brightness exceeds max brightness\n");
pdata->default_brightness = pdata->max_brightness; pdata->default_brightness = pdata->max_brightness;
} }
...@@ -310,8 +297,8 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip, ...@@ -310,8 +297,8 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
* If missing, the default value for OVP is 35.5V * If missing, the default value for OVP is 35.5V
*/ */
pdata->over_voltage_protection = REG_I2C_1_OVP1; pdata->over_voltage_protection = REG_I2C_1_OVP1;
if (!of_property_read_u32(node, "mps,overvoltage-protection-microvolt", ret = device_property_read_u32(dev, "mps,overvoltage-protection-microvolt", &tmp_value);
&tmp_value)) { if (!ret) {
switch (tmp_value) { switch (tmp_value) {
case 13500000: case 13500000:
pdata->over_voltage_protection = 0x00; pdata->over_voltage_protection = 0x00;
...@@ -328,62 +315,59 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip, ...@@ -328,62 +315,59 @@ static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
} }
/* Synchronous (default) and non-synchronous mode */ /* Synchronous (default) and non-synchronous mode */
pdata->sync_mode = true; pdata->sync_mode = !device_property_read_bool(dev, "mps,no-sync-mode");
if (of_property_read_bool(node, "mps,no-sync-mode"))
pdata->sync_mode = false;
return 0; return 0;
} }
static int mp3309c_probe(struct i2c_client *client) 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 mp3309c_chip *chip;
struct backlight_properties props; struct backlight_properties props;
struct pwm_state pwmstate; struct pwm_state pwmstate;
int ret; int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
dev_err(&client->dev, "failed to check i2c functionality\n"); return dev_err_probe(dev, -EOPNOTSUPP, "failed to check i2c functionality\n");
return -EOPNOTSUPP;
}
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip) if (!chip)
return -ENOMEM; return -ENOMEM;
chip->dev = &client->dev; chip->dev = dev;
chip->regmap = devm_regmap_init_i2c(client, &mp3309c_regmap); chip->regmap = devm_regmap_init_i2c(client, &mp3309c_regmap);
if (IS_ERR(chip->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"); "failed to allocate register map\n");
i2c_set_clientdata(client, chip); i2c_set_clientdata(client, chip);
if (!pdata) { if (!pdata) {
pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
return -ENOMEM; return -ENOMEM;
ret = pm3309c_parse_dt_node(chip, pdata); ret = mp3309c_parse_fwnode(chip, pdata);
if (ret) if (ret)
return ret; return ret;
} }
chip->pdata = pdata; chip->pdata = pdata;
/* Backlight properties */ /* Backlight properties */
memset(&props, 0, sizeof(struct backlight_properties));
props.brightness = pdata->default_brightness; props.brightness = pdata->default_brightness;
props.max_brightness = pdata->max_brightness; props.max_brightness = pdata->max_brightness;
props.scale = BACKLIGHT_SCALE_LINEAR; props.scale = BACKLIGHT_SCALE_LINEAR;
props.type = BACKLIGHT_RAW; props.type = BACKLIGHT_RAW;
props.power = FB_BLANK_UNBLANK; props.power = FB_BLANK_UNBLANK;
props.fb_blank = FB_BLANK_UNBLANK; props.fb_blank = FB_BLANK_UNBLANK;
chip->bl = devm_backlight_device_register(chip->dev, "mp3309c", chip->bl = devm_backlight_device_register(dev, "mp3309c", dev, chip,
chip->dev, chip,
&mp3309c_bl_ops, &props); &mp3309c_bl_ops, &props);
if (IS_ERR(chip->bl)) 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"); "error registering backlight device\n");
/* In PWM dimming mode, enable pwm device */ /* In PWM dimming mode, enable pwm device */
...@@ -393,10 +377,9 @@ static int mp3309c_probe(struct i2c_client *client) ...@@ -393,10 +377,9 @@ static int mp3309c_probe(struct i2c_client *client)
chip->pdata->default_brightness, chip->pdata->default_brightness,
chip->pdata->max_brightness); chip->pdata->max_brightness);
pwmstate.enabled = true; pwmstate.enabled = true;
ret = pwm_apply_state(chip->pwmd, &pwmstate); ret = pwm_apply_might_sleep(chip->pwmd, &pwmstate);
if (ret) if (ret)
return dev_err_probe(chip->dev, ret, return dev_err_probe(dev, ret, "error setting pwm device\n");
"error setting pwm device\n");
} }
chip->pdata->status = FIRST_POWER_ON; chip->pdata->status = FIRST_POWER_ON;
......
...@@ -114,10 +114,8 @@ static int pandora_backlight_probe(struct platform_device *pdev) ...@@ -114,10 +114,8 @@ static int pandora_backlight_probe(struct platform_device *pdev)
u8 r; u8 r;
priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) { if (!priv)
dev_err(&pdev->dev, "failed to allocate driver private data\n");
return -ENOMEM; return -ENOMEM;
}
memset(&props, 0, sizeof(props)); memset(&props, 0, sizeof(props));
props.max_brightness = MAX_USER_VALUE; props.max_brightness = MAX_USER_VALUE;
......
/* 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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment