1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
7
8#include <backlight.h>
9#include <dm.h>
10#include <i2c.h>
11#include <log.h>
12#include <linux/delay.h>
13#include <linux/err.h>
14#include <asm/gpio.h>
15
16#define LM3533_BL_MIN_BRIGHTNESS			0x02
17#define LM3533_BL_MAX_BRIGHTNESS			0xFF
18
19#define LM3533_SINK_OUTPUT_CONFIG_1			0x10
20#define LM3533_CONTROL_BANK_A_PWM			0x14
21#define LM3533_CONTROL_BANK_AB_BRIGHTNESS		0x1A
22#define LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT		0x1F
23#define LM3533_CONTROL_BANK_ENABLE			0x27
24#define LM3533_OVP_FREQUENCY_PWM_POLARITY		0x2C
25#define LM3533_BRIGHTNESS_REGISTER_A			0x40
26
27struct lm3533_backlight_priv {
28	struct gpio_desc enable_gpio;
29	u32 def_bl_lvl;
30};
31
32static int lm3533_backlight_enable(struct udevice *dev)
33{
34	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
35	int ret;
36
37	dm_gpio_set_value(&priv->enable_gpio, 1);
38	mdelay(5);
39
40	/* HVLED 1 & 2 are controlled by Bank A */
41	ret = dm_i2c_reg_write(dev, LM3533_SINK_OUTPUT_CONFIG_1, 0x00);
42	if (ret)
43		return ret;
44
45	/* PWM input is disabled for CABC */
46	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_PWM, 0x00);
47	if (ret)
48		return ret;
49
50	/* Linear & Control Bank A is configured for register Current control */
51	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_AB_BRIGHTNESS, 0x02);
52	if (ret)
53		return ret;
54
55	/* Full-Scale Current (20.2mA) */
56	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT, 0x13);
57	if (ret)
58		return ret;
59
60	/* Control Bank A is enable */
61	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_ENABLE, 0x01);
62	if (ret)
63		return ret;
64
65	ret = dm_i2c_reg_write(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY, 0x0A);
66	if (ret)
67		return ret;
68
69	return 0;
70}
71
72static int lm3533_backlight_set_brightness(struct udevice *dev, int percent)
73{
74	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
75	int ret;
76
77	if (percent == BACKLIGHT_DEFAULT)
78		percent = priv->def_bl_lvl;
79
80	if (percent < LM3533_BL_MIN_BRIGHTNESS)
81		percent = LM3533_BL_MIN_BRIGHTNESS;
82
83	if (percent > LM3533_BL_MAX_BRIGHTNESS)
84		percent = LM3533_BL_MAX_BRIGHTNESS;
85
86	/* Set brightness level */
87	ret = dm_i2c_reg_write(dev, LM3533_BRIGHTNESS_REGISTER_A,
88			       percent);
89	if (ret)
90		return ret;
91
92	return 0;
93}
94
95static int lm3533_backlight_probe(struct udevice *dev)
96{
97	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
98	int ret;
99
100	if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
101		return -EPROTONOSUPPORT;
102
103	ret = gpio_request_by_name(dev, "enable-gpios", 0,
104				   &priv->enable_gpio, GPIOD_IS_OUT);
105	if (ret) {
106		log_err("Could not decode enable-gpios (%d)\n", ret);
107		return ret;
108	}
109
110	priv->def_bl_lvl = dev_read_u32_default(dev, "default-brightness-level",
111						LM3533_BL_MAX_BRIGHTNESS);
112
113	return 0;
114}
115
116static const struct backlight_ops lm3533_backlight_ops = {
117	.enable = lm3533_backlight_enable,
118	.set_brightness = lm3533_backlight_set_brightness,
119};
120
121static const struct udevice_id lm3533_backlight_ids[] = {
122	{ .compatible = "ti,lm3533" },
123	{ }
124};
125
126U_BOOT_DRIVER(lm3533_backlight) = {
127	.name		= "lm3533_backlight",
128	.id		= UCLASS_PANEL_BACKLIGHT,
129	.of_match	= lm3533_backlight_ids,
130	.probe		= lm3533_backlight_probe,
131	.ops		= &lm3533_backlight_ops,
132	.priv_auto	= sizeof(struct lm3533_backlight_priv),
133};
134