- Core Frameworks
- Provide helpers to enable/disable backlight - Provide standard and devres versions OF find helpers - New Drivers - Add support for the Zodiac Inflight Innovations RAVE Supervisory Processor - New Functionality - Allow pwm-on/pwm-off delay to be specified via DT - Bug Fixes - Fix ordering of the power {en,dis}able and PWM {en,dis}able signals - Fix Device Tree node look-up -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAlsecEYACgkQUa+KL4f8 d2FGhA/+K+4o6WmyNxcQ2NZdZ0XZecFJv+iE73GHl2YYQH5dW6r98BmWa8Blbfdf Ik3Q9cUAcsB9P5OMQrrTC0vpoFbvP/0aNhd+essIAx+mQGQbr73uoDMTgzyD9y9s lqTXBfbvEP5AUwyLWmmLK0LwaU4LFrRF2q2lMwIqy9Cklogl6Xy+bNToq+NHkpvW nPkNiZfy3afDSSycqiUgPRbpQT1Yw2+BswSKWybI8HSkSJozNEZM8GydJmRSeNPD VvQh7j3/EHhZ1EyaBKc1xLYDJ0OKgbXSWuXUxIRCGlaQCVazCAONu4KDBVeYWmdB khqJRobWbNrGeo2zvAOuw0aYf0mpc5HMTzQAQkjhvFTEbgoyc/di1oYKClfT3eke xPq1L5lEl4uGU+CRHvC9eiju1vLOiFX8aFvnJInNacooWdCJQmKurl8FwyiKnAWT w0GExtT6CHw2N3OIKk3qnymlGpUJ0DCwxlOVK6m69nR5dhUq83KPpbALA4Bz6xLU BYoHxa46cqVmv0i2zRyL+ANsk47ayLG48KLuLg5evRCbCP2IomLqBgQ06PteRVOf mNvJtM461J+1MRh18G2g5OfYsHcIGrvG5scEUvZJiNYimSCHLcFPrO/tgYV4fgST Raqbi/zcLbhKrq+GxKUqufDxvLcwmpNQbibluYWu9fBaAR1cJ3c= =hWye -----END PGP SIGNATURE----- Merge tag 'backlight-next-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight Pull backlight updates from Lee Jones: "Core Frameworks - Provide helpers to enable/disable backlight - Provide standard and devres versions OF find helpers New Drivers: - Add support for the Zodiac Inflight Innovations RAVE Supervisory Processor New Functionality: - Allow pwm-on/pwm-off delay to be specified via DT Bug Fixes: - Fix ordering of the power {en,dis}able and PWM {en,dis}able signals - Fix Device Tree node look-up" * tag 'backlight-next-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight: backlight: as3711_bl: Fix Device Tree node leaks backlight: tps65217_bl: Fix Device Tree node lookup backlight: max8925_bl: Fix Device Tree node lookup backlight: as3711_bl: Fix Device Tree node lookup MAINTAINERS: Add dri-devel for backlight subsystem patches backlight: Nuke BL_CORE_DRIVER1 staging: fbtft: Stop using BL_CORE_DRIVER1 backlight: pandora: Stop using BL_CORE_DRIVER1 backlight: generic-bl: Remove DRIVER1 state backlight: Nuke unused backlight.props.state states backlight: otm3225a: Add support for ORISE OTM3225A LCD SoC backlight: pwm_bl: Don't use GPIOF_* with gpiod_get_direction pwm-backlight: Add support for PWM delays proprieties. dt-bindings: pwm-backlight: Add PWM delay proprieties. pwm-backlight: Enable/disable the PWM before/after LCD enable toggle. dt-bindings: backlight: Add binding for RAVE SP backlight driver backlight: Add RAVE SP backlight driver
This commit is contained in:
commit
0f105cf4f6
|
@ -17,6 +17,10 @@ Optional properties:
|
||||||
"pwms" property (see PWM binding[0])
|
"pwms" property (see PWM binding[0])
|
||||||
- enable-gpios: contains a single GPIO specifier for the GPIO which enables
|
- enable-gpios: contains a single GPIO specifier for the GPIO which enables
|
||||||
and disables the backlight (see GPIO binding[1])
|
and disables the backlight (see GPIO binding[1])
|
||||||
|
- post-pwm-on-delay-ms: Delay in ms between setting an initial (non-zero) PWM
|
||||||
|
and enabling the backlight using GPIO.
|
||||||
|
- pwm-off-delay-ms: Delay in ms between disabling the backlight using GPIO
|
||||||
|
and setting PWM value to 0.
|
||||||
|
|
||||||
[0]: Documentation/devicetree/bindings/pwm/pwm.txt
|
[0]: Documentation/devicetree/bindings/pwm/pwm.txt
|
||||||
[1]: Documentation/devicetree/bindings/gpio/gpio.txt
|
[1]: Documentation/devicetree/bindings/gpio/gpio.txt
|
||||||
|
@ -32,4 +36,6 @@ Example:
|
||||||
|
|
||||||
power-supply = <&vdd_bl_reg>;
|
power-supply = <&vdd_bl_reg>;
|
||||||
enable-gpios = <&gpio 58 0>;
|
enable-gpios = <&gpio 58 0>;
|
||||||
|
post-pwm-on-delay-ms = <10>;
|
||||||
|
pwm-off-delay-ms = <10>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
Zodiac Inflight Innovations RAVE Supervisory Processor Backlight Bindings
|
||||||
|
|
||||||
|
RAVE SP backlight device is a "MFD cell" device corresponding to
|
||||||
|
backlight functionality of RAVE Supervisory Processor. It is expected
|
||||||
|
that its Device Tree node is specified as a child of the node
|
||||||
|
corresponding to the parent RAVE SP device (as documented in
|
||||||
|
Documentation/devicetree/bindings/mfd/zii,rave-sp.txt)
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible: Should be "zii,rave-sp-backlight"
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
rave-sp {
|
||||||
|
compatible = "zii,rave-sp-rdu1";
|
||||||
|
current-speed = <38400>;
|
||||||
|
|
||||||
|
backlight {
|
||||||
|
compatible = "zii,rave-sp-backlight";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -2606,6 +2606,7 @@ BACKLIGHT CLASS/SUBSYSTEM
|
||||||
M: Lee Jones <lee.jones@linaro.org>
|
M: Lee Jones <lee.jones@linaro.org>
|
||||||
M: Daniel Thompson <daniel.thompson@linaro.org>
|
M: Daniel Thompson <daniel.thompson@linaro.org>
|
||||||
M: Jingoo Han <jingoohan1@gmail.com>
|
M: Jingoo Han <jingoohan1@gmail.com>
|
||||||
|
L: dri-devel@lists.freedesktop.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/video/backlight/
|
F: drivers/video/backlight/
|
||||||
|
|
|
@ -246,7 +246,7 @@ static int fbtft_request_gpios_dt(struct fbtft_par *par)
|
||||||
static int fbtft_backlight_update_status(struct backlight_device *bd)
|
static int fbtft_backlight_update_status(struct backlight_device *bd)
|
||||||
{
|
{
|
||||||
struct fbtft_par *par = bl_get_data(bd);
|
struct fbtft_par *par = bl_get_data(bd);
|
||||||
bool polarity = !!(bd->props.state & BL_CORE_DRIVER1);
|
bool polarity = par->polarity;
|
||||||
|
|
||||||
fbtft_par_dbg(DEBUG_BACKLIGHT, par,
|
fbtft_par_dbg(DEBUG_BACKLIGHT, par,
|
||||||
"%s: polarity=%d, power=%d, fb_blank=%d\n",
|
"%s: polarity=%d, power=%d, fb_blank=%d\n",
|
||||||
|
@ -296,7 +296,7 @@ void fbtft_register_backlight(struct fbtft_par *par)
|
||||||
/* Assume backlight is off, get polarity from current state of pin */
|
/* Assume backlight is off, get polarity from current state of pin */
|
||||||
bl_props.power = FB_BLANK_POWERDOWN;
|
bl_props.power = FB_BLANK_POWERDOWN;
|
||||||
if (!gpio_get_value(par->gpio.led[0]))
|
if (!gpio_get_value(par->gpio.led[0]))
|
||||||
bl_props.state |= BL_CORE_DRIVER1;
|
par->polarity = true;
|
||||||
|
|
||||||
bd = backlight_device_register(dev_driver_string(par->info->device),
|
bd = backlight_device_register(dev_driver_string(par->info->device),
|
||||||
par->info->device, par,
|
par->info->device, par,
|
||||||
|
|
|
@ -229,6 +229,7 @@ struct fbtft_par {
|
||||||
ktime_t update_time;
|
ktime_t update_time;
|
||||||
bool bgr;
|
bool bgr;
|
||||||
void *extra;
|
void *extra;
|
||||||
|
bool polarity;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
|
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
|
||||||
|
|
|
@ -150,6 +150,13 @@ config LCD_HX8357
|
||||||
If you have a HX-8357 LCD panel, say Y to enable its LCD control
|
If you have a HX-8357 LCD panel, say Y to enable its LCD control
|
||||||
driver.
|
driver.
|
||||||
|
|
||||||
|
config LCD_OTM3225A
|
||||||
|
tristate "ORISE Technology OTM3225A support"
|
||||||
|
depends on SPI
|
||||||
|
help
|
||||||
|
If you have a panel based on the OTM3225A controller
|
||||||
|
chip then say y to include a driver for it.
|
||||||
|
|
||||||
endif # LCD_CLASS_DEVICE
|
endif # LCD_CLASS_DEVICE
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -467,6 +474,12 @@ config BACKLIGHT_ARCXCNN
|
||||||
If you have an ARCxCnnnn family backlight say Y to enable
|
If you have an ARCxCnnnn family backlight say Y to enable
|
||||||
the backlight driver.
|
the backlight driver.
|
||||||
|
|
||||||
|
config BACKLIGHT_RAVE_SP
|
||||||
|
tristate "RAVE SP Backlight driver"
|
||||||
|
depends on RAVE_SP_CORE
|
||||||
|
help
|
||||||
|
Support for backlight control on RAVE SP device.
|
||||||
|
|
||||||
endif # BACKLIGHT_CLASS_DEVICE
|
endif # BACKLIGHT_CLASS_DEVICE
|
||||||
|
|
||||||
endif # BACKLIGHT_LCD_SUPPORT
|
endif # BACKLIGHT_LCD_SUPPORT
|
||||||
|
|
|
@ -13,6 +13,7 @@ obj-$(CONFIG_LCD_LD9040) += ld9040.o
|
||||||
obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o
|
obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o
|
||||||
obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o
|
obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o
|
||||||
obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
|
obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
|
||||||
|
obj-$(CONFIG_LCD_OTM3225A) += otm3225a.o
|
||||||
obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
|
obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
|
||||||
obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
|
obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
|
||||||
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
|
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
|
||||||
|
@ -57,3 +58,4 @@ obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
|
||||||
obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
|
obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
|
||||||
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
|
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
|
||||||
obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
|
obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
|
||||||
|
obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o
|
||||||
|
|
|
@ -28,8 +28,6 @@ enum as3711_bl_type {
|
||||||
|
|
||||||
struct as3711_bl_data {
|
struct as3711_bl_data {
|
||||||
bool powered;
|
bool powered;
|
||||||
const char *fb_name;
|
|
||||||
struct device *fb_dev;
|
|
||||||
enum as3711_bl_type type;
|
enum as3711_bl_type type;
|
||||||
int brightness;
|
int brightness;
|
||||||
struct backlight_device *bl;
|
struct backlight_device *bl;
|
||||||
|
@ -262,10 +260,10 @@ static int as3711_bl_register(struct platform_device *pdev,
|
||||||
static int as3711_backlight_parse_dt(struct device *dev)
|
static int as3711_backlight_parse_dt(struct device *dev)
|
||||||
{
|
{
|
||||||
struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
|
struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
|
||||||
struct device_node *bl =
|
struct device_node *bl, *fb;
|
||||||
of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
bl = of_get_child_by_name(dev->parent->of_node, "backlight");
|
||||||
if (!bl) {
|
if (!bl) {
|
||||||
dev_dbg(dev, "backlight node not found\n");
|
dev_dbg(dev, "backlight node not found\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -273,26 +271,30 @@ static int as3711_backlight_parse_dt(struct device *dev)
|
||||||
|
|
||||||
fb = of_parse_phandle(bl, "su1-dev", 0);
|
fb = of_parse_phandle(bl, "su1-dev", 0);
|
||||||
if (fb) {
|
if (fb) {
|
||||||
pdata->su1_fb = fb->full_name;
|
of_node_put(fb);
|
||||||
|
|
||||||
|
pdata->su1_fb = true;
|
||||||
|
|
||||||
ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
|
ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
|
||||||
if (pdata->su1_max_uA <= 0)
|
if (pdata->su1_max_uA <= 0)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto err_put_bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
fb = of_parse_phandle(bl, "su2-dev", 0);
|
fb = of_parse_phandle(bl, "su2-dev", 0);
|
||||||
if (fb) {
|
if (fb) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
pdata->su2_fb = fb->full_name;
|
of_node_put(fb);
|
||||||
|
|
||||||
|
pdata->su2_fb = true;
|
||||||
|
|
||||||
ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
|
ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
|
||||||
if (pdata->su2_max_uA <= 0)
|
if (pdata->su2_max_uA <= 0)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto err_put_bl;
|
||||||
|
|
||||||
if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
|
if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
|
||||||
pdata->su2_feedback = AS3711_SU2_VOLTAGE;
|
pdata->su2_feedback = AS3711_SU2_VOLTAGE;
|
||||||
|
@ -314,8 +316,10 @@ static int as3711_backlight_parse_dt(struct device *dev)
|
||||||
pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
|
pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (count != 1)
|
if (count != 1) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto err_put_bl;
|
||||||
|
}
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
|
if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
|
||||||
|
@ -334,8 +338,10 @@ static int as3711_backlight_parse_dt(struct device *dev)
|
||||||
pdata->su2_fbprot = AS3711_SU2_GPIO4;
|
pdata->su2_fbprot = AS3711_SU2_GPIO4;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if (count != 1)
|
if (count != 1) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto err_put_bl;
|
||||||
|
}
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
if (of_find_property(bl, "su2-auto-curr1", NULL)) {
|
if (of_find_property(bl, "su2-auto-curr1", NULL)) {
|
||||||
|
@ -355,11 +361,20 @@ static int as3711_backlight_parse_dt(struct device *dev)
|
||||||
* At least one su2-auto-curr* must be specified iff
|
* At least one su2-auto-curr* must be specified iff
|
||||||
* AS3711_SU2_CURR_AUTO is used
|
* AS3711_SU2_CURR_AUTO is used
|
||||||
*/
|
*/
|
||||||
if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO))
|
if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto err_put_bl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
of_node_put(bl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_put_bl:
|
||||||
|
of_node_put(bl);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int as3711_backlight_probe(struct platform_device *pdev)
|
static int as3711_backlight_probe(struct platform_device *pdev)
|
||||||
|
@ -412,7 +427,6 @@ static int as3711_backlight_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
if (pdata->su1_fb) {
|
if (pdata->su1_fb) {
|
||||||
su = &supply->su1;
|
su = &supply->su1;
|
||||||
su->fb_name = pdata->su1_fb;
|
|
||||||
su->type = AS3711_BL_SU1;
|
su->type = AS3711_BL_SU1;
|
||||||
|
|
||||||
max_brightness = min(pdata->su1_max_uA, 31);
|
max_brightness = min(pdata->su1_max_uA, 31);
|
||||||
|
@ -423,7 +437,6 @@ static int as3711_backlight_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
if (pdata->su2_fb) {
|
if (pdata->su2_fb) {
|
||||||
su = &supply->su2;
|
su = &supply->su2;
|
||||||
su->fb_name = pdata->su2_fb;
|
|
||||||
su->type = AS3711_BL_SU2;
|
su->type = AS3711_BL_SU2;
|
||||||
|
|
||||||
switch (pdata->su2_fbprot) {
|
switch (pdata->su2_fbprot) {
|
||||||
|
|
|
@ -21,9 +21,6 @@ static int genericbl_intensity;
|
||||||
static struct backlight_device *generic_backlight_device;
|
static struct backlight_device *generic_backlight_device;
|
||||||
static struct generic_bl_info *bl_machinfo;
|
static struct generic_bl_info *bl_machinfo;
|
||||||
|
|
||||||
/* Flag to signal when the battery is low */
|
|
||||||
#define GENERICBL_BATTLOW BL_CORE_DRIVER1
|
|
||||||
|
|
||||||
static int genericbl_send_intensity(struct backlight_device *bd)
|
static int genericbl_send_intensity(struct backlight_device *bd)
|
||||||
{
|
{
|
||||||
int intensity = bd->props.brightness;
|
int intensity = bd->props.brightness;
|
||||||
|
@ -34,8 +31,6 @@ static int genericbl_send_intensity(struct backlight_device *bd)
|
||||||
intensity = 0;
|
intensity = 0;
|
||||||
if (bd->props.state & BL_CORE_SUSPENDED)
|
if (bd->props.state & BL_CORE_SUSPENDED)
|
||||||
intensity = 0;
|
intensity = 0;
|
||||||
if (bd->props.state & GENERICBL_BATTLOW)
|
|
||||||
intensity &= bl_machinfo->limit_mask;
|
|
||||||
|
|
||||||
bl_machinfo->set_bl_intensity(intensity);
|
bl_machinfo->set_bl_intensity(intensity);
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev)
|
||||||
if (!pdata)
|
if (!pdata)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
np = of_find_node_by_name(nproot, "backlight");
|
np = of_get_child_by_name(nproot, "backlight");
|
||||||
if (!np) {
|
if (!np) {
|
||||||
dev_err(&pdev->dev, "failed to find backlight node\n");
|
dev_err(&pdev->dev, "failed to find backlight node\n");
|
||||||
return;
|
return;
|
||||||
|
@ -125,6 +125,8 @@ static void max8925_backlight_dt_init(struct platform_device *pdev)
|
||||||
if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
|
if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val))
|
||||||
pdata->dual_string = val;
|
pdata->dual_string = val;
|
||||||
|
|
||||||
|
of_node_put(np);
|
||||||
|
|
||||||
pdev->dev.platform_data = pdata;
|
pdev->dev.platform_data = pdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
252
drivers/video/backlight/otm3225a.c
Normal file
252
drivers/video/backlight/otm3225a.c
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/* Driver for ORISE Technology OTM3225A SOC for TFT LCD
|
||||||
|
* Copyright (C) 2017, EETS GmbH, Felix Brack <fb@ltec.ch>
|
||||||
|
*
|
||||||
|
* This driver implements a lcd device for the ORISE OTM3225A display
|
||||||
|
* controller. The control interface to the display is SPI and the display's
|
||||||
|
* memory is updated over the 16-bit RGB interface.
|
||||||
|
* The main source of information for writing this driver was provided by the
|
||||||
|
* OTM3225A datasheet from ORISE Technology. Some information arise from the
|
||||||
|
* ILI9328 datasheet from ILITEK as well as from the datasheets and sample code
|
||||||
|
* provided by Crystalfontz America Inc. who sells the CFAF240320A-032T, a 3.2"
|
||||||
|
* TFT LC display using the OTM3225A controller.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/lcd.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
|
#define OTM3225A_INDEX_REG 0x70
|
||||||
|
#define OTM3225A_DATA_REG 0x72
|
||||||
|
|
||||||
|
/* instruction register list */
|
||||||
|
#define DRIVER_OUTPUT_CTRL_1 0x01
|
||||||
|
#define DRIVER_WAVEFORM_CTRL 0x02
|
||||||
|
#define ENTRY_MODE 0x03
|
||||||
|
#define SCALING_CTRL 0x04
|
||||||
|
#define DISPLAY_CTRL_1 0x07
|
||||||
|
#define DISPLAY_CTRL_2 0x08
|
||||||
|
#define DISPLAY_CTRL_3 0x09
|
||||||
|
#define FRAME_CYCLE_CTRL 0x0A
|
||||||
|
#define EXT_DISP_IFACE_CTRL_1 0x0C
|
||||||
|
#define FRAME_MAKER_POS 0x0D
|
||||||
|
#define EXT_DISP_IFACE_CTRL_2 0x0F
|
||||||
|
#define POWER_CTRL_1 0x10
|
||||||
|
#define POWER_CTRL_2 0x11
|
||||||
|
#define POWER_CTRL_3 0x12
|
||||||
|
#define POWER_CTRL_4 0x13
|
||||||
|
#define GRAM_ADDR_HORIZ_SET 0x20
|
||||||
|
#define GRAM_ADDR_VERT_SET 0x21
|
||||||
|
#define GRAM_READ_WRITE 0x22
|
||||||
|
#define POWER_CTRL_7 0x29
|
||||||
|
#define FRAME_RATE_CTRL 0x2B
|
||||||
|
#define GAMMA_CTRL_1 0x30
|
||||||
|
#define GAMMA_CTRL_2 0x31
|
||||||
|
#define GAMMA_CTRL_3 0x32
|
||||||
|
#define GAMMA_CTRL_4 0x35
|
||||||
|
#define GAMMA_CTRL_5 0x36
|
||||||
|
#define GAMMA_CTRL_6 0x37
|
||||||
|
#define GAMMA_CTRL_7 0x38
|
||||||
|
#define GAMMA_CTRL_8 0x39
|
||||||
|
#define GAMMA_CTRL_9 0x3C
|
||||||
|
#define GAMMA_CTRL_10 0x3D
|
||||||
|
#define WINDOW_HORIZ_RAM_START 0x50
|
||||||
|
#define WINDOW_HORIZ_RAM_END 0x51
|
||||||
|
#define WINDOW_VERT_RAM_START 0x52
|
||||||
|
#define WINDOW_VERT_RAM_END 0x53
|
||||||
|
#define DRIVER_OUTPUT_CTRL_2 0x60
|
||||||
|
#define BASE_IMG_DISPLAY_CTRL 0x61
|
||||||
|
#define VERT_SCROLL_CTRL 0x6A
|
||||||
|
#define PD1_DISPLAY_POS 0x80
|
||||||
|
#define PD1_RAM_START 0x81
|
||||||
|
#define PD1_RAM_END 0x82
|
||||||
|
#define PD2_DISPLAY_POS 0x83
|
||||||
|
#define PD2_RAM_START 0x84
|
||||||
|
#define PD2_RAM_END 0x85
|
||||||
|
#define PANEL_IFACE_CTRL_1 0x90
|
||||||
|
#define PANEL_IFACE_CTRL_2 0x92
|
||||||
|
#define PANEL_IFACE_CTRL_4 0x95
|
||||||
|
#define PANEL_IFACE_CTRL_5 0x97
|
||||||
|
|
||||||
|
struct otm3225a_data {
|
||||||
|
struct spi_device *spi;
|
||||||
|
struct lcd_device *ld;
|
||||||
|
int power;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct otm3225a_spi_instruction {
|
||||||
|
unsigned char reg; /* register to write */
|
||||||
|
unsigned short value; /* data to write to 'reg' */
|
||||||
|
unsigned short delay; /* delay in ms after write */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct otm3225a_spi_instruction display_init[] = {
|
||||||
|
{ DRIVER_OUTPUT_CTRL_1, 0x0000, 0 },
|
||||||
|
{ DRIVER_WAVEFORM_CTRL, 0x0700, 0 },
|
||||||
|
{ ENTRY_MODE, 0x50A0, 0 },
|
||||||
|
{ SCALING_CTRL, 0x0000, 0 },
|
||||||
|
{ DISPLAY_CTRL_2, 0x0606, 0 },
|
||||||
|
{ DISPLAY_CTRL_3, 0x0000, 0 },
|
||||||
|
{ FRAME_CYCLE_CTRL, 0x0000, 0 },
|
||||||
|
{ EXT_DISP_IFACE_CTRL_1, 0x0000, 0 },
|
||||||
|
{ FRAME_MAKER_POS, 0x0000, 0 },
|
||||||
|
{ EXT_DISP_IFACE_CTRL_2, 0x0002, 0 },
|
||||||
|
{ POWER_CTRL_2, 0x0007, 0 },
|
||||||
|
{ POWER_CTRL_3, 0x0000, 0 },
|
||||||
|
{ POWER_CTRL_4, 0x0000, 200 },
|
||||||
|
{ DISPLAY_CTRL_1, 0x0101, 0 },
|
||||||
|
{ POWER_CTRL_1, 0x12B0, 0 },
|
||||||
|
{ POWER_CTRL_2, 0x0007, 0 },
|
||||||
|
{ POWER_CTRL_3, 0x01BB, 50 },
|
||||||
|
{ POWER_CTRL_4, 0x0013, 0 },
|
||||||
|
{ POWER_CTRL_7, 0x0010, 50 },
|
||||||
|
{ GAMMA_CTRL_1, 0x000A, 0 },
|
||||||
|
{ GAMMA_CTRL_2, 0x1326, 0 },
|
||||||
|
{ GAMMA_CTRL_3, 0x0A29, 0 },
|
||||||
|
{ GAMMA_CTRL_4, 0x0A0A, 0 },
|
||||||
|
{ GAMMA_CTRL_5, 0x1E03, 0 },
|
||||||
|
{ GAMMA_CTRL_6, 0x031E, 0 },
|
||||||
|
{ GAMMA_CTRL_7, 0x0706, 0 },
|
||||||
|
{ GAMMA_CTRL_8, 0x0303, 0 },
|
||||||
|
{ GAMMA_CTRL_9, 0x010E, 0 },
|
||||||
|
{ GAMMA_CTRL_10, 0x040E, 0 },
|
||||||
|
{ WINDOW_HORIZ_RAM_START, 0x0000, 0 },
|
||||||
|
{ WINDOW_HORIZ_RAM_END, 0x00EF, 0 },
|
||||||
|
{ WINDOW_VERT_RAM_START, 0x0000, 0 },
|
||||||
|
{ WINDOW_VERT_RAM_END, 0x013F, 0 },
|
||||||
|
{ DRIVER_OUTPUT_CTRL_2, 0x2700, 0 },
|
||||||
|
{ BASE_IMG_DISPLAY_CTRL, 0x0001, 0 },
|
||||||
|
{ VERT_SCROLL_CTRL, 0x0000, 0 },
|
||||||
|
{ PD1_DISPLAY_POS, 0x0000, 0 },
|
||||||
|
{ PD1_RAM_START, 0x0000, 0 },
|
||||||
|
{ PD1_RAM_END, 0x0000, 0 },
|
||||||
|
{ PD2_DISPLAY_POS, 0x0000, 0 },
|
||||||
|
{ PD2_RAM_START, 0x0000, 0 },
|
||||||
|
{ PD2_RAM_END, 0x0000, 0 },
|
||||||
|
{ PANEL_IFACE_CTRL_1, 0x0010, 0 },
|
||||||
|
{ PANEL_IFACE_CTRL_2, 0x0000, 0 },
|
||||||
|
{ PANEL_IFACE_CTRL_4, 0x0210, 0 },
|
||||||
|
{ PANEL_IFACE_CTRL_5, 0x0000, 0 },
|
||||||
|
{ DISPLAY_CTRL_1, 0x0133, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct otm3225a_spi_instruction display_enable_rgb_interface[] = {
|
||||||
|
{ ENTRY_MODE, 0x1080, 0 },
|
||||||
|
{ GRAM_ADDR_HORIZ_SET, 0x0000, 0 },
|
||||||
|
{ GRAM_ADDR_VERT_SET, 0x0000, 0 },
|
||||||
|
{ EXT_DISP_IFACE_CTRL_1, 0x0111, 500 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct otm3225a_spi_instruction display_off[] = {
|
||||||
|
{ DISPLAY_CTRL_1, 0x0131, 100 },
|
||||||
|
{ DISPLAY_CTRL_1, 0x0130, 100 },
|
||||||
|
{ DISPLAY_CTRL_1, 0x0100, 0 },
|
||||||
|
{ POWER_CTRL_1, 0x0280, 0 },
|
||||||
|
{ POWER_CTRL_3, 0x018B, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct otm3225a_spi_instruction display_on[] = {
|
||||||
|
{ POWER_CTRL_1, 0x1280, 0 },
|
||||||
|
{ DISPLAY_CTRL_1, 0x0101, 100 },
|
||||||
|
{ DISPLAY_CTRL_1, 0x0121, 0 },
|
||||||
|
{ DISPLAY_CTRL_1, 0x0123, 100 },
|
||||||
|
{ DISPLAY_CTRL_1, 0x0133, 10 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void otm3225a_write(struct spi_device *spi,
|
||||||
|
struct otm3225a_spi_instruction *instruction,
|
||||||
|
unsigned int count)
|
||||||
|
{
|
||||||
|
unsigned char buf[3];
|
||||||
|
|
||||||
|
while (count--) {
|
||||||
|
/* address register using index register */
|
||||||
|
buf[0] = OTM3225A_INDEX_REG;
|
||||||
|
buf[1] = 0x00;
|
||||||
|
buf[2] = instruction->reg;
|
||||||
|
spi_write(spi, buf, 3);
|
||||||
|
|
||||||
|
/* write data to addressed register */
|
||||||
|
buf[0] = OTM3225A_DATA_REG;
|
||||||
|
buf[1] = (instruction->value >> 8) & 0xff;
|
||||||
|
buf[2] = instruction->value & 0xff;
|
||||||
|
spi_write(spi, buf, 3);
|
||||||
|
|
||||||
|
/* execute delay if any */
|
||||||
|
if (instruction->delay)
|
||||||
|
msleep(instruction->delay);
|
||||||
|
instruction++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int otm3225a_set_power(struct lcd_device *ld, int power)
|
||||||
|
{
|
||||||
|
struct otm3225a_data *dd = lcd_get_data(ld);
|
||||||
|
|
||||||
|
if (power == dd->power)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (power > FB_BLANK_UNBLANK)
|
||||||
|
otm3225a_write(dd->spi, display_off, ARRAY_SIZE(display_off));
|
||||||
|
else
|
||||||
|
otm3225a_write(dd->spi, display_on, ARRAY_SIZE(display_on));
|
||||||
|
dd->power = power;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int otm3225a_get_power(struct lcd_device *ld)
|
||||||
|
{
|
||||||
|
struct otm3225a_data *dd = lcd_get_data(ld);
|
||||||
|
|
||||||
|
return dd->power;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct lcd_ops otm3225a_ops = {
|
||||||
|
.set_power = otm3225a_set_power,
|
||||||
|
.get_power = otm3225a_get_power,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int otm3225a_probe(struct spi_device *spi)
|
||||||
|
{
|
||||||
|
struct otm3225a_data *dd;
|
||||||
|
struct lcd_device *ld;
|
||||||
|
struct device *dev = &spi->dev;
|
||||||
|
|
||||||
|
dd = devm_kzalloc(dev, sizeof(struct otm3225a_data), GFP_KERNEL);
|
||||||
|
if (dd == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ld = devm_lcd_device_register(dev, dev_name(dev), dev, dd,
|
||||||
|
&otm3225a_ops);
|
||||||
|
if (IS_ERR(ld))
|
||||||
|
return PTR_ERR(ld);
|
||||||
|
|
||||||
|
dd->spi = spi;
|
||||||
|
dd->ld = ld;
|
||||||
|
dev_set_drvdata(dev, dd);
|
||||||
|
|
||||||
|
dev_info(dev, "Initializing and switching to RGB interface");
|
||||||
|
otm3225a_write(spi, display_init, ARRAY_SIZE(display_init));
|
||||||
|
otm3225a_write(spi, display_enable_rgb_interface,
|
||||||
|
ARRAY_SIZE(display_enable_rgb_interface));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct spi_driver otm3225a_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "otm3225a",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
.probe = otm3225a_probe,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_spi_driver(otm3225a_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Felix Brack <fb@ltec.ch>");
|
||||||
|
MODULE_DESCRIPTION("OTM3225A TFT LCD driver");
|
||||||
|
MODULE_VERSION("1.0.0");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
|
@ -35,11 +35,15 @@
|
||||||
#define MAX_VALUE 63
|
#define MAX_VALUE 63
|
||||||
#define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE)
|
#define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE)
|
||||||
|
|
||||||
#define PANDORABL_WAS_OFF BL_CORE_DRIVER1
|
struct pandora_private {
|
||||||
|
unsigned old_state;
|
||||||
|
#define PANDORABL_WAS_OFF 1
|
||||||
|
};
|
||||||
|
|
||||||
static int pandora_backlight_update_status(struct backlight_device *bl)
|
static int pandora_backlight_update_status(struct backlight_device *bl)
|
||||||
{
|
{
|
||||||
int brightness = bl->props.brightness;
|
int brightness = bl->props.brightness;
|
||||||
|
struct pandora_private *priv = bl_get_data(bl);
|
||||||
u8 r;
|
u8 r;
|
||||||
|
|
||||||
if (bl->props.power != FB_BLANK_UNBLANK)
|
if (bl->props.power != FB_BLANK_UNBLANK)
|
||||||
|
@ -53,7 +57,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
|
||||||
brightness = MAX_USER_VALUE;
|
brightness = MAX_USER_VALUE;
|
||||||
|
|
||||||
if (brightness == 0) {
|
if (brightness == 0) {
|
||||||
if (bl->props.state & PANDORABL_WAS_OFF)
|
if (priv->old_state == PANDORABL_WAS_OFF)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
/* first disable PWM0 output, then clock */
|
/* first disable PWM0 output, then clock */
|
||||||
|
@ -66,7 +70,7 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bl->props.state & PANDORABL_WAS_OFF) {
|
if (priv->old_state == PANDORABL_WAS_OFF) {
|
||||||
/*
|
/*
|
||||||
* set PWM duty cycle to max. TPS61161 seems to use this
|
* set PWM duty cycle to max. TPS61161 seems to use this
|
||||||
* to calibrate it's PWM sensitivity when it starts.
|
* to calibrate it's PWM sensitivity when it starts.
|
||||||
|
@ -93,9 +97,9 @@ static int pandora_backlight_update_status(struct backlight_device *bl)
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (brightness != 0)
|
if (brightness != 0)
|
||||||
bl->props.state &= ~PANDORABL_WAS_OFF;
|
priv->old_state = 0;
|
||||||
else
|
else
|
||||||
bl->props.state |= PANDORABL_WAS_OFF;
|
priv->old_state = PANDORABL_WAS_OFF;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -109,13 +113,20 @@ static int pandora_backlight_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct backlight_properties props;
|
struct backlight_properties props;
|
||||||
struct backlight_device *bl;
|
struct backlight_device *bl;
|
||||||
|
struct pandora_private *priv;
|
||||||
u8 r;
|
u8 r;
|
||||||
|
|
||||||
|
priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv) {
|
||||||
|
dev_err(&pdev->dev, "failed to allocate driver private data\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&props, 0, sizeof(props));
|
memset(&props, 0, sizeof(props));
|
||||||
props.max_brightness = MAX_USER_VALUE;
|
props.max_brightness = MAX_USER_VALUE;
|
||||||
props.type = BACKLIGHT_RAW;
|
props.type = BACKLIGHT_RAW;
|
||||||
bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev,
|
bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev,
|
||||||
NULL, &pandora_backlight_ops, &props);
|
priv, &pandora_backlight_ops, &props);
|
||||||
if (IS_ERR(bl)) {
|
if (IS_ERR(bl)) {
|
||||||
dev_err(&pdev->dev, "failed to register backlight\n");
|
dev_err(&pdev->dev, "failed to register backlight\n");
|
||||||
return PTR_ERR(bl);
|
return PTR_ERR(bl);
|
||||||
|
@ -126,7 +137,7 @@ static int pandora_backlight_probe(struct platform_device *pdev)
|
||||||
/* 64 cycle period, ON position 0 */
|
/* 64 cycle period, ON position 0 */
|
||||||
twl_i2c_write_u8(TWL_MODULE_PWM, 0x80, TWL_PWM0_ON);
|
twl_i2c_write_u8(TWL_MODULE_PWM, 0x80, TWL_PWM0_ON);
|
||||||
|
|
||||||
bl->props.state |= PANDORABL_WAS_OFF;
|
priv->old_state = PANDORABL_WAS_OFF;
|
||||||
bl->props.brightness = MAX_USER_VALUE;
|
bl->props.brightness = MAX_USER_VALUE;
|
||||||
backlight_update_status(bl);
|
backlight_update_status(bl);
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -35,6 +36,8 @@ struct pwm_bl_data {
|
||||||
struct gpio_desc *enable_gpio;
|
struct gpio_desc *enable_gpio;
|
||||||
unsigned int scale;
|
unsigned int scale;
|
||||||
bool legacy;
|
bool legacy;
|
||||||
|
unsigned int post_pwm_on_delay;
|
||||||
|
unsigned int pwm_off_delay;
|
||||||
int (*notify)(struct device *,
|
int (*notify)(struct device *,
|
||||||
int brightness);
|
int brightness);
|
||||||
void (*notify_after)(struct device *,
|
void (*notify_after)(struct device *,
|
||||||
|
@ -54,10 +57,14 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
dev_err(pb->dev, "failed to enable power supply\n");
|
dev_err(pb->dev, "failed to enable power supply\n");
|
||||||
|
|
||||||
|
pwm_enable(pb->pwm);
|
||||||
|
|
||||||
|
if (pb->post_pwm_on_delay)
|
||||||
|
msleep(pb->post_pwm_on_delay);
|
||||||
|
|
||||||
if (pb->enable_gpio)
|
if (pb->enable_gpio)
|
||||||
gpiod_set_value_cansleep(pb->enable_gpio, 1);
|
gpiod_set_value_cansleep(pb->enable_gpio, 1);
|
||||||
|
|
||||||
pwm_enable(pb->pwm);
|
|
||||||
pb->enabled = true;
|
pb->enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,12 +73,15 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb)
|
||||||
if (!pb->enabled)
|
if (!pb->enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pwm_config(pb->pwm, 0, pb->period);
|
|
||||||
pwm_disable(pb->pwm);
|
|
||||||
|
|
||||||
if (pb->enable_gpio)
|
if (pb->enable_gpio)
|
||||||
gpiod_set_value_cansleep(pb->enable_gpio, 0);
|
gpiod_set_value_cansleep(pb->enable_gpio, 0);
|
||||||
|
|
||||||
|
if (pb->pwm_off_delay)
|
||||||
|
msleep(pb->pwm_off_delay);
|
||||||
|
|
||||||
|
pwm_config(pb->pwm, 0, pb->period);
|
||||||
|
pwm_disable(pb->pwm);
|
||||||
|
|
||||||
regulator_disable(pb->power_supply);
|
regulator_disable(pb->power_supply);
|
||||||
pb->enabled = false;
|
pb->enabled = false;
|
||||||
}
|
}
|
||||||
|
@ -177,6 +187,14 @@ static int pwm_backlight_parse_dt(struct device *dev,
|
||||||
data->max_brightness--;
|
data->max_brightness--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These values are optional and set as 0 by default, the out values
|
||||||
|
* are modified only if a valid u32 value can be decoded.
|
||||||
|
*/
|
||||||
|
of_property_read_u32(node, "post-pwm-on-delay-ms",
|
||||||
|
&data->post_pwm_on_delay);
|
||||||
|
of_property_read_u32(node, "pwm-off-delay-ms", &data->pwm_off_delay);
|
||||||
|
|
||||||
data->enable_gpio = -EINVAL;
|
data->enable_gpio = -EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -275,6 +293,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
||||||
pb->exit = data->exit;
|
pb->exit = data->exit;
|
||||||
pb->dev = &pdev->dev;
|
pb->dev = &pdev->dev;
|
||||||
pb->enabled = false;
|
pb->enabled = false;
|
||||||
|
pb->post_pwm_on_delay = data->post_pwm_on_delay;
|
||||||
|
pb->pwm_off_delay = data->pwm_off_delay;
|
||||||
|
|
||||||
pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
|
pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
|
||||||
GPIOD_ASIS);
|
GPIOD_ASIS);
|
||||||
|
@ -301,14 +321,14 @@ static int pwm_backlight_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the GPIO is not known to be already configured as output, that
|
* If the GPIO is not known to be already configured as output, that
|
||||||
* is, if gpiod_get_direction returns either GPIOF_DIR_IN or -EINVAL,
|
* is, if gpiod_get_direction returns either 1 or -EINVAL, change the
|
||||||
* change the direction to output and set the GPIO as active.
|
* direction to output and set the GPIO as active.
|
||||||
* Do not force the GPIO to active when it was already output as it
|
* Do not force the GPIO to active when it was already output as it
|
||||||
* could cause backlight flickering or we would enable the backlight too
|
* could cause backlight flickering or we would enable the backlight too
|
||||||
* early. Leave the decision of the initial backlight state for later.
|
* early. Leave the decision of the initial backlight state for later.
|
||||||
*/
|
*/
|
||||||
if (pb->enable_gpio &&
|
if (pb->enable_gpio &&
|
||||||
gpiod_get_direction(pb->enable_gpio) != GPIOF_DIR_OUT)
|
gpiod_get_direction(pb->enable_gpio) != 0)
|
||||||
gpiod_direction_output(pb->enable_gpio, 1);
|
gpiod_direction_output(pb->enable_gpio, 1);
|
||||||
|
|
||||||
pb->power_supply = devm_regulator_get(&pdev->dev, "power");
|
pb->power_supply = devm_regulator_get(&pdev->dev, "power");
|
||||||
|
|
82
drivers/video/backlight/rave-sp-backlight.c
Normal file
82
drivers/video/backlight/rave-sp-backlight.c
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LCD Backlight driver for RAVE SP
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Zodiac Inflight Innovations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/backlight.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mfd/rave-sp.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#define RAVE_SP_BACKLIGHT_LCD_EN BIT(7)
|
||||||
|
|
||||||
|
static int rave_sp_backlight_update_status(struct backlight_device *bd)
|
||||||
|
{
|
||||||
|
const struct backlight_properties *p = &bd->props;
|
||||||
|
const u8 intensity =
|
||||||
|
(p->power == FB_BLANK_UNBLANK) ? p->brightness : 0;
|
||||||
|
struct rave_sp *sp = dev_get_drvdata(&bd->dev);
|
||||||
|
u8 cmd[] = {
|
||||||
|
[0] = RAVE_SP_CMD_SET_BACKLIGHT,
|
||||||
|
[1] = 0,
|
||||||
|
[2] = intensity ? RAVE_SP_BACKLIGHT_LCD_EN | intensity : 0,
|
||||||
|
[3] = 0,
|
||||||
|
[4] = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return rave_sp_exec(sp, cmd, sizeof(cmd), NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct backlight_ops rave_sp_backlight_ops = {
|
||||||
|
.options = BL_CORE_SUSPENDRESUME,
|
||||||
|
.update_status = rave_sp_backlight_update_status,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct backlight_properties rave_sp_backlight_props = {
|
||||||
|
.type = BACKLIGHT_PLATFORM,
|
||||||
|
.max_brightness = 100,
|
||||||
|
.brightness = 50,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rave_sp_backlight_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct backlight_device *bd;
|
||||||
|
|
||||||
|
bd = devm_backlight_device_register(dev, pdev->name, dev->parent,
|
||||||
|
dev_get_drvdata(dev->parent),
|
||||||
|
&rave_sp_backlight_ops,
|
||||||
|
&rave_sp_backlight_props);
|
||||||
|
if (IS_ERR(bd))
|
||||||
|
return PTR_ERR(bd);
|
||||||
|
|
||||||
|
backlight_update_status(bd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id rave_sp_backlight_of_match[] = {
|
||||||
|
{ .compatible = "zii,rave-sp-backlight" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver rave_sp_backlight_driver = {
|
||||||
|
.probe = rave_sp_backlight_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = KBUILD_MODNAME,
|
||||||
|
.of_match_table = rave_sp_backlight_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(rave_sp_backlight_driver);
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, rave_sp_backlight_of_match);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
|
||||||
|
MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
|
||||||
|
MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
|
||||||
|
MODULE_DESCRIPTION("RAVE SP Backlight driver");
|
|
@ -184,11 +184,11 @@ static struct tps65217_bl_pdata *
|
||||||
tps65217_bl_parse_dt(struct platform_device *pdev)
|
tps65217_bl_parse_dt(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
|
struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct device_node *node = of_node_get(tps->dev->of_node);
|
struct device_node *node;
|
||||||
struct tps65217_bl_pdata *pdata, *err;
|
struct tps65217_bl_pdata *pdata, *err;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
node = of_find_node_by_name(node, "backlight");
|
node = of_get_child_by_name(tps->dev->of_node, "backlight");
|
||||||
if (!node)
|
if (!node)
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,6 @@ struct backlight_properties {
|
||||||
|
|
||||||
#define BL_CORE_SUSPENDED (1 << 0) /* backlight is suspended */
|
#define BL_CORE_SUSPENDED (1 << 0) /* backlight is suspended */
|
||||||
#define BL_CORE_FBBLANK (1 << 1) /* backlight is under an fb blank event */
|
#define BL_CORE_FBBLANK (1 << 1) /* backlight is under an fb blank event */
|
||||||
#define BL_CORE_DRIVER4 (1 << 28) /* reserved for driver specific use */
|
|
||||||
#define BL_CORE_DRIVER3 (1 << 29) /* reserved for driver specific use */
|
|
||||||
#define BL_CORE_DRIVER2 (1 << 30) /* reserved for driver specific use */
|
|
||||||
#define BL_CORE_DRIVER1 (1 << 31) /* reserved for driver specific use */
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -108,9 +108,9 @@ struct as3711_regulator_pdata {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct as3711_bl_pdata {
|
struct as3711_bl_pdata {
|
||||||
const char *su1_fb;
|
bool su1_fb;
|
||||||
int su1_max_uA;
|
int su1_max_uA;
|
||||||
const char *su2_fb;
|
bool su2_fb;
|
||||||
int su2_max_uA;
|
int su2_max_uA;
|
||||||
enum as3711_su2_feedback su2_feedback;
|
enum as3711_su2_feedback su2_feedback;
|
||||||
enum as3711_su2_fbprot su2_fbprot;
|
enum as3711_su2_fbprot su2_fbprot;
|
||||||
|
|
|
@ -21,6 +21,7 @@ enum rave_sp_command {
|
||||||
RAVE_SP_CMD_STATUS = 0xA0,
|
RAVE_SP_CMD_STATUS = 0xA0,
|
||||||
RAVE_SP_CMD_SW_WDT = 0xA1,
|
RAVE_SP_CMD_SW_WDT = 0xA1,
|
||||||
RAVE_SP_CMD_PET_WDT = 0xA2,
|
RAVE_SP_CMD_PET_WDT = 0xA2,
|
||||||
|
RAVE_SP_CMD_SET_BACKLIGHT = 0xA6,
|
||||||
RAVE_SP_CMD_RESET = 0xA7,
|
RAVE_SP_CMD_RESET = 0xA7,
|
||||||
RAVE_SP_CMD_RESET_REASON = 0xA8,
|
RAVE_SP_CMD_RESET_REASON = 0xA8,
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ struct platform_pwm_backlight_data {
|
||||||
unsigned int lth_brightness;
|
unsigned int lth_brightness;
|
||||||
unsigned int pwm_period_ns;
|
unsigned int pwm_period_ns;
|
||||||
unsigned int *levels;
|
unsigned int *levels;
|
||||||
|
unsigned int post_pwm_on_delay;
|
||||||
|
unsigned int pwm_off_delay;
|
||||||
/* TODO remove once all users are switched to gpiod_* API */
|
/* TODO remove once all users are switched to gpiod_* API */
|
||||||
int enable_gpio;
|
int enable_gpio;
|
||||||
int (*init)(struct device *dev);
|
int (*init)(struct device *dev);
|
||||||
|
|
Loading…
Reference in a new issue