summaryrefslogtreecommitdiff
path: root/drivers/video/lm3533_backlight.c
blob: 7b87b6bd40b95cb8912f2a581dd184d3af82c920 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
 */

#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT

#include <backlight.h>
#include <dm.h>
#include <dm/ofnode.h>
#include <i2c.h>
#include <log.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <asm/gpio.h>

#define LM3533_BL_MIN_BRIGHTNESS			0x02
#define LM3533_BL_MAX_BRIGHTNESS			0xFF

#define LM3533_SINK_OUTPUT_CONFIG_1			0x10
#define LM3533_CONTROL_PWM_BASE				0x14
#define   PWM_MAX					GENMASK(5, 0)
#define LM3533_CONTROL_BANK_AB_BRIGHTNESS		0x1A
#define LM3533_CONTROL_FULLSCALE_CURRENT_BASE		0x1F
#define   MAX_CURRENT_MIN				5000
#define   MAX_CURRENT_MAX				29800
#define   MAX_CURRENT_STEP				800
#define LM3533_CONTROL_BANK_ENABLE			0x27
#define LM3533_OVP_FREQUENCY_PWM_POLARITY		0x2C
#define   BOOST_OVP_MASK				GENMASK(2, 1)
#define   BOOST_OVP_SHIFT				1
#define   BOOST_FREQ_MASK				BIT(0)
#define   BOOST_FREQ_SHIFT				0
#define LM3533_BRIGHTNESS_REGISTER_A			0x40

#define LM3533_BOOST_OVP_16V				16000000UL
#define LM3533_BOOST_FREQ_500KHZ			500000UL

struct lm3533_backlight_priv {
	struct gpio_desc enable_gpio;
	u32 def_bl_lvl;

	/* Core */
	u32 boost_ovp;
	u32 boost_freq;

	/* Backlight */
	u32 reg;
	u16 max_current;		/* 5000 - 29800 uA (800 uA step) */
	u8 pwm;				/* 0 - 0x3f */
	bool linear;
	bool hvled;
};

static int lm3533_backlight_enable(struct udevice *dev)
{
	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
	u8 val, id = priv->reg;
	int ret;

	if (priv->linear) {
		ret = dm_i2c_reg_clrset(dev, LM3533_CONTROL_BANK_AB_BRIGHTNESS,
					BIT(2 * id + 1), BIT(2 * id + 1));
		if (ret)
			return ret;
	}

	if (priv->hvled) {
		ret = dm_i2c_reg_clrset(dev, LM3533_SINK_OUTPUT_CONFIG_1,
					BIT(0) | BIT(1), id | id << 1);
		if (ret)
			return ret;
	}

	/* Set current */
	if (priv->max_current < MAX_CURRENT_MIN || priv->max_current > MAX_CURRENT_MAX)
		return -EINVAL;

	val = (priv->max_current - MAX_CURRENT_MIN) / MAX_CURRENT_STEP;
	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_FULLSCALE_CURRENT_BASE + id, val);
	if (ret)
		return ret;

	/* Set PWM mask */
	if (priv->pwm > PWM_MAX)
		return -EINVAL;

	ret = dm_i2c_reg_write(dev, LM3533_CONTROL_PWM_BASE + id, priv->pwm);
	if (ret)
		return ret;

	/* Enable Control Bank */
	return dm_i2c_reg_clrset(dev, LM3533_CONTROL_BANK_ENABLE, BIT(id), BIT(id));
}

static int lm3533_backlight_set_brightness(struct udevice *dev, int percent)
{
	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
	int ret;

	if (percent == BACKLIGHT_DEFAULT)
		percent = priv->def_bl_lvl;

	if (percent < LM3533_BL_MIN_BRIGHTNESS)
		percent = LM3533_BL_MIN_BRIGHTNESS;

	if (percent > LM3533_BL_MAX_BRIGHTNESS)
		percent = LM3533_BL_MAX_BRIGHTNESS;

	/* Set brightness level */
	ret = dm_i2c_reg_write(dev, LM3533_BRIGHTNESS_REGISTER_A,
			       percent);
	if (ret)
		return ret;

	return 0;
}

static int lm3533_backlight_of_to_plat(struct udevice *dev)
{
	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
	ofnode child;
	int ret;

	ret = gpio_request_by_name(dev, "enable-gpios", 0,
				   &priv->enable_gpio, GPIOD_IS_OUT);
	if (ret) {
		log_err("Could not decode enable-gpios (%d)\n", ret);
		return ret;
	}

	priv->boost_ovp = dev_read_u32_default(dev, "ti,boost-ovp-microvolt",
					       LM3533_BOOST_OVP_16V);

	/* boost_ovp is defined in microvolts, convert to enum value */
	priv->boost_ovp = priv->boost_ovp / (8 * 1000 * 1000) - 2;

	priv->boost_freq = dev_read_u32_default(dev, "ti,boost-freq-hz",
						LM3533_BOOST_FREQ_500KHZ);

	/* boost_freq is defined in Hz, convert to enum value */
	priv->boost_freq = priv->boost_freq / (500 * 1000) - 1;

	/* Backlight is one of children but has no dedicated driver */
	ofnode_for_each_subnode(child, dev_ofnode(dev)) {
		if (ofnode_device_is_compatible(child, "ti,lm3533-backlight")) {
			const char *node_name = ofnode_get_name(child);

			if (!strcmp(&node_name[10], "1"))
				priv->reg = 1;
			else
				priv->reg = 0;

			priv->max_current = ofnode_read_u32_default(child, "ti,max-current-microamp",
								    5000);
			priv->pwm = ofnode_read_u32_default(child, "ti,pwm-config-mask", 0);

			priv->def_bl_lvl = ofnode_read_u32_default(child, "default-brightness",
								   LM3533_BL_MAX_BRIGHTNESS);

			priv->linear = ofnode_read_bool(child, "ti,linear-mapping-mode");
			priv->hvled = ofnode_read_bool(child, "ti,hardware-controlled");
		}
	}

	return 0;
}

static int lm3533_backlight_probe(struct udevice *dev)
{
	struct lm3533_backlight_priv *priv = dev_get_priv(dev);
	int ret;

	if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
		return -EPROTONOSUPPORT;

	dm_gpio_set_value(&priv->enable_gpio, 1);
	mdelay(5);

	ret = dm_i2c_reg_clrset(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY,
				BOOST_FREQ_MASK, priv->boost_freq << BOOST_FREQ_SHIFT);
	if (ret) {
		log_debug("%s: freq config failed %d\n", __func__, ret);
		return ret;
	}

	ret = dm_i2c_reg_clrset(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY,
				BOOST_OVP_MASK, priv->boost_ovp << BOOST_OVP_SHIFT);
	if (ret) {
		log_debug("%s: ovp config failed %d\n", __func__, ret);
		return ret;
	}

	return 0;
}

static const struct backlight_ops lm3533_backlight_ops = {
	.enable = lm3533_backlight_enable,
	.set_brightness = lm3533_backlight_set_brightness,
};

static const struct udevice_id lm3533_backlight_ids[] = {
	{ .compatible = "ti,lm3533" },
	{ }
};

U_BOOT_DRIVER(lm3533_backlight) = {
	.name		= "lm3533_backlight",
	.id		= UCLASS_PANEL_BACKLIGHT,
	.of_match	= lm3533_backlight_ids,
	.of_to_plat	= lm3533_backlight_of_to_plat,
	.probe		= lm3533_backlight_probe,
	.ops		= &lm3533_backlight_ops,
	.priv_auto	= sizeof(struct lm3533_backlight_priv),
};