blob: f97f17fec4e66f43dffa0502435ad9bb1fb927af [file] [log] [blame]
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +03001// 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>
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +03009#include <dm.h>
Svyatoslav Ryhel98602962025-02-21 17:05:37 +020010#include <dm/ofnode.h>
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030011#include <i2c.h>
12#include <log.h>
13#include <linux/delay.h>
14#include <linux/err.h>
15#include <asm/gpio.h>
16
17#define LM3533_BL_MIN_BRIGHTNESS 0x02
18#define LM3533_BL_MAX_BRIGHTNESS 0xFF
19
20#define LM3533_SINK_OUTPUT_CONFIG_1 0x10
21#define LM3533_CONTROL_BANK_A_PWM 0x14
22#define LM3533_CONTROL_BANK_AB_BRIGHTNESS 0x1A
23#define LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT 0x1F
24#define LM3533_CONTROL_BANK_ENABLE 0x27
25#define LM3533_OVP_FREQUENCY_PWM_POLARITY 0x2C
Svyatoslav Ryhel2906b002025-02-21 17:22:47 +020026#define BOOST_OVP_MASK GENMASK(2, 1)
27#define BOOST_OVP_SHIFT 1
28#define BOOST_FREQ_MASK BIT(0)
29#define BOOST_FREQ_SHIFT 0
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030030#define LM3533_BRIGHTNESS_REGISTER_A 0x40
31
Svyatoslav Ryhel98602962025-02-21 17:05:37 +020032#define LM3533_BOOST_OVP_16V 16000000UL
33#define LM3533_BOOST_FREQ_500KHZ 500000UL
34
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030035struct lm3533_backlight_priv {
36 struct gpio_desc enable_gpio;
37 u32 def_bl_lvl;
Svyatoslav Ryhel98602962025-02-21 17:05:37 +020038
39 /* Core */
40 u32 boost_ovp;
41 u32 boost_freq;
42
43 /* Backlight */
44 u32 reg;
45 u16 max_current; /* 5000 - 29800 uA (800 uA step) */
46 u8 pwm; /* 0 - 0x3f */
47 bool linear;
48 bool hvled;
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030049};
50
51static int lm3533_backlight_enable(struct udevice *dev)
52{
53 struct lm3533_backlight_priv *priv = dev_get_priv(dev);
54 int ret;
55
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030056 /* HVLED 1 & 2 are controlled by Bank A */
57 ret = dm_i2c_reg_write(dev, LM3533_SINK_OUTPUT_CONFIG_1, 0x00);
58 if (ret)
59 return ret;
60
61 /* PWM input is disabled for CABC */
62 ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_PWM, 0x00);
63 if (ret)
64 return ret;
65
66 /* Linear & Control Bank A is configured for register Current control */
67 ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_AB_BRIGHTNESS, 0x02);
68 if (ret)
69 return ret;
70
71 /* Full-Scale Current (20.2mA) */
72 ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_A_FULLSCALE_CURRENT, 0x13);
73 if (ret)
74 return ret;
75
76 /* Control Bank A is enable */
77 ret = dm_i2c_reg_write(dev, LM3533_CONTROL_BANK_ENABLE, 0x01);
78 if (ret)
79 return ret;
80
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +030081 return 0;
82}
83
84static int lm3533_backlight_set_brightness(struct udevice *dev, int percent)
85{
86 struct lm3533_backlight_priv *priv = dev_get_priv(dev);
87 int ret;
88
89 if (percent == BACKLIGHT_DEFAULT)
90 percent = priv->def_bl_lvl;
91
92 if (percent < LM3533_BL_MIN_BRIGHTNESS)
93 percent = LM3533_BL_MIN_BRIGHTNESS;
94
95 if (percent > LM3533_BL_MAX_BRIGHTNESS)
96 percent = LM3533_BL_MAX_BRIGHTNESS;
97
98 /* Set brightness level */
99 ret = dm_i2c_reg_write(dev, LM3533_BRIGHTNESS_REGISTER_A,
100 percent);
101 if (ret)
102 return ret;
103
104 return 0;
105}
106
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200107static int lm3533_backlight_of_to_plat(struct udevice *dev)
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300108{
109 struct lm3533_backlight_priv *priv = dev_get_priv(dev);
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200110 ofnode child;
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300111 int ret;
112
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300113 ret = gpio_request_by_name(dev, "enable-gpios", 0,
114 &priv->enable_gpio, GPIOD_IS_OUT);
115 if (ret) {
116 log_err("Could not decode enable-gpios (%d)\n", ret);
117 return ret;
118 }
119
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200120 priv->boost_ovp = dev_read_u32_default(dev, "ti,boost-ovp-microvolt",
121 LM3533_BOOST_OVP_16V);
122
123 /* boost_ovp is defined in microvolts, convert to enum value */
124 priv->boost_ovp = priv->boost_ovp / (8 * 1000 * 1000) - 2;
125
126 priv->boost_freq = dev_read_u32_default(dev, "ti,boost-freq-hz",
127 LM3533_BOOST_FREQ_500KHZ);
128
129 /* boost_freq is defined in Hz, convert to enum value */
130 priv->boost_freq = priv->boost_freq / (500 * 1000) - 1;
131
132 /* Backlight is one of children but has no dedicated driver */
133 ofnode_for_each_subnode(child, dev_ofnode(dev)) {
134 if (ofnode_device_is_compatible(child, "ti,lm3533-backlight")) {
135 const char *node_name = ofnode_get_name(child);
136
137 if (!strcmp(&node_name[10], "1"))
138 priv->reg = 1;
139 else
140 priv->reg = 0;
141
142 priv->max_current = ofnode_read_u32_default(child, "ti,max-current-microamp",
143 5000);
144 priv->pwm = ofnode_read_u32_default(child, "ti,pwm-config-mask", 0);
145
146 priv->def_bl_lvl = ofnode_read_u32_default(child, "default-brightness",
147 LM3533_BL_MAX_BRIGHTNESS);
148
149 priv->linear = ofnode_read_bool(child, "ti,linear-mapping-mode");
150 priv->hvled = ofnode_read_bool(child, "ti,hardware-controlled");
151 }
152 }
153
154 return 0;
155}
156
157static int lm3533_backlight_probe(struct udevice *dev)
158{
Svyatoslav Ryhel2906b002025-02-21 17:22:47 +0200159 struct lm3533_backlight_priv *priv = dev_get_priv(dev);
160 int ret;
161
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200162 if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
163 return -EPROTONOSUPPORT;
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300164
Svyatoslav Ryhel2906b002025-02-21 17:22:47 +0200165 dm_gpio_set_value(&priv->enable_gpio, 1);
166 mdelay(5);
167
168 ret = dm_i2c_reg_clrset(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY,
169 BOOST_FREQ_MASK, priv->boost_freq << BOOST_FREQ_SHIFT);
170 if (ret) {
171 log_debug("%s: freq config failed %d\n", __func__, ret);
172 return ret;
173 }
174
175 ret = dm_i2c_reg_clrset(dev, LM3533_OVP_FREQUENCY_PWM_POLARITY,
176 BOOST_OVP_MASK, priv->boost_ovp << BOOST_OVP_SHIFT);
177 if (ret) {
178 log_debug("%s: ovp config failed %d\n", __func__, ret);
179 return ret;
180 }
181
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300182 return 0;
183}
184
185static const struct backlight_ops lm3533_backlight_ops = {
186 .enable = lm3533_backlight_enable,
187 .set_brightness = lm3533_backlight_set_brightness,
188};
189
190static const struct udevice_id lm3533_backlight_ids[] = {
191 { .compatible = "ti,lm3533" },
192 { }
193};
194
195U_BOOT_DRIVER(lm3533_backlight) = {
196 .name = "lm3533_backlight",
197 .id = UCLASS_PANEL_BACKLIGHT,
198 .of_match = lm3533_backlight_ids,
Svyatoslav Ryhel98602962025-02-21 17:05:37 +0200199 .of_to_plat = lm3533_backlight_of_to_plat,
Svyatoslav Ryhel3e9488a2023-04-25 10:51:42 +0300200 .probe = lm3533_backlight_probe,
201 .ops = &lm3533_backlight_ops,
202 .priv_auto = sizeof(struct lm3533_backlight_priv),
203};