Hi Daniel,
On Wed, Apr 04, 2018 at 03:57:39PM +0100, Daniel Thompson wrote:
On Fri, Mar 30, 2018 at 07:24:12PM +0200, Sebastian Reichel wrote:
quoted
This adds backlight support for the following TI LMU
chips: LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697.
Signed-off-by: Milo Kim <redacted>
[add LED subsystem support for keyboard backlight and rework DT
Milo's mail has be bouncing for a very long time now. Did they really
sign off this code or is this intended to be an authorship credit?
I took over his patches from ~ a year ago and reworked them.
quoted
binding according to Rob Herrings feedback]
Signed-off-by: Sebastian Reichel <redacted>
---
drivers/video/backlight/Kconfig | 7 +
drivers/video/backlight/Makefile | 3 +
drivers/video/backlight/ti-lmu-backlight-core.c | 666 ++++++++++++++++++++++++
drivers/video/backlight/ti-lmu-backlight-data.c | 304 +++++++++++
drivers/video/backlight/ti-lmu-backlight-data.h | 95 ++++
5 files changed, 1075 insertions(+)
create mode 100644 drivers/video/backlight/ti-lmu-backlight-core.c
create mode 100644 drivers/video/backlight/ti-lmu-backlight-data.c
create mode 100644 drivers/video/backlight/ti-lmu-backlight-data.h
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 5d2d0d7e8100..27e6c5a0add8 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -427,6 +427,13 @@ config BACKLIGHT_SKY81452
To compile this driver as a module, choose M here: the module will
be called sky81452-backlight
+config BACKLIGHT_TI_LMU
+ tristate "Backlight driver for TI LMU"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_TI_LMU
+ help
+ Say Y to enable the backlight driver for TI LMU devices.
+ This supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697.
+
config BACKLIGHT_TPS65217
tristate "TPS65217 Backlight"
depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 19da71d518bf..a1132d3dfd4c 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -53,6 +53,9 @@ obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
+ti-lmu-backlight-objs := ti-lmu-backlight-core.o \
+ ti-lmu-backlight-data.o
+obj-$(CONFIG_BACKLIGHT_TI_LMU) += ti-lmu-backlight.o
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
diff --git a/drivers/video/backlight/ti-lmu-backlight-core.c b/drivers/video/backlight/ti-lmu-backlight-core.c
new file mode 100644
index 000000000000..a6099581edd7
--- /dev/null
+++ b/drivers/video/backlight/ti-lmu-backlight-core.c
@@ -0,0 +1,666 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2015 Texas Instruments
+ * Copyright 2018 Sebastian Reichel
+ *
+ * TI LMU Backlight driver, based on previous work from
+ * Milo Kim <milo.kim@ti.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/leds.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "ti-lmu-backlight-data.h"
+
+enum ti_lmu_bl_ctrl_mode {
+ BL_REGISTER_BASED,
+ BL_PWM_BASED,
+};
+
+enum ti_lmu_bl_type {
+ TI_LMU_BL, /* backlight userspace interface */
+ TI_LMU_LED, /* led userspace interface */
+};
+
+enum ti_lmu_bl_ramp_mode {
+ BL_RAMP_UP,
+ BL_RAMP_DOWN,
+};
+
+#define DEFAULT_PWM_NAME "lmu-backlight"
+#define NUM_DUAL_CHANNEL 2
+#define LMU_BACKLIGHT_DUAL_CHANNEL_USED (BIT(0) | BIT(1))
+#define LMU_BACKLIGHT_11BIT_LSB_MASK (BIT(0) | BIT(1) | BIT(2))
+#define LMU_BACKLIGHT_11BIT_MSB_SHIFT 3
+
+struct ti_lmu_bank {
+ struct device *dev;
+ int bank_id;
+ const struct ti_lmu_bl_cfg *cfg;
+ struct ti_lmu *lmu;
+ const char *label;
+ int leds;
+ int current_brightness;
+ u32 default_brightness;
+ u32 ramp_up_msec;
+ u32 ramp_down_msec;
+ u32 pwm_period;
+ enum ti_lmu_bl_ctrl_mode mode;
+ enum ti_lmu_bl_type type;
+
+ struct notifier_block nb;
+
+ struct backlight_device *backlight;
+ struct led_classdev *led;
+};
+
+static int ti_lmu_bl_enable(struct ti_lmu_bank *lmu_bank, bool enable)
+{
+ struct regmap *regmap = lmu_bank->lmu->regmap;
+ unsigned long enable_time = lmu_bank->cfg->reginfo->enable_usec;
+ u8 *reg = lmu_bank->cfg->reginfo->enable;
+ u8 mask = BIT(lmu_bank->bank_id);
+ u8 val = (enable == true) ? mask : 0;
+ int ret;
+
+ if (!reg)
+ return -EINVAL;
+
+ ret = regmap_update_bits(regmap, *reg, mask, val);
+ if (ret)
+ return ret;
+
+ if (enable_time > 0)
+ usleep_range(enable_time, enable_time + 100);
+
+ return 0;
+}
+
+static int ti_lmu_bl_update_brightness_register(struct ti_lmu_bank *lmu_bank,
+ int brightness)
+{
+ const struct ti_lmu_bl_cfg *cfg = lmu_bank->cfg;
+ const struct ti_lmu_bl_reg *reginfo = cfg->reginfo;
+ struct regmap *regmap = lmu_bank->lmu->regmap;
+ u8 reg, val;
+ int ret;
+
+ /*
+ * Brightness register update
+ *
+ * 11 bit dimming: update LSB bits and write MSB byte.
+ * MSB brightness should be shifted.
+ * 8 bit dimming: write MSB byte.
+ */
+ if (cfg->max_brightness == MAX_BRIGHTNESS_11BIT) {
+ reg = reginfo->brightness_lsb[lmu_bank->bank_id];
+ ret = regmap_update_bits(regmap, reg,
+ LMU_BACKLIGHT_11BIT_LSB_MASK,
+ brightness);
+ if (ret)
+ return ret;
+
+ val = brightness >> LMU_BACKLIGHT_11BIT_MSB_SHIFT;
+ } else {
+ val = brightness;
+ }
+
+ reg = reginfo->brightness_msb[lmu_bank->bank_id];
+ return regmap_write(regmap, reg, val);
+}
+
+static int ti_lmu_bl_pwm_ctrl(struct ti_lmu_bank *lmu_bank, int brightness)
+{
+ int max_brightness = lmu_bank->cfg->max_brightness;
+ struct pwm_state state = { };
+ int ret;
+
+ if (!lmu_bank->lmu->pwm) {
+ dev_err(lmu_bank->dev, "Missing PWM device!\n");
+ return -ENODEV;
+ }
+
+ pwm_init_state(lmu_bank->lmu->pwm, &state);
+ state.period = lmu_bank->pwm_period;
+ state.duty_cycle = brightness * state.period / max_brightness;
+
+ if (state.duty_cycle)
+ state.enabled = true;
+ else
+ state.enabled = false;
+
+ ret = pwm_apply_state(lmu_bank->lmu->pwm, &state);
+ if (ret)
+ dev_err(lmu_bank->dev, "Failed to configure PWM: %d", ret);
+
+ return ret;
+}
+
+static int ti_lmu_bl_set_brightness(struct ti_lmu_bank *lmu_bank,
+ int brightness)
+{
+ const struct ti_lmu_bl_cfg *cfg = lmu_bank->cfg;
+ bool enable = brightness > 0;
+ int ret;
+
+ ret = ti_lmu_bl_enable(lmu_bank, enable);
+ if (ret)
+ return ret;
+
+ if (lmu_bank->mode == BL_PWM_BASED) {
+ ti_lmu_bl_pwm_ctrl(lmu_bank, brightness);
+
+ switch (cfg->pwm_action) {
+ case UPDATE_PWM_ONLY:
+ /* No register update is required */
+ return 0;
+ case UPDATE_MAX_BRT:
+ /*
+ * PWM can start from any non-zero code and dim down
+ * to zero. So, brightness register should be updated
+ * even in PWM mode.
+ */
This comment could do with a little expansion (I assume the bank's
brightness register means something different when in PWM mode but the
flow of the code is tricky to read).
I will consult the manual and see how exactly the PWM stuff
is supposed to work. The platform I need this driver for
(Motorola Droid 4) does not have/use the PWM feature.
quoted
+ if (brightness > 0)
Isn't this "enable"?
Yes, good catch!
quoted
+ brightness = MAX_BRIGHTNESS_11BIT;
+ else
+ brightness = 0;
+ break;
+ default:
case UPDATE_PWM_AND_BRT_REGISTER:
ok.
quoted
+ break;
+ }
+ }
+
+ lmu_bank->current_brightness = brightness;
+
+ return ti_lmu_bl_update_brightness_register(lmu_bank, brightness);
+}
[...]
Thanks for the review.
-- Sebastian