Thread (30 messages) 30 messages, 6 authors, 2018-04-16

Re: [PATCHv4 08/10] backlight: add TI LMU backlight driver

From: Sebastian Reichel <hidden>
Date: 2018-04-09 16:14:39
Also in: linux-devicetree, linux-omap, lkml

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

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help